本文介绍设计模式中的享元(Flyweight)模式的概念,用法,以及实际应用中怎么样使用Flyweight模式进行开发。
Flyweight模式的概念
Flyweight通过与其他类似对象共享数据来减小内存占用。简单地说,Flyweight模式为类的所有具有相同状态的对象分配同一个实例来达到减小内存占用的目的。
我们通过Flyweight模式的类图来说明Flyweight模式:
[出自:维基百科wikipedia.org]
Flyweight 目标类。需要与其他类似对象共享数据来减小内存占用的某一类事物的抽象
FlyweightFactory 对Flyweight实例提供管理的类
调用方在生成Flyweight实例时,不直接通过new的方式而是通过FlyweightFactory#getFlyweight()取得Flyweight的一个实例。
而FlyweightFactory 对象对Flyweight实例进行管理:
调用时当Flyweight的相应实例还未生成时,则:1,生成Flyweight实例
2,将生成的Flyweight实例保存到对象池中(pooling)
3,返回该Flyweight实例
调用时当Flyweight的相应实例已经生成时,则:1,从对象池取出该Flyweight实例
2,返回该Flyweight实例
通过以上处理,一方面,FlyweightFactory可以在对象池里只保存最少限度的Flyweight实例;另一方面,调用方可以不用理会FlyweightFactory的内部实现细节而可以取得Flyweight实例。
Flyweight模式的实现范例
我们以公交公司的公交车为例:某公交公司有编号为A,B,C,D的公交车,同一编号的公交车最多只有一辆,对于需要使用这些公交车的任何客户,通过同一编号取车的话,不管是谁,取出来的都是同一辆车。这种情况,我们可以用Flyweight模式来实现。
代码:
import java.util.HashMap;
import java.util.Map;
/** Flyweight */
class Bus {
private String number;
public Bus(String number) {
this.number = number;
}
public void printNumber() {
System.out.println(number);
}
}
/** FlyweightFactory */
class BusFactory {
Map pool;
public BusFactory(){
this.pool = new HashMap();
}
public Bus getBus(String number){
Bus bus = this.pool.get(number);
if(bus == null) {
bus = new Bus(number);
this.pool.put(number, bus);
}
return bus;
}
}
//Test:
public class Client {
public static void main(String []args) {
BusFactory busFactory = new BusFactory();
Bus bus1 = busFactory.getBus("A");
Bus bus2 = busFactory.getBus("B");
Bus bus3 = busFactory.getBus("C");
Bus bus4 = busFactory.getBus("D");
Bus bus5 = busFactory.getBus("E");
Bus bus6 = busFactory.getBus("B");
bus1.printNumber();
bus2.printNumber();
bus3.printNumber();
bus4.printNumber();
bus5.printNumber();
bus6.printNumber();
System.out.println("bus2 = bus6:" + bus2.equals(bus6));
}
}
运行并显示Client:
C:\Flyweight>javac *.java
C:\Flyweight>java Client
A
B
C
D
E
B
bus2 = bus6:true
C:\Flyweight>
Flyweight模式使用提示
Flyweight模式一般用于外部操作不改变Flyweight实例状态的情况下。因为如果外部操作取出了Flyweight的一个实例并在外部改变了其状态后,下一次操作取得的同一个Flyweight实例可能并具有我们所要求的状态了。
需要删除Flyweight某实例时,应该通过FlyweightFactory加以删除。
为了调用方便,FlyweightFactory类一般使用Singleton模式实现。
Flyweight模式与工厂模式的区别
有关工厂模式的文章请参考:
通过比较,我们可以发现Flyweight模式与工厂模式存在某些相似之处:都提供了对象工厂的功能,生成了类的实例供外部调用。
但Flyweight模式的目的是使某些相似对象共用类的同一个实例以达到节省内存空间的目的;工厂模式则不强制这一点,它只是负责生成类的实例,另外,工厂模式还通过工厂的继承来生成具有继承关系的不同类的实例,而Flyweight模式不强调这一点。