意图

运用共享技术有效的支持大量细粒度的对象。采用一个共享来避免大量拥有相同内容的“小类”的开销。在Java中可以使用类变量、缓存技术共享相同的部分。
享元模式分为:单纯享元模式和复合享元模式。
内蕴(内部)状态:共享的信息
外蕴(外部)状态:特有的信息

适用性

Flyweight模式的有效性很大程度上取决于如何使用它以及在何处使用它。当一下情况都成立时使用Flyweight模式:
1. 一个应用程序使用了大量的对象
2. 完全由于使用大量的对象,造成很大的存储开销
3. 对象的大多数状态都可变为外部状态
4. 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象
5. 应用程序不依赖于对象标识。由于Flyweight对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。

结构

参与者

Flyweight

描述一个接口,通过这个接口Flyweight可以接受并作用于外部状态。

ConcreteFlyweight

实现了Flyweight接口,并为内部状态(如果有的话)增加了存储空间。ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的;即,它必须独立于ConcreteFlyweight对象的场景。

UnsharedConcreteFlyweight

并非所有的Flyweight的子类都需要被共享。Flyweight接口使共享成为可能,但它并不强制共享。在Flyweight对象接口的某些层次,UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。

FlyweightFactory

创建并管理Flyweight对象。确保合理地共享Flyweight。当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。

Client

维持一个对Flyweight的引用。计算或存储一个(多个)Flyweight的外部状态。

代码

Flyweight

public interface Flyweight {//传入的外部状态public void operation(String outState);public Flyweight get(String flyweightKey);public void put(String flyweightKey,Flyweight flyweightValue);public boolean remove(String flyweightKey);
}

ConcreteFlyweight

public class ConcreteFlyweight implements Flyweight{//内部状态private String inState;public ConcreteFlyweight(String inState){this.inState = inState;}public void operation(String outState) {System.out.println("inState:"+inState+" outState:"+outState);}public Flyweight get(String flyweightKey) {throw new IllegalArgumentException("子节点不能执行:get()操作");}public void put(String flyweightKey,Flyweight flyweightValue) {throw new IllegalArgumentException("子节点不能执行:put()操作");}public boolean remove(String flyweightKey) {throw new IllegalArgumentException("子节点不能执行:remove()操作");}
}

UnsharedConcreteFlyweight

public class UnsharedConcreteFlyweight implements Flyweight{private Map<String,Flyweight> flyweightMap = new HashMap<String,Flyweight>();public void operation(String outState) {for(Map.Entry<String, Flyweight> map: flyweightMap.entrySet()){Flyweight f = map.getValue();f.operation(outState);}}public Flyweight get(String flyweightKey) {return flyweightMap.get(flyweightKey);}public void put(String flyweightKey,Flyweight flyweightValue) {flyweightMap.put(flyweightKey,flyweightValue);}public boolean remove(String flyweightKey) {return flyweightMap.remove(flyweightKey)==null?false:true;}
}

FlyweightFactory

public class FlyweightFactory {private static Map<String,Flyweight> flyweightMap = new HashMap<String,Flyweight>();public static Flyweight getFlyweight(List<String> flyweightKeyList){Flyweight unsharedConcreteFlyweight = new UnsharedConcreteFlyweight();for(String flyweightKey : flyweightKeyList){if(unsharedConcreteFlyweight.get(flyweightKey)==null){unsharedConcreteFlyweight.put(flyweightKey, new ConcreteFlyweight(flyweightKey));}}return unsharedConcreteFlyweight;} public static Flyweight getFlyweight(String flyweightKey){if(flyweightMap.containsKey(flyweightKey)){return flyweightMap.get(flyweightKey);}else{Flyweight concreteFlyweight = new ConcreteFlyweight(flyweightKey);flyweightMap.put(flyweightKey, concreteFlyweight);return concreteFlyweight;}}
}

Client

public class Client {public static void main(String[] args) {Flyweight f = FlyweightFactory.getFlyweight("123");f.operation("246");}
}

协作

