Flyweight (享元模式),其主要思想是运用共享技术有效地支持大量细粒度的对象。
也就是说在一个系统中如果有多个相同的对象,那么只共享一份就可以了,不必每个都去实例化一个对象。比如说(这里引用 GOF 书中的例子)一个文本系统,每个字母定一个对象,那么大小写字母一共就是 52 个,那么就要定义 52 个对象。如果有一个 1M 的文本,那么字母是何其的多,如果每个字母都定义一个对象那么 内存早就爆了。那么如果要是每个字母都共享一个对象,那么就大大节约了资源。
应用场景
Flyweight , 说白了,他就是一个Pool,也就是由一个Flyweight Factory来管理一族一定数目逻辑上经常需要构建和销毁的细颗粒对象,例如我们常见的数据库连接池。在Factory内部,并不物理销毁这些对象,而在接到实例化请求时 返回这些被关系对象的实例,从而减少创建销毁这些细颗粒对象的开销。
其适用于
1 、一个应用程序使用了大量的对象。 2 、完全由于使用大量的对象,造成很大的存储开销。 3 、对象的大多数状态都可变为外部状态。 4 、如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。 5 、应用程序不依赖于对象标识。由于 Flyweight 对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。
模式架构
•Flyweight
— 描述一个接口,通过这个接口Flyweight 可以接受并作用于外部状态。
• ConcreteFlyweight
— 实现Flyweight 接口, 并为内部状态( 如果有的话) 增加存储空间。
ConcreteFlyweight 对象必须是可共享的。它所存储的状态必须是内部的;即,它必须独立于Concrete Flyweight 对象的场景。
•UnsharedConcreteFlyweight
— 并非所有的Flyweight 子类都需要被共享。Flyweight接口使共享成为可能,但它并不强制共享。在Flyweight对象结构的某些层次,UnsharedConcreteFlyweight对象通常
将ConcreteFlyweight 对象作为子节点(Row和Conum就是这样)。
• FlyweightFactory
— 创建并管理Flyweight 对象。
— 确保合理地共享Flyweight 。当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。
• Client
— 维持一个对Flyweight 的引用。
— 计算或存储一个(多个)Flyweight 的外部状态。
先定义一个抽象的 Flyweight 类:
package Flyweight; public abstract class Flyweight ... { public abstract void operation(); }//end abstract class Flyweight
在实现一个具体类:
package Flyweight; public class ConcreteFlyweight extends Flyweight ... { private String string; public ConcreteFlyweight(String str) ... { string = str; }//end ConcreteFlyweight(...) public void operation() ... { System.out.println("Concrete---Flyweight : " + string); }//end operation() }//end class ConcreteFlyweight
实现一个工厂方法类:
package Flyweight; import java.util.Hashtable; public class FlyweightFactory ... { private Hashtable flyweights = new Hashtable();//----------------------------1 public FlyweightFactory() ...{} public Flyweight getFlyWeight(Object obj) ... { Flyweight flyweight = (Flyweight) flyweights.get(obj);//----------------2 if(flyweight == null) ...{//---------------------------------------------------3 // 产生新的 ConcreteFlyweight flyweight = new ConcreteFlyweight((String)obj); flyweights.put(obj, flyweight);//--------------------------------------5 } return flyweight;//---------------------------------------------------------6 }//end GetFlyWeight(...) public int getFlyweightSize() ... { return flyweights.size(); } }//end class FlyweightFactory
这个工厂方法类非常关键,这里详细解释一下: 在 1 处定义了一个 Hashtable 用来存储各个对象;在 2 处选出要实例化的对象,在 6 处将该对象返回,如果在 Hashtable 中没有要选择的对象,此时变量 flyweight 为 null ,产生一个新的 flyweight 存储在 Hashtable 中,并将该对象返回。 最后看看 Flyweight 的调用:
package Flyweight; import java.util.Hashtable; public class FlyweightPattern ...{ FlyweightFactory factory = new FlyweightFactory(); Flyweight fly1; Flyweight fly2; Flyweight fly3; Flyweight fly4; Flyweight fly5; Flyweight fly6; /** *//** Creates a new instance of FlyweightPattern */ public FlyweightPattern() ...{ fly1 = factory.getFlyWeight("Google"); fly2 = factory.getFlyWeight("Qutr"); fly3 = factory.getFlyWeight("Google"); fly4 = factory.getFlyWeight("Google"); fly5 = factory.getFlyWeight("Google"); fly6 = factory.getFlyWeight("Google"); }//end FlyweightPattern() public void showFlyweight() ... { fly1.operation(); fly2.operation(); fly3.operation(); fly4.operation(); fly5.operation(); fly6.operation(); int objSize = factory.getFlyweightSize(); System.out.println("objSize = " + objSize); }//end showFlyweight() public static void main(String[] args) ... { System.out.println("The FlyWeight Pattern!"); FlyweightPattern fp = new FlyweightPattern(); fp.showFlyweight(); }//end main(...) }//end class FlyweightPattern
下面是运行结果:
Concrete---Flyweight : Google Concrete---Flyweight : Qutr Concrete---Flyweight : Google Concrete---Flyweight : Google Concrete---Flyweight : Google Concrete---Flyweight : Google objSize = 2
我们定义了 6 个对象,其中有 5 个是相同的,按照 Flyweight 模式的定义 “Google” 应该共享一个对象,在实际的对象数中我们可以看出实际的对象却是只有 2 个。