1、前言
当需要克隆100个名称为Dolly 年龄 1的羊,以往的写法都是直接new 100个Sheep对象;
public class PrototypeDemo {
    public static void main(String[] args) {
        // 克隆100个 名称为Dolly 年龄 1;
        Sheep dolly1 = new Sheep("Dolly", 1);
        Sheep dolly2 = new Sheep("Dolly", 1);
        Sheep dolly3 = new Sheep("Dolly", 1);
        Sheep dolly4 = new Sheep("Dolly", 1);
        // ...
        Sheep dolly100 = new Sheep("Dolly", 1);
    }
    @Data
    static
    class Sheep {
        private String name;
        private int age;
    
        public Sheep (String name,int age){
            this.name = name;
            this.age = age;
        }
    }
}
- 优点 
  - 代码直观,易于理解
 
- 缺点 
  - 在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低
- 总是需要重新初始化对象,而不是动态地获得对象运行时的状态,不够灵活
 
2、什么是原型模式
原型模式(Prototype Pattern)通过拷贝这些原型,创建新的对象,是用于创建重复的对象,同时又能保证性能。原型模式属于创建型模式,它提供了一种创建对象的最佳方式。
原型模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。
Java中Object类提供了一个clone()方法,该方法可以将一个Java对象复制一份,但是需要实现clone的Java类必须要实现一个接口Cloneable,该接口表示该类能够复制且具有复制的能力
-  原型模式的实例的拷贝包括 - 浅复制:将一个对象复制后,其基本数据类型的变量都会重新创建,而引用类型的变量指向的还是原对象所指向的,也就是指向的内存堆地址没变。
- 深复制:将一个对象复制后,不论是基本数据类型还是引用类型,都是重新创建的
 
-  通过实现Cloneable接口, Java默认的实现方式是浅复制,而非深复制。由于Object并没有实现Cloneable接口,所以子类必须实现Cloneable,并调用基类的clone方法才能实现浅复制。
3、原型模式实现
/**
 * 原型模式
 * @author liushiwei
 */
public class PrototypeDemo {
    public static void main(String[] args) throws Exception {
        prototype();
    }
    private static void prototype() throws Exception {
        ArrayList arrayList = new ArrayList();
        arrayList.add("foreFoot");
        Sheep dolly1 = new Sheep("Dolly", 1,arrayList);
        // 对象深拷贝
        Sheep dolly2 = (Sheep)dolly1.clone();
        ArrayList list = dolly2.getListFoot();
        list.add("hindFoot2");
        // 序列化的方式深拷贝
        Sheep dolly3 = (Sheep)dolly1.deepClone();
        ArrayList list3 = dolly3.getListFoot();
        list3.add("hindFoot3");
        System.out.println(dolly1 == dolly2);
        // 验证是拷贝类型,结果浅拷贝
        System.out.println("dolly1.list="+dolly1.getListFoot());
        System.out.println("dolly2.list="+dolly2.getListFoot());
        System.out.println("dolly3.list="+dolly3.getListFoot());
    }
    private static void tradition() {
        // 克隆100个 名称为Dolly 年龄 1;
        Sheep dolly1 = new Sheep("Dolly", 1,null);
        Sheep dolly2 = new Sheep("Dolly", 1,null);
        Sheep dolly3 = new Sheep("Dolly", 1,null);
        Sheep dolly4 = new Sheep("Dolly", 1,null);
        // ...
        Sheep dolly100 = new Sheep("Dolly", 1,null);
    }
}
public class Sheep implements Cloneable, Serializable {
    private String name;
    private int age;
    private ArrayList listFoot;
    public Sheep (){
    }
    public Sheep (String name,int age,ArrayList listFoot){
        this.name = name;
        this.age = age;
        this.listFoot = listFoot;
    }
    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 ArrayList getListFoot() {
        return listFoot;
    }
    public void setListFoot(ArrayList listFoot) {
        this.listFoot = listFoot;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Sheep sheep = (Sheep)super.clone();
        // 对listFoot深拷贝
        sheep.listFoot = (ArrayList) this.listFoot.clone();
        return sheep;
    }
    /**
     * 通过序列化的方式 深拷贝
     * @return
     */
    protected Object deepClone() throws Exception{
        //把对象写入到字节流中
        ByteArrayOutputStream baos =new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(this);
        //把字节流转化为对象
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        return (Sheep) ois.readObject();
    }
}
4、原型模式优缺点
-  原型模式的优点: -  提高了创建对象的性能,避免了调用构造器创建对象。 
-  对于创建一个对象需要很多资源的情况,可以减少资源的浪费。 
 
-  
-  原型模式的缺点: -  如果使用Cloneable接口的方式,需要实现Cloneable接口,对代码有一定的侵入性。 
-  如果使用序列化方式,则需要实现Serializable接口,对代码也有一定的侵入性。 
 
-  
5、原型模式的更多实现
- SpringSheep dolly4 = new Sheep(); BeanUtils.copyProperties(dolly1,dolly4); ArrayList list4 = dolly4.getListFoot(); list4.add("hindFoot4"); System.out.println("list4.list="+dolly4.getListFoot());
- fastjson 
  - 通过JSONObject.parseObject方法实现
 










