## 1 原型模式

指定创建对象的种类，并且通**过拷贝这些原型，创建新的对象**，是一种创建型设计模式，允许一个对象再创建另外一个可定制的对象，无需知道如何创建的细节。这种模式现了一个原型接口，该接口用于创建当前对象的克隆。

原型模式的构成：

* Prototype : 原型类，声明一个克隆自己的接口
* ConcretePrototype: 具体的原型类,  实现一个克隆自己的操作
* Client: 让一个原型对象克隆自己，从而创建一个新的对象(属性一样）

## 2 例子

```java
//克隆羊
public class Sheep implements Cloneable{

    private String name;

    private int age;

    public Country country; //对象,  克隆是会如何处理,  默认是浅拷贝

    public Sheep(String name, int age,Country country) {
        this.name = name;
        this.age = age;
        this.country = country;
    }

    @Override
    protected Object clone() {
        Sheep sheep = null;
        try {
            sheep = (Sheep)super.clone();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return sheep;
    }

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", country=" + country +
                ", countryHashCode=" + country.hashCode() +
                '}';
    }
   //省略 getter/setter
}

public class Country implements Cloneable{
    private  String name;

    @Override
    protected Object clone() {
        Country country = null;
        try {
            country = (Country)super.clone();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return country;
    }

    @Override
    public String toString() {
        return "Country{" +
                "name='" + name + '\'' +
                '}';
    }
    //省略 getter/setter
}


public class Client {
    public static void main(String[] args) {
        Sheep sheep = new Sheep("多利羊", 3,new Country("美国"));
        Sheep sheep1 = (Sheep)sheep.clone();
        Sheep sheep2 = (Sheep)sheep.clone();
        Sheep sheep3 = (Sheep)sheep.clone();
        Sheep sheep4 = (Sheep)sheep.clone();
        System.out.println("sheep1 =" + sheep1 );
        System.out.println("sheep2 =" + sheep2 );
        System.out.println("sheep3 =" + sheep3 );
        System.out.println("sheep4 =" + sheep4 );
    }

}

//输出：
//sheep1 =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=356573597}
//sheep2 =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=356573597}
//sheep3 =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=356573597}
//sheep4 =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=356573597}
```

## 3 浅拷贝和深拷贝

基本数据类型的成员变量：

* 浅拷贝：直接进行值传递，该属性值复制一份给新的对象。
* 深拷贝：直接进行值传递，该属性值复制一份给新的对象。

引用数据类型的成员变量：

- 浅拷贝：将该成员变量的引用值（内存地址）复制一份给新的对象。
- 深拷贝：创建一个新对象，赋值。

## 4 深拷贝

```java
//方法一：将 Sheep 的 clone 修改为如下
@Override
protected Object clone() {
    Sheep sheep = null;
    try {
       sheep = (Sheep)super.clone();
       //对象修改为可 clone
       sheep.setCountry((Country)this.country.clone());
     } catch (Exception e){
       System.out.println(e.getMessage());
     }
       return sheep;
}
//输出：
//sheep1 =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=356573597}
//sheep2 =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=1735600054}
//sheep3 =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=21685669}
// =Sheep{name='多利羊', age=3, country=Country{name='美国'}, countryHashCode=2133927002}

//方法二：使用序列化
public class DeepSheep implements Serializable, Cloneable{

    private String name;

    private int age;

    public Country country; //对象,  克隆是会如何处理,  默认是浅拷贝

    public DeepSheep(String name, int age, Country country) {
        this.name = name;
        this.age = age;
        this.country = country;
    }

    @Override
    protected Object clone() {
        DeepSheep sheep = null;
        try {
            sheep = deepClone();
            //sheep = SerializationUtils.deepCopy(this);
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return sheep;
    }

    public DeepSheep deepClone() throws IOException,ClassNotFoundException{
        //将对象写入流中
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
        objectOutputStream.writeObject(this);
        //从流中取出
        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
        return (DeepSheep)objectInputStream.readObject();
    }


    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", country=" + country +
                ", countryHashCode=" + country.hashCode() +
                '}';
    }
    //省略 getter/setter
}

public class Client {
    public static void main(String[] args) {
        DeepSheep deepSheep = new DeepSheep("汤姆羊", 3,new Country("法国"));
        DeepSheep deepSheep1 = (DeepSheep)deepSheep.clone();
        DeepSheep deepSheep2 = (DeepSheep)deepSheep.clone();
        DeepSheep deepSheep3 = (DeepSheep)deepSheep.clone();
        DeepSheep deepSheep4 = (DeepSheep)deepSheep.clone();
        System.out.println("deepSheep1 =" + deepSheep1 );
        System.out.println("deepSheep2 =" + deepSheep2 );
        System.out.println("deepSheep3 =" + deepSheep3 );
        System.out.println("deepSheep4 =" + deepSheep4 );
    }
}
//deepSheep1 =Sheep{name='汤姆羊', age=3, country=Country{name='法国'}, countryHashCode=1531448569}
//deepSheep2 =Sheep{name='汤姆羊', age=3, country=Country{name='法国'}, countryHashCode=1867083167}
//deepSheep3 =Sheep{name='汤姆羊', age=3, country=Country{name='法国'}, countryHashCode=1915910607}
//deepSheep4 =Sheep{name='汤姆羊', age=3, country=Country{name='法国'}, countryHashCode=284720968}

//深拷贝工具类
public class SerializationUtils {
    public static <T> T deepCopy(T src) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteOut);
        out.writeObject(src);

        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
        ObjectInputStream in = new ObjectInputStream(byteIn);
        @SuppressWarnings("unchecked")
        T dest = (T) in.readObject();
        return dest;
    }
}

```



## 5 注意事项

* 创建新的对象比较复杂时，可以利用原型模式简化对象的创建过程，同时也能够提高效率

* 不用重新初始化对象，而是动态地获得对象运行时的状态

* 如果原始对象发生变化(增加或者减少属性)，其它克隆对象的也会发生相应的变化，无需修改代码

* 在实现深克隆的时候可能需要比较复杂的代码

* 缺点：需要为每一个类配备一个克隆方法，这对全新的类来说不是很难，但对已有的类进行改造时，需要修改其源代码，违背了 ocp 原则，这点请同学们注意.