意图和动机
意图
- 运用共享技术有效地支持大量细粒度的对象
- 避免大量拥有相同内容的小类的开销
- 使大家共享一个对象
动机
- OO技术很好地解决一些灵活性或可扩展性问题
- 某些情况对象数量太多,导致运行时代价巨大
- Flyweight是一个共享对象
- 享元模式通过共享技术实现相同/相似对象重用
关键
- 关键概念是内部状态和外部状态
- 内部状态存储于Flyweight,包含独立于场景的信息(共享)
- 外部状态取决于 Flyweight场景,根据场景而变化(非共享)
适用性
- 系统中有大量的相似的对象,这些对象耗费大量的内存。
- 细粒度的对象都具备较接近的外部状态, 而内部状态与环境无关,即对象没有特定身份
- 需要缓冲池的场景
结构与参与者
- 抽象享元角色(Flyweight)
描述一个被所有具体享元类的实现的接口,即Flyweight是所有具体享元类的超类。 - 具体享元角色 (ConcreteFlyweight )
实现flyweight接口的具体享元类,如果有内蕴状态(Internal State)并为其分配存储空间。 ConcreteFlyweight对象中的内蕴状态是不会随着环境而变化,这一特性使得包含它的ConcreteFlyweight对象变的有共享性。 - 享元工厂角色 (Flyweight factory )
是享元工厂类,负责产生和管理新的Flyweight。该享元工厂维护一个享元池 - 具体非共享元角色 (UnshareConcreteFlyweight )
并非所有的Flyweight子类都需要被共享。 Flyweight接口使共享成为可能,但它并不强制共享。
Flyweight执行时所需的状态必定是内部或外部的。内部状态存储在ConcreteFlyweight中,外部对象则由Client对象存储或计算。 当用户调用flyweight对象操作时,将该状态传递给它
用户不应直接对ConcreteFlyweight类进行实例化,只能从FlyweightFactory对象得到ConcreteFlyweight对象,以保证对它们适当地进行共享
代码示例
public interface Chesspiece {
void put(int x, int y); // 落子
}
class ChesspieceFlyweight implements Chesspiece {
private String color;
public ChesspieceFlyweight(String color) { this.color = color; }
public void put(int x, int y) {
System.out.println("在(" + x + ", " + y + ")位置放了一个" + color + "子");
}
}
public class ChesspieceFactory {
static final Chesspiece WHITE = new ChesspieceFlyweight("白");
static final Chesspiece BLACK = new ChesspieceFlyweight("黑");
public static Chesspiece getChesspiece(String color) {
if (color.equals("白"))
return WHITE;
else if (color.equals("黑"))
return BLACK;
return null;
}
}
public class Game {
public static void main(String[] args) {
Chesspiece p1 = ChesspieceFactory.getChesspiece("黑");
p1.put(1, 1);
Chesspiece p2 = ChesspieceFactory.getChesspiece("白");
p2.put(2, 2);
Chesspiece p3 = ChesspieceFactory.getChesspiece("黑");
p3.put(3, 3);
Chesspiece p4 = ChesspieceFactory.getChesspiece("白");
p4.put(4, 4);
}
}
效果
- Flyweight模式的核心——
把大量共享的对象收集在一起
使用简单工厂模式进行管理
避免由大量的小对象导致系统的内存过渡消耗 - 当重复对象较多时
Flyweight模式具有较好的空间性能
但在查找搜索上消耗了时间复杂度