享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享相同的对象来减少内存使用,适合用于创建大量相似对象的场景。该模式的核心思想是:如果发现对象的某些部分是可共享的,就将这些部分提取出来,并在多个对象中共享,从而避免重复创建相同数据的对象。
核心组成
- 享元接口(Flyweight Interface): 定义对象的公共方法,用于外部与享元对象交互。
- 具体享元类(Concrete Flyweight): 实现享元接口,并存储可以共享的内部状态。
- 不可共享享元类(Unshared Flyweight): 并非所有的享元对象都可以被共享。对于那些不可共享的对象,使用此类来处理。
- 享元工厂(Flyweight Factory): 用于管理享元对象的创建和共享。它确保重复使用已有的享元对象。
- 内部状态(Intrinsic State)和外部状态(Extrinsic State):
内部状态:可以被共享,存储在享元对象内部,不会随着环境变化而改变。
外部状态:不可以被共享,随着环境变化而改变,由客户端维护。
享元模式的工作原理
享元模式将对象分为两部分:
- 可共享的部分(即内部状态)通过享元对象共享;
- 不可共享的部分(即外部状态)由客户端维护,并在运行时传递给享元对象。
代码示例
以围棋棋子为例(黑棋和白棋共享棋子类型):
// 抽象享元类
interface Flyweight {
void place(String position); // 接受外部状态
}
// 具体享元类
class ConcreteFlyweight implements Flyweight {
private final String color; // 内部状态(棋子的颜色)
public ConcreteFlyweight(String color) {
this.color = color;
}
@Override
public void place(String position) {
System.out.println("棋子颜色:" + color + ",放置位置:" + position);
}
}
// 享元工厂
class FlyweightFactory {
private final Map<String, Flyweight> flyweights = new HashMap<>();
public Flyweight getFlyweight(String color) {
if (!flyweights.containsKey(color)) {
flyweights.put(color, new ConcreteFlyweight(color));
}
return flyweights.get(color);
}
}
// 客户端
public class FlyweightPatternDemo {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
Flyweight black = factory.getFlyweight("黑色");
Flyweight white = factory.getFlyweight("白色");
black.place("A1");
black.place("B2");
white.place("C3");
}
}
优缺点
- 优点
减少内存使用: 共享相同的对象,避免重复创建相似对象。
提升性能: 减少对象数量,降低内存压力。 - 缺点
增加复杂度: 引入共享机制后,系统逻辑可能变得复杂。
外部状态管理困难: 客户端需自行管理外部状态,增加了使用成本。
适用场景
系统需要大量细粒度的相似对象时,例如:文字处理软件中的字符对象。
对象中的状态大部分是可以共享的,只有少部分是不变的。