一、概念

  享元模式是对象的结构模式,它以共享的方式高效的支持大量的细粒度对象,减少对象的数量,并达到节约内存的目的。

  享元对象能够做到共享的关键,主要是区分了内部状态和外部状态,内部状态是对象是在建立时就已确定了,且它不随环境的改变而有所不同,所以这些内部状态就可以共享,而外部状态是会随着环境的变化而会改变的,不可以共享。所以外部状态必须由客户端保存,当需要时可以传给享元对象。

二、模式动机

  当一个系统对于同一个对象类型,有大量的对象实例 ,且这些对象实例里面的状态大部分都可以外部化,而对一些不可变的相同内部状态一组实例,就可以用一个对象代替。这样就可以减少对角的数量,从而达到节约内存目的。

三、模式的结构

  

  角色分析:

    FlyWeight:享元接口,通过这个接口Flyweight可以接受并作用于外部状态。通过这个接口传入外部的状态,在享元对象的方法处理过程中可能会使用到这些数据。

    ConcreteFlyWeight:具体的享元对象,这些对象必须是可以共享的,需要封装Flyweight的内部状态。

    UnsharedConcreteFlyweight:非共享的享元实例对象,并非所有的Flyweight实现对象都需要共享,非共享的享元实现对象通常是共享的享元实例对象的组合。

    FlyWeightFactory:主要用来创建并管理共享享元对象,并对外提供访问共享享元对象的接口,它内部往往有一个共享享元对象的实例池,通过这个实例池来实现享元对象的共享。

    Client:享元客户端,主要的工作是维持一个对Flyweight对象的引用,通过FlyWeightFactory获取享元对象,并将客户端存储的外部状态作用于享元对象。

  代码样例如下:

  

package flyweight.sample;

/**
* 抽像享元角色,所有具体享元角色的超类,通过这个角色享元接收并作用于外部状态
* @ClassName: FlyWeight
* @author beteman6988
* @date 2018年3月31日 上午7:50:48
*
*/
public interface FlyWeight { /**
* 具体业务逻辑
* @Title: operation
* @param @param extrinsicSate 外部状态
* @return void
* @throws
*/
public void operation(String extrinsicSate); } /**
* 享元对象:可以共享的享元对象
* @ClassName: ConcreteFlyWeight
* @author beteman6988
* @date 2018年3月31日 上午7:56:13
*
*/
public class ConcreteFlyWeight implements FlyWeight { private String intrinsicState ; //不依赖于环境改变而改变的内部状态 /**
* 构造方法,传入享元对象的内部状态
* @param intrinsicState:内部状态
*/
public ConcreteFlyWeight(String intrinsicState) {
super();
this.intrinsicState = intrinsicState;
} /**
* 具体业务逻辑
* @Title: operation
* @param @param extrinsicSate 外部状态
* @return void
* @throws
*/
@Override
public void operation(String extrinsicSate) {
//具体业务逻辑
} } import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; /**
* 不需要共享的复合享元对象
*
* @ClassName: UnsharedConcreteFlyWeight
* @author beteman6988
* @date 2018年3月31日 上午8:05:55
*
*/
public class UnsharedConcreteFlyWeight implements FlyWeight { //享元集合 ,主键:代表共享享元的主键 值:共享享元主键代表的共享享元
private Map<String,FlyWeight> flies = new HashMap<String,FlyWeight>(); /**
* 往复合享元对象中添加共享享元
* @Title: add
* @param @param intrinsticState:内部状态(不一定必须是内部状态,只要是代表该共享享元的主键即可)
* @param @param oneFlyWeight
* @return void
* @throws
*/
public void add(String intrinsticState,FlyWeight oneFlyWeight) {
this.flies.put(intrinsticState,oneFlyWeight);
} /**
* 作用于所有无享元的具体业务逻辑
* @Title: operation
* @param @param extrinsicSate 外部状态
* @return void
* @throws
*/
@Override
public void operation(String extrinsicSate) {
//具体业务逻辑
} public String toString() {
for(Iterator it=flies.entrySet().iterator();it.hasNext();) {
Map.Entry entry=(Entry) it.next();
System.out.println(entry.getValue());
}
return null;
} } import java.util.HashMap;
import java.util.List;
import java.util.Map; /**
* 提供共享享元对象或复合享元对象的工厂
*
* @ClassName: FlyWeightFactory
* @author beteman6988
* @date 2018年3月31日 上午8:24:14
*
*/
public class FlyWeightFactory {
// 共享享元的实例池 ,主键:代表共享享元的主键 值:共享享元主键代表的共享享元
private Map<String, FlyWeight> flies = new HashMap<String, FlyWeight>(); /**
* 返回共享享元对象的工厂方法
* @Title: factory
* @param @param intrinsticState :内部状态
* @param @return
* @return FlyWeight :共享享元实例
* @throws
*/
public FlyWeight factory(String intrinsticState) {
// 从实例池获取需要的享元对象
FlyWeight flyWeight = this.flies.get(intrinsticState); if (null == flyWeight) { // 如果获取不到则创建享元对象
flyWeight = new ConcreteFlyWeight(intrinsticState);
this.flies.put(intrinsticState, flyWeight); // 将创建的享元对象添加到实例池
}
return flyWeight;
} /**
* 返回不共享的复合享元实例
* @Title: factory
* @param @param intrinsticStates
* @param @return
* @return FlyWeight
* @throws
*/
public FlyWeight factory(List<String> intrinsticStates) {
UnsharedConcreteFlyWeight unsharedFlyWeight=new UnsharedConcreteFlyWeight(); //创建不共享的复合享元
for(String intrinsticState:intrinsticStates) {
unsharedFlyWeight.add(intrinsticState, this.factory(intrinsticState));
}
return unsharedFlyWeight;
} } import java.util.ArrayList;
import java.util.List; public class Client { public static void main(String[] args) {
FlyWeightFactory factory =new FlyWeightFactory(); List list=new ArrayList();
list.add("a");
list.add("a"); FlyWeight three=factory.factory(list);
System.out.println(three); FlyWeight one=factory.factory("a");
FlyWeight two=factory.factory("a");
System.out.println(one);
System.out.println(two); }
}

