✨这里是第七人格的博客✨小七,欢迎您的到来~✨
🍅系列专栏:设计模式🍅
✈️本篇内容: 原型模式✈️
🍱本篇收录完整代码地址:https://gitee.com/diqirenge/design-pattern🍱
原型模式是一种创建型设计模式,它允许复制现有对象来创建新对象,而不是通过实例化新对象,这样可以在创建复杂对象时,节约时间。如果你经常使用 JavaScript,那么原型模式是一种比较常用的开发模式,原型链也是面试经常被问到的问题。但是如果你是使用Java的后端程序员,那么原型模式的确是很少在业务中运用的。
我们从远程RPC获取了一份数据,假设为数据A,在不影响数A的情况下,我们需要从数据A复制一份数据B,然后在数据B上进行操作。
因为是将数据A复制到数据B,所以可以实现Cloneable,使用原型模式。
又因为不能影响数据A,所以我们需要考虑使用浅拷贝还是深拷贝。
怎么理解浅拷贝和深拷贝呢?
浅拷贝是按位拷贝对象,会创建一个新对象,但不会修改原对象的值。它复制的是对象的引用地址,没有开辟新的栈,所以复制的结果是两个对象指向同一个地址。因此,当修改其中一个对象的属性时,另一个对象的属性也会跟着改变。
深拷贝是复制对象本身,不共享内存。这意味着它会创建一个新的对象,并且复制原对象的所有字段以及字段所指向的动态分配内存。因此,修改新对象不会影响原对象。
深拷贝相比于浅拷贝速度较慢并且花销较大,因为它需要复制更多的数据。
举个例子,浅拷贝就好比钢铁侠的机甲,不管他制造了多少套,但是他们的AI都是贾维斯,都是一个。
而深拷贝,就是一套机甲一个AI。
所以我们上面的需求,需要使用深拷贝。
根据分析设计,我们可以先画一个简单的UML图,后面通过UML图编码
prototype
https://gitee.com/diqirenge/design-pattern/tree/master/src/main/java/com/run2code/design/creational/prototype
原型模式代码示例
1、首先我们实现浅拷贝
/** * 原型模式 * 关注公众号【奔跑的码畜】,一起进步不迷路 * * @author 第七人格 * @date 2023/11/21 */ public class RpcData implements Cloneable { private String name; private String age; private Pet pet; public static class Pet { private String name; private String age; private String tyep; public Pet() { } public Pet(String name, String age, String tyep) { this.name = name; this.age = age; this.tyep = tyep; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public String getTyep() { return tyep; } public void setTyep(String tyep) { this.tyep = tyep; } @Override public String toString() { System.out.println("Pet{" + "name='" + name + '\'' + ", age='" + age + '\'' + ", tyep='" + tyep + '\'' + '}'); return super.toString(); } } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public Pet getPet() { return pet; } public void setPet(Pet pet) { this.pet = pet; } @Override public String toString() { System.out.println("RpcData{" + "name='" + name + '\'' + ", age='" + age + '\'' + ", pet=" + pet + '}'); return super.toString(); } }
2、编写测试方法
/** * 原型模式 * 关注公众号【奔跑的码畜】,一起进步不迷路 * * @author 第七人格 * @date 2023/11/21 */ public class RpcDataPrototypeTest { @Test public void test_shallow_copy() throws CloneNotSupportedException { System.out.println("==========浅拷贝开始=========="); RpcData rpcData = new RpcData(); Pet pet = new Pet("小黑", "1", "dog"); rpcData.setName("第七人格"); rpcData.setAge("18"); rpcData.setPet(pet); RpcData cloneData = (RpcData) rpcData.clone(); Pet clonePet = cloneData.getPet(); System.out.println("原型对象和克隆对象是否是同一个对象:" + (rpcData == cloneData)); System.out.println("原型对象和克隆对象中的宠物是否是同一个对象:" + (pet == clonePet)); System.out.println("==========浅拷贝结束=========="); } }
3、测试结果
①执行test_shallow_copy方法
==浅拷贝开始==
原型对象和克隆对象是否是同一个对象:false
原型对象和克隆对象中的宠物是否是同一个对象:true
==浅拷贝结束==
一般有两种实现方式:
①先将对象序列化,然后再反序列化成新的对象
②递归拷贝对象、对象的引用对象以及引用对象的引用对象,直到对象属性中只有基本数据类型数据为止
我们这里只演示第一种方式
1、RpcData和Pet实现Serializable接口
2、添加深拷贝-序列化方法
public Object deepCopy(Object object) throws IOException, ClassNotFoundException { ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(object); ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); return oi.readObject(); }
3、编写测试方法
@Test public void test_deepCopy_copy() throws IOException, ClassNotFoundException { System.out.println("==========深拷贝开始=========="); RpcData rpcData = new RpcData(); Pet pet = new Pet("小黑", "1", "dog"); rpcData.setName("第七人格"); rpcData.setAge("18"); rpcData.setPet(pet); RpcData cloneData = (RpcData) rpcData.deepCopy(rpcData); Pet clonePet = cloneData.getPet(); System.out.println("原型对象和克隆对象是否是同一个对象:" + (rpcData == cloneData)); System.out.println("原型对象和克隆对象中的宠物是否是同一个对象:" + (pet == clonePet)); System.out.println("===========深拷贝结束=========="); }
4、测试结果
==深拷贝开始==
原型对象和克隆对象是否是同一个对象:false
原型对象和克隆对象中的宠物是否是同一个对象:false
=深拷贝结束
①先将对象序列化,然后再反序列化成新的对象
原型模式的原理和实现都是比较简单的,主要是需要理解浅拷贝和深拷贝的原理。有机会还是要用在项目中,多实践才能掌握得更好。
面对对象面对君,不负代码不负卿