JavaDog程序狗
发布于 2026-11-12 / 6 阅读
0
0

【设计模式】跟着狗哥复习设计模式(十一):享元模式

游戏地图上种了很多树。有的在河边,有的在山脚,坐标都不一样。

可仔细看,树的种类就那么几种。绿色橡树长得一样,橙色枫树也用同一张图片。

享元模式就是把这些重复内容共享起来。

加瓦狗在游戏地图上使用两种模板种出一片树林

每棵树都存一套资料,有点浪费

如果每个树对象都保存坐标、名称、颜色和图片,同一份图片会被重复放很多次。

每棵树重复保存相同资料

树少时没啥感觉。对象一多,重复数据就显眼了。

先看关键 UML 图

享元模式关键 UML 类图

TreeType 保存可以共享的树种资料。Tree 保存坐标,并引用一个 TreeType。

TreeFactory 像个小仓库,相同树种只创建一次。

内部状态和外部状态

享元模式常提两个词,其实没多玄乎。

享元模式的内部状态与外部状态

内部状态是可以共享的内容,比如树名、颜色、图片。

外部状态是每个对象自己的内容,比如横坐标和纵坐标。

济南话说,把能公用的搁一块,不能公用的各自拿着,就这么个意思。

共享的树种对象

public class TreeType {
    private final String name;
    private final String color;

    public TreeType(String name, String color) {
        this.name = name;
        this.color = color;
    }

    public void draw(int x, int y) {
        System.out.println(name + "(" + color + ") 坐标=" + x + "," + y);
    }
}

坐标没有放进 TreeType,因为同一种树会出现在不同位置。

工厂负责找共享对象

private static final Map<String, TreeType> TYPES = new HashMap<>();

public static TreeType getTreeType(String name, String color) {
    String key = name + ":" + color;
    return TYPES.computeIfAbsent(
            key, k -> new TreeType(name, color));
}

享元工厂从缓存中取得共享对象

缓存里有绿色橡树,就把原来的对象拿出来。没有时才创建。

每棵树只保存位置

public class Tree {
    private final int x;
    private final int y;
    private final TreeType type;

    public Tree(int x, int y, TreeType type) {
        this.x = x;
        this.y = y;
        this.type = type;
    }

    public void draw() {
        type.draw(x, y);
    }
}

Tree 很轻,只保存坐标和共享类型的引用。

种 5 棵树看看

Forest forest = new Forest();
forest.plantTree(10, 20, "橡树", "绿色");
forest.plantTree(30, 40, "橡树", "绿色");
forest.plantTree(50, 60, "枫树", "橙色");
forest.plantTree(70, 80, "橡树", "绿色");
forest.plantTree(90, 30, "枫树", "橙色");

5棵树共享2个树种对象

这里有 5 个位置不同的 Tree,但 TreeType 只有 2 个。

青岛话说,省下来的不是树,是重复的那份资料,挺恣儿。

什么时候适合用

什么时候适合使用享元模式

对象不多时,普通写法更清楚。只有数量很多、重复数据明显时,共享才有价值。

共享对象最好保持不变。大家共用一份数据,谁随手改了,其他对象也会受影响。

狗哥收个尾

享元模式的重点,是 共享重复且稳定的内容。

树的位置各自保存,树种资料集中复用。先分清内部状态和外部状态,这个模式就不难了。

下一篇继续聊 代理模式,看看图片还没真正加载时,怎么先放一个代理顶上。


评论