首页 > Design > 设计模式(9):享元模式(Flyweight)

设计模式(9):享元模式(Flyweight)

  享元模式(英语:FlyweightPattern)是一种软件设计模式。它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。
  享元模式就是运用共享技术有效地支持大量细粒度的对象。
  因此,需要分离出被缓存对象实例中,哪些数据是不变且重复出现的,哪些数据是经常变化的,真正应该被缓存的数据是那些不变且重复出现的数据,把它们称为对象的内部状态,而那些变化的数据就不缓存了,把它们称为对象的外部状态。
这样在实现的时候,把内部状态分离出来共享,称之为享元,通过共享享元对象来减少对内存的占用。把外部状态分离出来,放到外部,让应用在使用的时候进行维护,并在需要的时候传递给享元对象使用。为了控制对内部状态的共享,并且让外部能简单地使用共享数据,提供一个工厂来管理事元,把它称为享元工厂。

模式讲解

1. 变与不变
  享元模式设计的重点就在于分离变与不变。把一个对象的状态分成内部状态和外部状态,内部状态是不变的,外部状态是可变的。然后通过共享不变的部分,达到减少对象数量并节约内存的目的。在享元对象需要的时候,可以从外部传入外部状态给共享的对象,共享对象会在功能处理的时候,使用自己内部的状态和这些外部的状态。
事实上,分离变与不变是软件设计上最基本的方式之一,比如预留接口,为什么在这个地方要预留接口,一个常见的原因就是这里存在变化,可能在今后需要扩展或者是改变己有的实现,因此预留接口作为”可插入性的保证” 。
2. 共享与不共事
  在享元模式中,享元对象又有共享与不共享之分,这种情况通常出现在和组合模式合用的情况,通常共享的是叶子对象,一般不共享的部分是由共享部分组合而成的,由于所有细粒度的叶子对象都已经缓存了,那么缓存组合对象就没有什么意义了。这在后面将给大家一个示例。
3. 内部状态和外部状态
  享元模式的内部状态,通常指的是包含在亭元对象内部的、对象本身的状态,是独立于使用享元的场景的信息,一般创建后就不再变化的状态,因此可以共享。外部状态指的是享元对象之外的状态,取决于使用享元的场景,会根据使用场景而变化,因此不可共享。如果享元对象需要这些外部状态的话,可以从外部传递到享元对象中,比如通过方法的参数来传递。也就是说享元模式真正缓存和共享的数据是享元的内部状态,而外部状态是不应该被缓存共享的。
  还有一点,内部状态和外部状态是独立的,外部状态的变化不应该影响到内部状态。
4. 实例池
  在享元模式中,为了创建和管理共享的享元部分,引入了享元工厂。享元工厂中一般都包含有享元对象的实例池,享元对象就是缓存在这个实例池中的。所谓实例池,指的是缓存和管理对象实例的程序,通常实例池会提供对象实例的运行环境,并控制对象实例的生命周期。

  享元模式的优点是:减少对象数量,节省内存空间。
  可能有的朋友认为共享对象会浪费空间,但是如果这些对象频繁使用,那么其实是节省空间的。因为占用空间的大小等于每个对象实例占用的大小再乘以数量,对于享元对象来讲,基本上就只有一个实例,大大减少了享元对象的数量,并节省不少的内存空间。节省的空间取决于以下几个因素:因为共享而减少的实例数目、每个实例本身所占用的空间。假如每个对象实例占用2个字节,如果不共享数量是100 个,而共享后就只有一个了,那么节省的空间约等于(100 – 1) x 2 字节。
  享元模式的缺点是:维护共享对象,需要额外开销。如同前面演示的享元工厂,在维护共享对象的时候,如果功能复杂,会有很多额外的开销,比如有一个线程来维护垃圾回收。

转载请注明: 转载自阿凡树的博客

本文链接地址: 设计模式(9):享元模式(Flyweight)

  1. 还没有评论
评论提交中, 请稍候...

留言

可以使用的标签: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
Trackbacks & Pingbacks ( 0 )
  1. 还没有 trackbacks