抽象类通过契约明确划分内部状态与外部状态:内部状态由具体享元类用final字段固化并共享,外部状态由客户端运行时传入;抽象类仅声明接收外部状态的方法,不存储任何外部状态。

抽象类在享元模式中不直接“区分”内部状态和外部状态,而是通过设计契约来明确划分职责:内部状态由具体享元类持有并共享,外部状态则完全交由客户端管理、运行时传入。
抽象享元类只声明操作,不存储外部状态
抽象类(或接口)定义的是所有享元对象共有的行为契约,它不保存任何外部状态字段,只提供接收外部状态的方法参数。比如:
- 方法签名如
void draw(Position pos)或void operate(ExtrinsicData data),其中pos或data就是外部状态,由调用方传入; - 内部状态(如颜色、类型、尺寸)只在具体子类中用
private final字段声明,确保不可变且可安全共享; - 抽象类可提供获取内部状态的 getter(如
String getType()),但绝不提供 setter 修改内部状态。
内部状态必须在构造时固化,且不可修改
具体享元类继承抽象类后,在构造器中初始化内部状态,并将其设为 final 或只读:
- 例如围棋棋子的
color(黑/白)、shape(圆形)属于内部状态,一旦创建就固定; - 这些字段不随调用上下文变化,因此可以被多个客户端复用同一个实例;
- 工厂类(FlyweightFactory)按内部状态组合(如 "BLACK_CIRCLE")缓存唯一实例,避免重复创建。
外部状态必须由客户端持有并每次传入
位置、时间戳、用户ID、渲染坐标等会变的信息,绝不能存进享元对象内部:
- 它们不属于享元生命周期的一部分,也不参与对象复用判断;
- 客户端需自行维护这些数据,在调用享元方法时显式传入(如
blackPiece.draw(new Position(3, 5))); - 这样既解耦了享元对象与运行环境,又保证了线程安全——因为享元实例本身无状态变更风险。
抽象类配合工厂,共同守住边界
抽象类本身不管理实例,但它是工厂和客户端之间的协议枢纽:
- 工厂只根据内部状态创建或返回享元,从不接触外部状态;
- 客户端拿到享元后,只调用其定义的方法,并负责准备和传入外部状态;
- 这种分工让抽象类成为“状态分界线”:它的方法签名就是内部与外部的接口边界。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











