享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern)

享元模式是一种结构型设计模式,它通过共享多个对象之间的相同状态来减少内存使用。享元模式的核心思想是将对象的内部状态(不变的部分)和外部状态(变化的部分)分离,从而在有限的内存中存储更多的对象。

模式结构

  1. 享元接口(Flyweight)
    定义享元对象的公共接口,声明操作外部状态的方法。
  2. 具体享元类(Concrete Flyweight)
    实现享元接口,存储内部状态,并提供操作外部状态的方法。
  3. 享元工厂(Flyweight Factory)
    负责创建和管理享元对象,确保合理地共享享元对象。
  4. 客户端(Client)
    负责计算或存储享元的外部状态,并通过享元工厂获取享元对象。

代码示例

1. 享元接口(Flyweight)

// 享元接口:定义享元对象的公共接口
interface Flyweight {
    void operation(int extrinsicState);
}

2. 具体享元类(Concrete Flyweight)

// 具体享元类:存储内部状态,并提供操作外部状态的方法
class ConcreteFlyweight implements Flyweight {
    private final String intrinsicState; // 内部状态

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

    @Override
    public void operation(int extrinsicState) {
        System.out.println("Object address : " + System.identityHashCode(this));
        System.out.println("IntrinsicState : " + intrinsicState);
        System.out.println("ExtrinsicState : " + extrinsicState);
    }
}

3. 享元工厂(Flyweight Factory)

// 享元工厂:负责创建和管理享元对象
class FlyweightFactory {
    private final Map<String, Flyweight> flyweights = new HashMap<>();

    public Flyweight getFlyweight(String key) {
        if (!flyweights.containsKey(key)) {
            ConcreteFlyweight flyweight = new ConcreteFlyweight(key);
            flyweights.put(key, flyweight);
        }
        return flyweights.get(key);
    }
}

4.调用示例

public class FlyweightPattern {
    public static void main(String[] args) {
        int extrinsicState = 22;

        FlyweightFactory factory = new FlyweightFactory();

        // 获取享元对象并操作
        Flyweight flyweight1 = factory.getFlyweight("X");
        flyweight1.operation(--extrinsicState);

        Flyweight flyweight2 = factory.getFlyweight("X");
        flyweight2.operation(--extrinsicState);

        Flyweight flyweight3 = factory.getFlyweight("Z");
        flyweight3.operation(--extrinsicState);
    }
}

输出结果

Object address : 1023892928
IntrinsicState : X
ExtrinsicState : 21

Object address : 1023892928
IntrinsicState : X
ExtrinsicState : 20

Object address : 558638686
IntrinsicState : Z
ExtrinsicState : 19

应用场景

  1. 大量相似对象
    当应用程序需要创建大量相似对象时,可以使用享元模式来减少内存开销。
  2. 内存限制
    当内存有限时,享元模式可以通过共享对象的内部状态来节省内存。
  3. 对象状态分离
    当对象的状态可以分为内部状态和外部状态时,可以使用享元模式来共享内部状态。

在Java中的应用

  • java.lang.Integer.valueOf(int)
    Java中的包装类(如IntegerBoolean等)使用了享元模式来缓存常用的值,从而减少内存开销。
  • 字符串池
    Java中的字符串常量池也是享元模式的一个应用,相同的字符串字面量会被共享。

优缺点

优点

  1. 减少内存使用
    享元模式通过共享对象的内部状态,减少了内存中对象的数量。
  2. 提高性能
    享元模式可以减少对象的创建和销毁,从而提高性能。

缺点

  1. 复杂性增加
    享元模式需要将对象的状态分为内部状态和外部状态,增加了代码的复杂性。
  2. 牺牲执行速度
    享元模式可能会牺牲执行速度来换取内存,因为每次调用时都需要重新计算外部状态。

总结

享元模式通过共享对象的内部状态来减少内存使用,适用于需要创建大量相似对象的场景。尽管它可能会增加代码的复杂性,但其优点在于提高了内存利用率和性能。在Java中,享元模式广泛应用于包装类和字符串常量池等场景。