设计模式之原型模式

原型模式主要是为了解决需要创建多个相同的类时,提高其效率的一种模式。

 

假设我们现在要new10十只相同的🐏,我们用最蠢的方法:

 

sheep类:

package com.atguigu.prototype;

 

public class Sheep {

   private String name;

   private int age;

   private String color;

   public Sheep(String name, int age, String color) {

      super();

      this.name = name;

      this.age = age;

      this.color = color;

   }

   public String getName() {

      return name;

   }

   public void setName(String name) {

      this.name = name;

   }

   public int getAge() {

      return age;

   }

   public void setAge(int age) {

      this.age = age;

   }

   public String getColor() {

      return color;

   }

   public void setColor(String color) {

      this.color = color;

   }

   @Override

   public String toString() {

      return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";

   }

   

   

}

现在我们来复制🐏:

 

package com.atguigu.prototype;

 

public class Client {

 

   public static void main(String[] args) {

      // TODO Auto-generated method stub

      //传统的方法

      Sheep sheep = new Sheep("tom", 1, "白色");

      

      Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());

      Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());

      Sheep sheep4 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());

      Sheep sheep5 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());

      //....

      

      System.out.println(sheep);

      System.out.println(sheep2);

      System.out.println(sheep3);

      System.out.println(sheep4);

      System.out.println(sheep5);

      //...

   }

 

}

五只意思意思一下,然而这种效率是非常低的。

 

下面我们使用原型模式:

 

object中有一个方法叫做clone,我们知道,Java中所有的类都是继承object的,不过你想使用这个方法,还需要自己重写。

 

//克隆该实例,使用默认的clone方法来完成

@Override

protected Object clone() throws CloneNotSupportedException {

   

   // TODO Auto-generated method stub

   return (Sheep)super.clone();

}

 

 

package com.atguigu.prototype.improve;

 

 

 

public class Client {

 

   public static void main(String[] args) throws CloneNotSupportedException {

      System.out.println("原型模式完成对象的创建");

      // TODO Auto-generated method stub

      Sheep sheep = new Sheep("tom", 1, "白色");

      

      sheep.friend = new Sheep("jack", 2, "黑色");

      

   Sheep sheep2 = (Sheep)sheep.clone(); //克隆

      Sheep sheep3 = (Sheep)sheep.clone(); //克隆

      Sheep sheep4 = (Sheep)sheep.clone(); //克隆

      Sheep sheep5 = (Sheep)sheep.clone(); //克隆

      

   }

 

}

这样就使用原型模式,效率要比一个一个new的效率要高。

 

 

 

如果我们在sheep类里面聚合一个羊类,这是羊的朋友:

 

public Sheep friend; //是对象, 克隆是会如何处理

然后再将其clone并打印就会发现被clone的这个羊朋友对象,是同一个对象,由此可见,clone这个方法对普通数据类型和String类型使用的是深拷贝,而对引用类型使用的是浅拷贝,解决这种问题有两种办法。首先我们new两个类:

 

package com.atguigu.prototype.deepclone;

 

import java.io.Serializable;

 

public class DeepCloneableTarget implements Serializable, Cloneable {

   

   /**

    * 

    */

   private static final long serialVersionUID = 1L;

 

   private String cloneName;

 

   private String cloneClass;

 

   //构造器

   public DeepCloneableTarget(String cloneName, String cloneClass) {

      this.cloneName = cloneName;

      this.cloneClass = cloneClass;

   }

 

   //因为该类的属性,都是String , 因此我们这里使用默认的clone完成即可

   @Override

   protected Object clone() throws CloneNotSupportedException {

      return super.clone();

   }

}

 

 

package com.atguigu.prototype.deepclone;

 

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.io.Serializable;

 

public class DeepProtoType implements Serializable, Cloneable{

   

   public String name; //String 属性

   public DeepCloneableTarget deepCloneableTarget;// 引用类型

   public DeepProtoType() {

      super();

   }

   

   

   //深拷贝 - 方式 1 使用clone 方法

   @Override

   protected Object clone() throws CloneNotSupportedException {

      

      Object deep = null;

      //这里完成对基本数据类型(属性)和String的克隆

      deep = super.clone(); 

      //对引用类型的属性,进行单独处理

      DeepProtoType deepProtoType = (DeepProtoType)deep;

      deepProtoType.deepCloneableTarget  = (DeepCloneableTarget)deepCloneableTarget.clone();

      

      // TODO Auto-generated method stub

      return deepProtoType;

   }

   

   //深拷贝 - 方式2 通过对象的序列化实现 (推荐)

   

   public Object deepClone() {

      

      //创建流对象

      ByteArrayOutputStream bos = null;

      ObjectOutputStream oos = null;

      ByteArrayInputStream bis = null;

      ObjectInputStream ois = null;

      

      try {

         

         //序列化

         bos = new ByteArrayOutputStream();

         oos = new ObjectOutputStream(bos);

         oos.writeObject(this); //当前这个对象以对象流的方式输出

         

         //反序列化

         bis = new ByteArrayInputStream(bos.toByteArray());

         ois = new ObjectInputStream(bis);

         DeepProtoType copyObj = (DeepProtoType)ois.readObject();

         

         return copyObj;

         

      } catch (Exception e) {

         // TODO: handle exception

         e.printStackTrace();

         return null;

      } finally {

         //关闭流

         try {

            bos.close();

            oos.close();

            bis.close();

            ois.close();

         } catch (Exception e2) {

            // TODO: handle exception

            System.out.println(e2.getMessage());

         }

      }

      

   }

   

}

 

 

第一种方法就是先将普通数据类型和String类型进行拷贝以后,在单独拿构造类型的clone方式再进行clone一次,

 

第二种方法就是使用IO将数据流拷贝到另一个容器当中,这种办法推荐使用。

 

 

 

值得一提的是,Spring的Ioc容器当中也使用了原型模式。

 

posted @ 2020-06-30 17:56  18软件工程五班陈星星  阅读(134)  评论(0编辑  收藏  举报