Flyweight执行时所需要的状态必定是内部的或外部的。内部状态存储于ConcreteFlyweight对象之中;而外部对象则由Client对象存储或计算。当用户调用Flyweight对象的操作时,将该状态传递给它。
用户不应直接对ConcreteFlyweight类进行实例化,而只能从FlyweightFactory对象得到ConcreteFlyweight对象,这可以保证对它们适当地进行共享。

效果

优点

  1. 减少运行时对象实例的个数,节省内存
  2. 将许多“虚拟”对象的状态集中管理
    共享的Flyweight越多,节省的空间就越多。存储节约由以下几个因素决定:
  3. 因为共享,实例总数减少的数目
  4. 对象内部状态的平均数据
  5. 外部状态是计算的还是存储的
    共享的Flyweight越多,存储节约也就越多。节约量随着共享状态的增加而增大。当对象使用大量的内部及外部状态,并且外部状态是计算出来的而非存储的时候,节约量将达到最大。所以,可以用两种方法来节约存储:用共享减少内部状态的消耗,用计算时间换取对外部状态的存储。
    Flyweight模式经常和Composite模式结合起来表示一个层次式结构,这一层次式结构是一个共享叶节点的图。共享的结果是,Flyweight的叶节点不能存储指向父节点的指针。而父节点的指针传给Flyweight作为它的外部状态的一部分。者对于该层次结构中对象之间相互通讯的方式将产生很大的影响。

缺点

系统逻辑复杂化,一定层度是外蕴状态影响系统速度

经典例子

方法:静态属性、缓冲池
具体场景: 缓存技术的使用
Java String的实现方式

实现

删除外部状态

该模式的可用性很大程度上取决于是否容易识别外部状态并将它从共享对象中删除。如果不同种类的外部状态和共享前对象的数目相同的话,删除外部状态不会降低存储消耗。理想的状况是,外部状态可以由一个单独的对象结构计算得到,且该结构的存储要求非常小。

管理共享对象

因为对象是共享的,用户不能直接对它进行实例化,因此FlyweightFactory可以帮助用户查找某个特定的Flyweight对象。FlyweightFactory对象经常使用关联存储(Map)帮助用户查找感兴趣的Flyweight对象。
共享还意味着某种形式的引用计数和垃圾回收,这样当一个Flyweight不再使用时,可以回收它的存储空间,然而,当Flyweight的数目固定而且很小的时候,这两种操作都不必要。在这种情况下,Flyweight完全可以永久保存。

相关模式

Proxy Pattern

Flyweight如果入到创建对象实例费时时利用对象实例共享可以提高处理速度;Proxy Pattern则是利用创建代理人的方式提高处理速度。

Composite Pattern

有时可以利用Flyweight Pattern让Composite Pattern中的Leaf参与者实现共享。

Singleton Pattern

FlyweightFactory使用单例模式实现,此外单例模式本身只能创建一个实例,所以在使用该实例对象的地方都变成共享,单利模式的参与者只有intrinsic型信息。

总结

享元模式可以使你共享地访问那些大量出现的细粒度对象,例如字符、化学药品以及边界等。享元对象必须是不可变的,可以将那些需要共享访问,并且不变的部分提取出来。为了确保你的享元对象能够被共享,需要提供并强制客户对象使用享元工厂来检查享元对象。访问修饰符对其他开发进行了一定的限制,但是内部类的使用限制更进一步,完全限制了该类仅能由其外部容器访问。在确保客户对象正确地使用享元工厂后,你就可以提供对大量细粒度对象得安全共享访问了。

转载于:https://my.oschina.net/sld880311/blog/1485953

