享元模式(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");
    }
}

优缺点

  • 优点
    减少内存使用: 共享相同的对象,避免重复创建相似对象。
    提升性能: 减少对象数量,降低内存压力。
  • 缺点
    增加复杂度: 引入共享机制后,系统逻辑可能变得复杂。
    外部状态管理困难: 客户端需自行管理外部状态,增加了使用成本。

适用场景

系统需要大量细粒度的相似对象时,例如:文字处理软件中的字符对象。
对象中的状态大部分是可以共享的,只有少部分是不变的。