参考文献

享元模式

  • 它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在有限的内存容量中载入更多对象.
  • 此模式的目的是使用共享来支持大量对象,这些对象的内部状态的一部分是相同的,而状态的其他部分可能会有所不同.

组件

  • Flyweight: 声明一个接口,通过该接口,flyweight 可以接收外部状态并对其进行操作
  • ConcreteFlyweight: 实现 Flyweight 接口并存储内在状态. ConcreteFlyweight 对象必须是可共享的.具体的享元对象必须维持其固有的状态,并且必须能够操纵外在的状态
  • FlyweightFactory: 工厂创建和管理 Flyweight 对象.此外,工厂还确保享元对象的共享.工厂维护一个不同的享元对象池,如果已经创建了对象,则从池中返回一个对象;如果是新对象,则向池中添加一个对象并返回该对象
  • Client: 除了计算和维护外部状态之外,客户端还维护对享元的引用
  • 客户端需要一个享元对象;它调用工厂来获取享元对象.工厂检查享元池以确定所请求类型的享元对象是否在池中,如果存在,则返回对该对象的引用.如果没有所需类型的对象,工厂将创建所需类型的享元,将其添加到池中,并返回对该享元的引用.享元维护内部状态(在我们为其创建享元的大量对象之间共享的状态)并提供操作外部状态的方法(状态因对象而异,并且在我们为其创建的对象中并不常见)

实现方式

  • 确定内在状态(Intrinsic State)和外在状态(Extrinsic State)

    • 内在状态指对象可以共享的不变数据,可以被多个对象共享.
    • 外在状态指对象的上下文相关数据,每个对象都可能不同.
  • 创建享元接口(Flyweight),定义对象的共享方法

    1
    2
    3
    public interface Flyweight {
    void operation(ExtrinsicState state);
    }
  • 创建具体享元类,实现享元接口,并存储内在状态(Intrinsic State):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class ConcreteFlyweight implements Flyweight {
    private IntrinsicState intrinsicState;

    public ConcreteFlyweight(IntrinsicState intrinsicState) {
    this.intrinsicState = intrinsicState;
    }

    @Override
    public void operation(ExtrinsicState state) {
    // 使用内在状态和外在状态执行操作
    // ...
    }
    }
  • 创建享元工厂类,用于管理和提供享元对象:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class FlyweightFactory {
    private Map<String, Flyweight> flyweights = new HashMap<>();

    public Flyweight getFlyweight(String key) {
    if (!flyweights.containsKey(key)) {
    // 创建新的享元对象并添加到缓存中
    flyweights.put(key, new ConcreteFlyweight(intrinsicState));
    }
    return flyweights.get(key);
    }
    }
  • 定义外在状态(Extrinsic State)类,用于存储对象的上下文相关数据:

    1
    2
    3
    4
    public class ExtrinsicState {
    // 存储外在状态的数据
    // ...
    }
  • 在客户端中使用享元模式:

    1
    2
    3
    4
    5
    6
    7
    8
    FlyweightFactory factory = new FlyweightFactory();
    Flyweight flyweight = factory.getFlyweight("key");

    ExtrinsicState state1 = new ExtrinsicState(...);
    flyweight.operation(state1);

    ExtrinsicState state2 = new ExtrinsicState(...);
    flyweight.operation(state2);

使用场景

  • 仅在程序必须支持大量对象且没有足够的内存容量时使用享元模式
    • 应用该模式所获的收益大小取决于使用它的方式和情景. 它在下列情况中最有效:
    • 程序需要生成数量巨大的相似对象
    • 这将耗尽目标设备的所有内存
    • 对象中包含可抽取且能在多个对象间共享的重复状态.