享元模式(Flyweight Pattern)

一、概念

享元模式(Flyweight Pattern)是 "资源池技术"实现方式,主要用于减少创建对象的数量,以减少内存占用和提高性能。

  • 模式动机:在创建大量对象时,有可能会造成内存溢出,享元模式把其中共同的部分抽象出来,保存在内存中,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。

  • 解决思路:复用对象最简单的方式是,用一个 HashMap 来存放每次新生成的对象。每次需要一个对象的时候,先到 HashMap 中看看有没有,如果没有,再生成新的对象,然后将这个对象放入 HashMap 中。

  • 享元模式通常需要和其他模式一起联用,几种常见的联用方式如下:
    • 享元模式的享元工厂类中通常提供一个静态的工厂方法用于返回享元对象,使用简单工厂模式来生成享元对象
    • 在一个系统中,通常只有唯一一个享元工厂,因此可以使用单例模式进行享元工厂类的设计。
    • 享元模式可以结合组合模式形成复合享元模式,统一对多个享元对象设置外部状态。

二、适用场景

  1. 有大量相同或者相似的对象,造成内存的大量耗费
  2. 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
  3. 需要缓冲池的场景
    • 在使用享元模式时需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源,因此,应当在需要多次重复使用享元对象时才值得使用享元模式

三、参与者

  • Flyweight(抽象享元角色) : 享元对象的抽象基类或者接口,声明所有具体享元角色需要实现的方法,这些方法可以向外界提供对象的内部状态,设置外部状态
    • 内部状态(intrinsic):是享元对象可共享的属性,存储在享元对象内部并且不会随环境改变而改变。
    • 外部状态(extrinsic):是对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状态。
  • ConcreteFlyweight( 具体享元角色)Flyweight的具体实现,实现抽象角色定义的方法。 为内部状态提供成员变量进行存储

  • UnsharedConcreteFlyweigh( 非共享的享元角色): 不能被共享的子类可以设计为非共享享元类

  • FlyweightFactory(享元工厂角色): 负责管理享元对象池和创建享元对象,就是构造一个池容器,同时提供从池中获得对象的方法,
    • 当请求获取一个享元对象时,享元工厂判断是否存在该享元对象,如果存在则返回;如果不存在的话,则创建一个新的享元对象,保存到池容器中,然后返回给请求者。
    • 享元池一般设计成键值对
    • 享元模式一般都是和工厂模式一起出现

四、代码例子

(一)单纯享元

工具箱内可以放置多个型号的扳手,当需要用大扳手时我们会买一个放在工具箱内,需要中号或小号的扳手时再买小号、中号的扳手放在工具箱内,如果朋友需要大号的扳手则可以直接从工具箱中拿出使用,但他需要用中号或小号扳手时,就需要先去五金店买一把中号或小号扳手放在工具箱内。这样其他人在使用扳手时直接从工具箱内拿出来使用就可以。

(二)复合享元

工具箱内可以放置多个型号的扳手,但是由于扳手总是丢失,所以每个人都有私人工具箱且不可外借,这个扳手不管你是装配还是维修都可以使用,如果没有合适的扳手需要自己去五金店买。

五、UML图

(一)单纯享元

(二)复合享元

 

六、模式思想

相同的对象共享使用。

单纯享元是开放式共享,所有对象均可以分享使用;单纯享元的特点是所有元素都是共享的;

复合享元是区分式共享,比如说同一小组或好朋友可以共享,陌生人不共享,不同小组之间不共享;复合享元角色对象是不共享的,但是一个复合享元内部对象可以划分为多个共享享元表示;

七、优缺点

(一)优点

  • 极大减少内存中对象的数量,相同或相似对象内存中只存一份,降低程序内存的占用,增强程序的性能。
  • 外部状态相对独立,不影响内部状态

(二)缺点

  • 提高了系统复杂性,需要分离出外部状态和内部状态,而且外部状态不应该随内部状态改变而改变,否则导致系统的逻辑混乱。
  • 为了节省内存,共享了内部状态,分离出外部状态,而读取外部状态使运行时间变长。用时间换取了空间。
posted @ 2022-12-10 13:55  ImreW  阅读(207)  评论(0编辑  收藏  举报