代码运行结果如下:

flyweight.sample.ConcreteFlyWeight@15db9742
null
flyweight.sample.ConcreteFlyWeight@15db9742
flyweight.sample.ConcreteFlyWeight@15db9742

通过结果可以看出,三个对象的hashcode相同,说明是同一个对象。

四、模式样例

  通过分析Integer.valueOf(int i)来分析JDK(JDK1,8.0.131)享元设计模式,首先分析Integer这个类是否可以做为一个享元的实现类,如下图:

可以看出这个类的内部状态为final的value,且这个值是通过构造函数传入,因为它是final int,所以它的值是不随环境的改变而受到影响的,所以Integer类可以做为享元对象的实现类来使用。

再来看valueOf(int i)函数:

可以看出如果传入的值>=IntegerCache.low且<=IntegerCache.high ,那么就直接从IntegerCache.cache[i + (-IntegerCache.low)]里直接去取对象,而不是新建对象,从而实现对象的共享。

再来看一下IntegerCache这个类,如下图:

可以看出它是Integer类的一个静态私有内部类,它有一个static final Integer cache[]的成员,且这成员变量在类加载时通过静态初始化块(语句2)将256(从上面的代码可以看出 是从 -128到127  共256个Integer对象)个Integer对象初始化到了cache[]数组里面,只要Integer类通过静态方法public static Integer valueOf(int i) 就可以直接从这个cache[]里面取到对应int值的Integer对象(前提是int i值的范围也是-128到127 ,但是这个缓存数组的大小也是可以改变的,通过语句3 ,在JDK的参数里面设置-Djava.lang.Integer.IntegerCache.high=整数值,就可以改变大小,但是这个值不能小于127,如果小于127会取缺省的127 )。

五、与其它模式的关系

  享元模式与单例模式:这两个模式可以组合使用。通常情况下,享元模式中的享元工厂可以实现成为单例模式。

享元模式与组合模式:这两个模式也是可以组合使用的。在享元模式中,存在不需要共享的实现,这些不需要共享的享元通常是对共享的享元对象的组合对象。也就是说,享元模式通常会和组合模式组合使用,来实现更复杂的对象层次结构。

