手记

设计模式Java实现-原型模式

✨这里是第七人格的博客✨小七,欢迎您的到来~✨

🍅系列专栏:设计模式🍅

✈️本篇内容: 原型模式✈️

🍱本篇收录完整代码地址:https://gitee.com/diqirenge/design-pattern🍱

楔子

原型模式是一种创建型设计模式,它允许复制现有对象来创建新对象,而不是通过实例化新对象,这样可以在创建复杂对象时,节约时间。如果你经常使用 JavaScript,那么原型模式是一种比较常用的开发模式,原型链也是面试经常被问到的问题。但是如果你是使用Java的后端程序员,那么原型模式的确是很少在业务中运用的。

需求背景

我们从远程RPC获取了一份数据,假设为数据A,在不影响数A的情况下,我们需要从数据A复制一份数据B,然后在数据B上进行操作。

分析设计

因为是将数据A复制到数据B,所以可以实现Cloneable,使用原型模式。

又因为不能影响数据A,所以我们需要考虑使用浅拷贝还是深拷贝。

怎么理解浅拷贝和深拷贝呢?

浅拷贝是按位拷贝对象,会创建一个新对象,但不会修改原对象的值。它复制的是对象的引用地址,没有开辟新的栈,所以复制的结果是两个对象指向同一个地址。因此,当修改其中一个对象的属性时,另一个对象的属性也会跟着改变。

深拷贝是复制对象本身,不共享内存。这意味着它会创建一个新的对象,并且复制原对象的所有字段以及字段所指向的动态分配内存。因此,修改新对象不会影响原对象。

深拷贝相比于浅拷贝速度较慢并且花销较大,因为它需要复制更多的数据。

举个例子,浅拷贝就好比钢铁侠的机甲,不管他制造了多少套,但是他们的AI都是贾维斯,都是一个。
而深拷贝,就是一套机甲一个AI。

所以我们上面的需求,需要使用深拷贝。

UML图

根据分析设计,我们可以先画一个简单的UML图,后面通过UML图编码

模块名称

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. 实现 Cloneable 接口,重写clone方法

深拷贝

一般有两种实现方式:

①先将对象序列化,然后再反序列化成新的对象

②递归拷贝对象、对象的引用对象以及引用对象的引用对象,直到对象属性中只有基本数据类型数据为止

我们这里只演示第一种方式

代码实现

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

=深拷贝结束

实现要点

①先将对象序列化,然后再反序列化成新的对象

总结

原型模式的原理和实现都是比较简单的,主要是需要理解浅拷贝和深拷贝的原理。有机会还是要用在项目中,多实践才能掌握得更好。

面对对象面对君,不负代码不负卿

0人推荐
随时随地看视频
慕课网APP