
一、原型模式定义原型模式采用复制原型对象的方法来创建实例。使用原型模式创建出来的对象具有与原型一样的数据结构也拥有与原型一样的值。核心思想对象创建的动作发自原型对象自身clone()而不是由外部new出来。二、原型模式的特点由原型对象自身创建目标对象即对象创建这一动作来自原型对象本身的clone()方法。目标对象是原型的一个克隆通过原型模式创建的对象不仅与原型有相同的结构还有相同的值。根据克隆深度的不同分浅度克隆与深度克隆见第四节。三、基础代码实现Object类自带protected Object clone()但只有实现了Cloneable标记接口的类调用clone()才不会抛CloneNotSupportedException。// 必须实现 Cloneable 接口才能克隆publicclassPersonimplementsCloneable{privateStringname;privateStringage;privateStringsex;publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.namename;}publicStringgetAge(){returnage;}publicvoidsetAge(Stringage){this.ageage;}publicStringgetSex(){returnsex;}publicvoidsetSex(Stringsex){this.sexsex;}// 克隆方法重写 Object.clone()提升为 publicOverridepublicPersonclone(){try{return(Person)super.clone();// 默认是【浅克隆】}catch(CloneNotSupportedExceptione){e.printStackTrace();returnnull;}}}publicclassMainClass{publicstaticvoidmain(String[]args){Personperson1newPerson();person1.setName(李白);person1.setAge(34);person1.setSex(男);// 克隆对象堆里生成了一份新对象Personperson2person1.clone();System.out.println(person2.getName());// 李白与原型数据一致}}⚠️super.clone()默认执行的是浅克隆见下节。这里的字段都是String不可变和基本类型浅克隆看不出副作用。四、浅克隆 vs 深克隆核心4.1 一个关键澄清super.clone()的本质是逐字段复制。基本类型int、double…直接复制值互不干扰引用类型对象、数组…只复制引用地址新旧对象指向同一个引用对象。原笔记说数值对象会生成全新一份并不准确——String是引用类型只是因为它不可变即使浅克隆共享了引用重新赋值p.namex也只是让p指向新字符串不会改动原对象所以看起来没副作用。要真正暴露浅克隆问题必须用可变引用对象。4.2 浅克隆的副作用用可变对象演示给Person增加一个可变的引用属性AddresspublicclassAddressimplementsCloneable{privateStringcity;publicAddress(Stringcity){this.citycity;}publicStringgetCity(){returncity;}publicvoidsetCity(Stringcity){this.citycity;}OverridepublicAddressclone(){try{return(Address)super.clone();}catch(CloneNotSupportedExceptione){returnnull;}}}publicclassPersonimplementsCloneable{privateStringname;privateAddressaddress;// 可变引用对象// 浅克隆address 引用被复制p1、p2 指向同一个 AddressOverridepublicPersonclone(){try{return(Person)super.clone();}catch(CloneNotSupportedExceptione){returnnull;}}}publicclassMainClass{publicstaticvoidmain(String[]args){Personp1newPerson(李白,newAddress(长安));Personp2p1.clone();// 浅克隆p2.getAddress().setCity(洛阳);// 改 p2 的地址System.out.println(p1.getAddress().getCity());// 输出洛阳p1 被牵连}}结论浅克隆下p1和p2共享同一个Address改一个另一个跟着变——这通常不是我们想要的。4.3 深克隆的修法深克隆 在clone()里连引用对象也一起克隆publicclassPersonimplementsCloneable{privateStringname;privateAddressaddress;OverridepublicPersonclone(){try{Personp(Person)super.clone();p.addressthis.address.clone();// 引用对象也克隆一份returnp;}catch(CloneNotSupportedExceptione){returnnull;}}}此时p2.getAddress().setCity(洛阳)不会影响p1二者完全独立。4.4 深克隆的另一种方式序列化当对象层级很深时逐层clone()很繁琐。可让类实现Serializable通过序列化成字节流再反序列化得到完全独立的新对象要求所有引用对象都可序列化// 伪代码思路把对象写进 ByteArrayOutputStream再读回 → 全新深拷贝面试常问深克隆两种实现——逐层 clone()或序列化。前者直观但层次深时繁琐后者一行深拷贝但要求全链路可序列化。五、角色与职责角色职责抽象原型Prototype声明克隆自身的接口。Java 中即Cloneable标记接口 clone()方法具体原型Concrete Prototype实现clone()返回自身的一个副本客户Client通过调用原型的clone()创建新对象而不使用new六、应用场景创建对象时希望新对象既继承基类结构又继承原型的数据直接clone比从头new再逐个set更高效。希望修改目标对象不影响既有原型配合深克隆克隆体与原型完全隔离。隐藏克隆细节对象本身的克隆往往涉及类内部数据细节用原型模式把这些细节封装在clone()内调用方无感知。对象创建成本高 / 构造复杂如从数据库或网络加载后缓存为原型后续直接复制省去昂贵初始化。七、总结原型模式 复制现有对象来创建新对象而非new。浅克隆复制基本类型值 复制引用地址引用对象共享深克隆引用对象也一并克隆完全独立。String不可变单用String字段无法体现浅克隆问题必须用可变引用对象演示。记忆浅克隆共享引用、深克隆独立副本层次深时用序列化做深克隆更省事。一句话总结原型模式用clone()拷贝代替new省去重复初始化用之前先想清楚——你的对象里有没有可变引用有就老老实实做深克隆否则改一个坑一片。