bigtalk.jpg

第26章 项目多也别傻做——享元模式

概念

运用共享技术支持大量细粒度的对象。(其实就是共享对象,将大量对象共享的公共部分集中到一起,形成一个“对象分类组”)

享元模式可以避免大量非常类似类的开销。有时需要生成大量细粒度类实例来表示数据,如果这些实例除了参数以外基本相同,若把那些参数单独转移到外部实现,使用时再传进来,就能通过共享的方式大幅度减少实例的数量。比如围棋,只有黑、白两种颜色。其它都是位置,所以,如果设计的好,只用两个类实例就行了。否则要361个。

享元对象内部不会随环境改变的部分,是其内部状态可以共享;随环境而改变的状态,是外部状态,不可共享。比如博客、论坛、等网站中,“博客”、“论坛”这种类型的名字可以做为内部状态,而用户ID因人而异做为外部状态。

应用

应用场景:如果一个应用程序使用了大量的对象,而这些对象会造成大量的开销(如存储、内存);对象的大多数状态可以用外部状态,如果删除对象的外部状态可以建立很少量的类实例来取代很多组对象,就考虑享元模式。优点是实例数量大大减少,共享部分导致节省开销并且容易维护。缺点是需要记录享元列表,并且将外部状态独立表示也使得程序逻辑复杂;只有对象够多,可共享才考虑。

实现

  • FlyWeightFactory: 享元工厂,以一个Hash列表维护享元列表,需要时返回相应享元实例,如果没有则创建。
  • FlyWeight:所有享元实例的抽象接口,比如使用实例的 Use() 函数。
  • ConcreteFlyWeight: 具体实现的享元实例,实现共享的接口。
  • UnSharedConcreteFlyWeight:个别时候 ,共享接口不想共享的时候,使用这个类。
  • Client:实例化外部状态,通过享元工厂获取享元对象,用外部状态做为传输传给享元对象,调用相应的接口使用享元对象。

实现类图:

25_flyweight.png

使用图:

25_flyweight_use.png

注意

关键两点:

  • 外部状态(非共享部分,区别具体个体)和内部状态(共享部分,集中于一个对象表示一组共享该属性个体)。
  • 享元工厂维护享元列表(Hash列表,可以需要时创建,平时为空)。