Skip to content

Latest commit

 

History

History
171 lines (132 loc) · 4.74 KB

设计模式(5)原型模式.md

File metadata and controls

171 lines (132 loc) · 4.74 KB

用于通过拷贝创建重复的对象,同时又能保证性能

**主要解决:**在运行期建立和删除原型。

优点: 1、性能提高。 2、逃避构造函数的约束。

缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。

Cloneable接口是一个空接口,使用Cloneable接口都不用导入包。而clone方法是属于Object对象的。如果要克隆某个对象的话必须实现Cloneable接口

浅拷贝和深拷贝

浅拷贝:Object类的clone方法指对拷贝对象的基本类型,对数组,容器对象,引用对象等不会拷贝;

深拷贝:如果实现深拷贝,必须将原型模式中的数组,容器对象,引用对象等另行拷贝;

注意:浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。

浅拷贝

/**
 * @description: 原型模式-浅拷贝
 * @author: husy
 * @date 2020/3/2
 */
public class Product implements  Cloneable {
   private String name;
   private int[] array;

   public Product(String name, int[] array) {
      this.name = name;
      this.array = array;
   }

   public void setName(String name) {
      this.name = name;
   }

   public void setArray(int[] array) {
      this.array = array;
   }

   @Override
   public String toString() {
      return this.name+"--"+ Arrays.toString(this.array);
   }

   @Override
   protected Object clone() throws CloneNotSupportedException {
      return super.clone();
   }
}

Main.java

public static void main(String[] args) throws CloneNotSupportedException {
   String name = "喜洋洋";
   int array[] = {1,2};

   Product product1 = new Product(name,array);
   Product product2 =(Product) product1.clone();
   System.out.println(product1.toString());
   System.out.println(product2.toString());

   System.out.println("-------修改字符串和数组的值,测试拷贝情况-------");
   product1.setName(  "灰太狼");
   array[1]=4;
   product1.setArray(array);

   System.out.println(product1.toString());
   System.out.println(product2.toString());
}

输出:

喜洋洋--[1, 2]
喜洋洋--[1, 2]
-------修改字符串和数组的值,测试拷贝情况-------
灰太狼--[1, 4]
喜洋洋--[1, 4]   //-->> 数组中第二个值被改变了--<<

有上可知,放我们修改最后结果,克隆对象仍保留原有数组对象的引用,值随着改变而改变,

如果要想解决这种问题,以达到深拷贝的目的,可以将数组,容器对象,引用对象都进行一次拷贝,如下可以将Product 类中的 Clone 方法修改一下,将数组也拷贝一次,其他不变

@Override
protected Object clone() throws CloneNotSupportedException {
//    return super.clone();
  Product product = (Product) super.clone();
  product.array=this.array.clone(); // 将数组也拷贝一次
  return product;
}

执行,结果如下:

喜洋洋--[1, 2]
喜洋洋--[1, 2]
-------修改字符串和数组的值,测试拷贝情况-------
灰太狼--[1, 4]
喜洋洋--[1, 2]

最结果看出,对象所有属性都进行可控了,修改product1的属性,不会改变product2的属性

深拷贝

创建序列化拷贝对象SerializedClone

public class SerializedClone {
   public static <T extends Serializable> T clone(T obj) {
      T cloneObj = null;
      try {
         //写入字节流
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         ObjectOutputStream obs = new ObjectOutputStream(out);
         obs.writeObject(obj);
         obs.close();

         //分配内存,写入原始对象,生成新对象
         ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
         ObjectInputStream ois = new ObjectInputStream(ios);
         //返回生成的新对象
         cloneObj = (T) ois.readObject();
         ois.close();
      } catch (Exception e) {
         e.printStackTrace();
      }
      return cloneObj;
   }
}

测试:

String name1 = "喜洋洋";
int[] array1 = {10,12};
Product product3 = new Product(name1,array1);
Product product4 = SerializedClone.clone(product3);
System.out.println(product3.toString());
System.out.println(product4.toString());
System.out.println("-------修改属性");
array[1]=3;
product1.setArray(array);
System.out.println(product3.toString());
System.out.println(product4.toString());

输出如下:

喜洋洋--[10, 12]
喜洋洋--[10, 12]
-------修改属性
喜洋洋--[10, 12]
喜洋洋--[10, 12]

序列化拷贝并不会因原型对象的属性值改变而发生变化