设计模式-享元模式(FlyWeight)的更多相关文章

  1. 设计模式--享元模式Flyweight(结构型)

    一.享元模式 在一个系统中如果有多个相同的对象,这些对象有部分状态是可以共享的,我们运用共享技术就能有效地支持大量细粒度的对象. 二.例子 举个围棋的例子,围棋的棋盘共有361格,即可放361个棋子. ...

  2. 大话设计模式--享元模式 Flyweight -- C++实现实例

    1. 享元模式: 运用共享技术有效地支持大量细粒度的对象. 享元模式可以避免大量非常相似类的开销,在程序设计中,有时需要生成大量颗粒度的类实例来表示数据,如果能发现这些实例除了几个参数外基本都是相同的 ...

  3. 深入浅出设计模式——享元模式(Flyweight Pattern)

    模式动机 面向对象技术可以很好地解决一些灵活性或可扩展性问题,但在很多情况下需要在系统中增加类和对象的个数.当对象数量太多时,将导致运行代价过高,带来性能下降等问题.享元模式正是为解决这一类问题而诞生 ...

  4. 设计模式(十)享元模式Flyweight(结构型)

    设计模式(十)享元模式Flyweight(结构型) 说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释 ...

  5. 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern)

    原文:乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) 作者:weba ...

  6. 享元模式 FlyWeight 结构型 设计模式(十五)

    享元模式(FlyWeight)  “享”取“共享”之意,“元”取“单元”之意. 意图 运用共享技术,有效的支持大量细粒度的对象. 意图解析 面向对象的程序设计中,一切皆是对象,这也就意味着系统的运行将 ...

  7. 设计模式-11享元模式(Flyweight Pattern)

    1.模式动机 在面向对象程序设计过程中,有时会面临要创建大量相同或相似对象实例的问题.创建那么多的对象将会耗费很多的系统资源,它是系统性能提高的一个瓶颈. 享元模式就是把相同或相似对象的公共部分提取出 ...

  8. 设计模式系列之享元模式(Flyweight Pattern)——实现对象的复用

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  9. 【UE4 设计模式】享元模式 Flyweight Pattern

    概述 描述 运用共享技术有效地支持大量细粒度对象的复用.系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用. 由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻 ...

随机推荐

  1. request接受表单数据中文乱码问题分析

    这个问题困扰了我很久,今天就来探索探索. [页面乱码] 浏览器的默认编码格式和你的jsp中的编码格式不统一造成的.假如你的jsp的头编码设置为utf-8,但是浏览器设置的是gbk,就会乱码. [pos ...

  2. Django orm 实现批量插入数据

    Django ORM 中的批量操作 在Hibenate中,通过批量提交SQL操作,部分地实现了数据库的批量操作.但在Django的ORM中的批量操作却要完美得多,真是一个惊喜. 数据模型定义 首先,定 ...

  3. Spring事务管理(详解+实例)

    1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必须是 ...

  4. windows快速打开命令窗口方式[利刃篇]

    windows当然是窗口界面操作了,谁有事没事去用什么命令行啊,但是当你要用的时候,也要会用才行哦. 打开命令行的方式小说一下: 1.开始 > 运行 > cmd , enter,  ok ...

  5. MySQL备份---lvm snapshot

    正常安装(缺点要锁表) 1, 创建一个LV(逻辑卷) , 把MySQL的数据目录放到这个LV上 /var/lib/mysql 对这个LV做快照, 从快照备份数据 删除快照 非正常安装 1,创建LV 2 ...

  6. css 如何“画”一个抽奖转盘

    主要描述的是如何运用 css 绘制一个抽奖转盘,并运用原生 js 实现转盘抽奖效果. 先来张效果图: 布局 一般来说,转盘一般有四个部分组成:外层闪烁的灯.内层旋转的圆盘.圆盘上的中奖结果.指针. 所 ...

  7. Maven Optional & Exclusions 使用区别

    Optional和Exclusions都是用来排除jar包依赖使用的,两者在使用上却是相反. Optional定义后,该依赖只能在本项目中传递,不会传递到引用该项目的父项目中,父项目需要主动引用该依赖 ...

  8. python爬取微信信息--显示性别/地域/词云(附代码)

    看到一篇有意思的博客 利用微信开放的接口itchat 可以获取登录的微信好友信息 并且利用图像工具显示分析结果 非常的有意思 记录下实现过程 并提供可执行代码 首先要 import itchat 库 ...

  9. Xamarin.Android 调用原生的Jar包

    我们有时候会从Android原生开发(Java)转移到Xamarin.Android开发时,需要将过去写好的Android Class Library直接嵌入到Xamarin.Android底下使用, ...

  10. 浅析mpvue的事件代理系统

    前言 说来惭愧,用 mpvue 大半年,小程序快一年了,居然还试图用 event.stopPropagation 方法阻止事件冒泡,也是有点蠢.痛定思痛,写篇博文来认真捋一捋小程序的事件系统和 mpv ...