享元模式(羽量级模式、蝇量级模式Flyweight,对象结构型模式)相关推荐

  1. Flyweight(享元)--对象结构型模式

    Flyweight(享元)–对象结构型模式 一.意图 运行共享技术有效地支持大量细粒度的对象. 二.动机 1.在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行 ...

  2. 设计模式十三:proxy(代理)——对象结构型模式

    proxy(代理)--对象结构型模式 1.意图 为其他对象提供一种代理以控制这个对象的访问 2.动机 对一个对象进行访问控制的一个原因是为了只有在我们确实需要这个对象时才对它进行创建和初始化. 3.适 ...

  3. Proxy(代理)--对象结构型模式

    Proxy(代理)–对象结构型模式 一.意图 为其他对象提供一种代理以控制对这个对象的访问. 二.动机 1.在面向对象系统中,有些对象由于某种原因(比如对象创建的开销很大,或者某些操作需要安全控制,或 ...

  4. Facade(外观)--对象结构型模式

    Facade(外观)–对象结构型模式 一.意图 为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 二.动机 1.上述左边方案的问题在于组 ...

  5. Decorator(装饰)--对象结构型模式

    Decorator(装饰)–对象结构型模式 一.意图 1.动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. 二.动机 1.在某些情况下我们可能会&quo ...

  6. Composite(组合)--对象结构型模式

    Composite(组合)–对象结构型模式 一.意图 将对象组合成树形结构以表示"部分-整体"的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. 二.动机 ...

  7. Adapter(适配器)--类对象结构型模式

    Adapter(适配器)–类对象结构型模式 一.意图 将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本接口不兼容而不能一起工作的那些类可以一起工作. 二.动机 1.在软件系统中, ...

  8. 设计模式七:Adapter(适配器)——类对象结构型模式

    结构型模式: 结构型模式设计到如何组织类和对象以获得更大的结构. 结构型类模式: 采用继承机制来组合接口或实现.简单的例子是采用多重继承,这一模式尤其有助于多个独立开发的类库协同工作. 结构型对象模式 ...

  9. Bridge模式——对象结构型模式

    今天看了Bridge模式,对其进行简单的总结,并给出几篇通俗易懂的文章链接. (一)意图--将抽象部分和它的实现部分分离,使它们都可以独立地变化. 适用于从多维度描述的类型,拆解开来,使其能沿着各维度 ...

  10. Proxy 代理模式 对象结构型模式

    1.意图 为其它对象提供一种代理以控制对这个对象的访问. 2.别名 Surrogate 3.动机 对一个对象进行访问控制的一个原因是为了只有在我们确实需要这个对象时才对它进行创建和初始化.我们考虑一个 ...

最新文章

  1. python类中的属性分为类属性和实例属性两种_python中类和实例如何绑定属性与方法示例详解...
  2. Vim 相关插件整理
  3. Vs code如何快速生成Verilog例化模板
  4. python微信开发实例 pdf 百度网盘_用python看女神微信里的百度云资源有啥?
  5. 一个Android开发者开博一周年的成长日记——送给不知如何下手的【初级开发者】和【在校生】...
  6. 基于.NET Framework 4.0的解决方案部署
  7. hdu5489 Removed Interval dp+线段树优化
  8. Codeforces Round #323 (Div. 2) C.GCD Table
  9. YbtOJ#482-爬上山顶【凸壳,链表】
  10. 如何用css设计出商品购物图片
  11. Apache HttpServer与Tomcat7集群Linux版
  12. 力扣题目系列:605. 种花问题
  13. hihocoder-13892016北京网赛07 Sewage Treatment(二分+网络流)
  14. 3步快速彻底卸载MySQL
  15. 手把手教你使用SPSS做出亚组分析的交互作用效应(p for Interaction)
  16. 宽带运营商为什么限制上行带宽
  17. android x86安装到硬盘不能启动,PC下安装androidx86一些问题的解决方法,gui start
  18. python心率检测
  19. python 成语接龙-连接数据库
  20. 容联云发送短信验证码

热门文章

  1. 如何用阿里云云盘快照恢复部分数据
  2. 【Cubieboard2】配置编译内核支持SPI全双工通信驱动
  3. 嘻哈说:设计模式之工厂方法模式
  4. Redis:只刷面试题,怎可能进大厂,多理解原理(RDB 持久化、AOF持久化)
  5. Linux 命令(184)—— at 命令
  6. 网页中打开某个网页自动弹出扣扣群实现方法
  7. 火狐插件 测试浏览器兼容性_在Firefox中测试和报告插件兼容性
  8. 同步锁Synchronized和ReentrantLock区别
  9. openwrt-mt7628 wds配置
  10. 解决Windows远程桌面连接工具连接不上远程操作系统的问题