设计模式(五)原型模式(Prototype)的理解

一、一句话理解
用已有的对象做‘模子’,通过复制(克隆)快速产生新对象,而不用重新走构造函数,但要小心深浅拷贝这把双刃剑。
ctrl+c / ctrl+v 生成对象

二、生活中的例子
1、3D 打印:把原模型放进扫描仓,一键打印出同款。
2、复印证件:原件(原型)放上去,按复印键即可,不用重新去xx所办一张。三、Java 代码(两种复制路线)
1. 默认浅克隆 —— 实现 Cloneable 标记接口,重写 Object.clone()

public class Sheep implements Cloneable {   // 多莉羊
    private String name;
    private int age;
    private List<String> hobbies;   // 引用类型——注意浅克隆问题

    public Sheep(String name, int age, List<String> hobbies) {
        this.name = name;
        this.age = age;
        this.hobbies = hobbies;
    }

    @Override
    public Sheep clone() {          // 改返回类型,方便调用
        try {
            return (Sheep) super.clone();  // 浅拷贝
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();    // 不会发生
        }
    }

    /* getter/setter 省略 */
}

客户端:

Sheep orig = new Sheep("Dolly", 3, Arrays.asList("eat", "sleep"));
Sheep copy = orig.clone();        // 0 成本 new

陷阱:hobbies 是同一个 List 对象,改 copy.getHobbies().add("sing") 会影响原羊。

2. 深克隆 —— 自己复制引用字段,或借助序列化/JSON

@Override
public Sheep clone() {
    try {
        Sheep s = (Sheep) super.clone();
        s.hobbies = new ArrayList<>(this.hobbies); // 手动深拷贝
        return s;
    } catch (CloneNotSupportedException e) {
        throw new AssertionError();
    }
}

public <T extends Serializable> T deepClone() {
    try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
         ObjectOutputStream oos = new ObjectOutputStream(bos)) {
        oos.writeObject(this);
        try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
             ObjectInputStream ois = new ObjectInputStream(bis)) {
            return (T) ois.readObject();
        }
    } catch (IOException | ClassNotFoundException e) {
        throw new RuntimeException(e);
    }
}

四、标准角色
1、Prototype  : 声明克隆方法的接口(Java 里通常是 Cloneable + clone())
2、ConcretePrototype  :  实现克隆逻辑的具体类
3、Client :   持有原型实例,调用 clone() 获得新对象,无需 new

五、优缺点
优点
1、运行期动态复制,避开构造函数,性能更高(尤其大对象、复杂依赖)。
2、保护原始对象:克隆完随意改副本,不影响原型。
3、简化创建:当对象构建步骤巨多、参数巨多时,直接“抄作业”比建造者还香。
4、可配合注册表(Prototype Registry)实现“对象缓存池”——提前 clone 好模板,用的时候秒拿。
缺点
1、深/浅拷贝容易踩坑:引用类型必须手动深克隆,否则出现共享数据。
2、每个具体类都要实现克隆逻辑,代码散落。
3、循环引用对象图深克隆时会栈溢出,需要特殊处理。
4、Cloneable 接口设计被官方吐槽(Effective Java 第 13 条),建议用拷贝构造器 / 工厂方法 / 序列化代替。

六、和工厂系列、建造者的区别

维度工厂/建造者 原型
创建方式 从零 new 或分步攒料直接内存复制
是否走构造器
性能对象大、初始化复杂时较慢 复制内存,快
适用场景一般创建构造开销大、对象图复杂、需要运行时副本

七、真实 JDK / 开源落地
1、java.lang.Object.clone() 与 java.lang.Cloneable
数组就是典型原型:int[] a2 = a1.clone();
2、java.util.ArrayList#clone()
集合自身支持浅克隆,元素不复制。
3、Spring BeanDefinition 的 scope="prototype"
容器每次 getBean 都调 clone() 返回新实例,与单例相反。
4、JSON 库 Gson.fromJson(json, Foo.class) 本质也是“先序列化再反序列化”完成深克隆。
游戏引擎(Unity、Cocos)里“节点复制”= 原型模式,一键生成敌方小兵。

八、使用场景口诀
“构造慢、对象大,副本多、要缓存;深拷贝、防共享,原型帮你秒克隆。”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值