课程大纲 / Lesson 09
Flyweight 结构型

Flyweight · 享元

运用共享技术有效地支持大量细粒度对象的复用。

01

理解享元模式:通过共享大量细粒度对象,大幅减少内存占用

02

掌握内部状态(可共享)与外部状态(随场景变化)的区分方法

03

理解 Flyweight Factory 的作用:管理共享对象池,确保相同内部状态只创建一个实例

04

了解享元模式在文本编辑器、游戏场景、森林植树等场景中的应用

核心概念
共享细粒度对象内部状态与外部状态对象池复用内存优化
classDiagram class treetype { +name string +color string +texture string +treetype(name string,color string,texture string) +draw(x int,y int) } class tree { -x int -y int -type treetype +draw() } class treefactory { -treetypes hashmap~string,treetype~$ +gettreetype(name string,color string,texture string) treetype$ } class forest { -trees list~tree~ +planttree(x int,y int,name string,color string,texture string) +size() int } tree o-- treetype treefactory o-- treetype forest *-- tree forest ..> treefactory

享元将可共享的内在状态集中到 treetype,每个 tree 只保留外在坐标

点击 Run 种植森林...
/** 享元对象:存储可共享的内部状态(树的种类信息) */
public class TreeType {
    public String name;
    public String color;
    public String texture;

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

    public void draw(int x, int y) {
        System.out.println("Drawing " + name + " tree at (" + x + "," + y + ")");
    }
}
/** 树对象:存储外部状态(坐标),引用共享的 TreeType */
public class Tree {
    private int x, y;
    private 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);
    }
}
import java.util.HashMap;

/** 享元工厂:管理 TreeType 对象池,相同种类只创建一个实例 */
public class TreeFactory {
    private static HashMap<String, TreeType> treeTypes =
        new HashMap<>();

    public static TreeType getTreeType(String name,
            String color, String texture) {
        String key = name + "_" + color + "_" + texture;
        if (!treeTypes.containsKey(key)) {
            treeTypes.put(key, new TreeType(name, color, texture));
        }
        return treeTypes.get(key);
    }
}
import java.util.ArrayList;
import java.util.List;

/** 森林:持有所有树对象,演示享元模式节省内存 */
public class Forest {
    private List<Tree> trees = new ArrayList<>();

    public void plantTree(int x, int y, String name,
                          String color, String texture) {
        TreeType type = TreeFactory.getTreeType(name, color, texture);
        Tree tree = new Tree(x, y, type);
        trees.add(tree);
    }

    public int size() { return trees.size(); }
}
public class Demo {
    public static void main(String[] args) {
        Forest forest = new Forest();
        // 种植 100 万棵树,但只共享 2 种 TreeType
        for (int i = 0; i < 500_000; i++) {
            forest.plantTree(i, i, "Oak", "Green", "oak.png");
            forest.plantTree(i, i + 1, "Pine", "DarkGreen", "pine.png");
        }
        System.out.println("Trees planted: " + forest.size());
    }
}
◈

内部状态可共享,外部状态由调用者提供

TreeType(name/color/texture)所有树共享,是内部状态;Tree 的 x/y 坐标随每次种植变化,是外部状态。

◈

工厂管理享元池

TreeFactory 用 Map 缓存已创建的 TreeType,getTreeType() 先查池,有则直接返回,无则创建并存入池。

◈

内存节省显著

100 万棵树(100 万 Tree 对象)只占用约 7 MB(TreeType 共享),而非约 36 MB(每树独立全部状态)。

◈

典型应用场景

文本编辑器(共享字符样式)、游戏(共享树木/石头/敌人贴图)、GUI(共享按钮/图标样式)、字符串池、线程池。