原型模式解决什么
原型模式(Prototype)通过克隆一个已存在的实例来创建新对象,而不是从头走构造流程。它适合两种情形:一是构造过程昂贵或依赖运行时才能确定的配置,二是需要以某个既有对象为模板批量产出微小变体。使用这类模式的核心风险集中在拷贝语义上:成员含有引用类型时,浅拷贝会让副本与原对象共享同一块数据。
基本信息
| 意图 | 以克隆代替从头构造,绕开复杂初始化流程 |
|---|---|
| 关键区分 | 浅拷贝只复制引用,深拷贝复制引用指向的数据 |
| 常见形态 | 拷贝构造器、显式复制方法、序列化往返 |
| 语言设施 | 部分语言的通用克隆语义较弱,推荐拷贝构造器 |
典型使用场景
- 配置模板:以一份已验证的基准配置为原型,派生多套环境配置并只改动少量字段
- 仿真或批量实体:同类对象数量多,从原型复制比逐一初始化更直接
- 编辑器操作:以当前图形为原型复制出变体,保留原有属性
- 测试夹具:以基准对象为原型快速生成多组用例数据
- 缓存预热:预先构造常用对象,使用时克隆交付,避免共享实例被调用方改写
拷贝构造器形态
拷贝构造器形态
class Config {
private final List<String> hosts;
private final Map<String, String> options;
// 拷贝构造器:显式控制每个字段的拷贝深度
Config(Config other) {
this.hosts = List.copyOf(other.hosts); // 不可变副本
this.options = Map.copyOf(other.options);
}
}拷贝深度对照
| 字段类型 | 浅拷贝后果 | 建议做法 |
|---|---|---|
| 不可变值类型 | 无风险 | 直接赋值即可 |
| 可变集合 | 副本与原对象共享同一集合 | 复制为不可变副本或深拷贝 |
| 嵌套对象 | 两处引用同一实例,改一处影响两处 | 按需深拷贝,或明确声明共享 |
| 缓存与连接对象 | 克隆后连接句柄重复 | 标记为不参与克隆,由原对象持有 |
| 序列化形态 | 往返拷贝成本高但隔离彻底 | 仅在对隔离要求高且性能可接受时使用 |
优先用拷贝构造器而不是通用的克隆方法:拷贝逻辑显式写在类型内部,新增字段时评审更容易发现遗漏,也不会因为父类语义不明产生意外行为。
克隆出的对象与原型之间不应再有隐式关联。若某字段必须共享(例如连接池、注册表),要在类型文档里写明,否则后续维护者会误以为副本完全独立,修改副本时以为不影响原型。
落地检查清单
- 每个引用类型字段都明确了拷贝深度
- 新增字段时拷贝逻辑同步更新
- 共享字段在文档中显式声明
- 克隆结果经过一次修改测试,确认不会反向污染原型