## **模式的定义**
用已经创建的原型实例来指定创建对象的种类,并通过拷贝这些原型创建新的对象并完成初始化。
白话文就是说通过new一个实例,在对这个new的实例进行拷贝来创建新的实例。
原型模式分为**浅复制**和**深复制**2种方式
## **浅复制**
浅拷贝需要实现`java.lang.Cloneable`接口,然后再调用`Object`类中的`clone`方法
1. 创建复制对象的类
```
public class Book implements Cloneable {
private String title;
private int number;
private ArrayList<String> images = new ArrayList<>();
// get set
...
public void addImages(String imgName) {
this.images.add(imgName);
}
@Override
public Book clone() {
Book book = new Book();
try {
// 调用Object父类的clone方法
book = (Book) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return book;
}
// 打印输出
public void show() {
System.out.println("title:" + title);
System.out.println("number:" + number);
String imageStr = "";
for (String image : images) {
imageStr = imageStr + "," + image;
}
System.out.println("images:" + imageStr);
System.out.println("----------------");
}
}
```
2. 客户端调用
```
public static void main(String[] args) {
Book book1 = new Book();
book1.setTitle("book1");
book1.setNumber(1);
book1.addImages("pic1");
book1.show("步骤一");
Book book2 = book1.clone();
book2.show("步骤二");
book2.setTitle("book2");
book2.setNumber(2);
book2.addImages("pic2");
book2.show("步骤三");
book1.show("步骤四");
}
```
3. 结果
```
步骤一
title:book1
number:1
images:,pic1
----------------
步骤二
title:book1
number:1
images:,pic1
----------------
步骤三
title:book2
number:2
images:,pic1,pic2
----------------
步骤四
title:book1
number:1
images:,pic1,pic2
----------------
```
步骤一二三应该很好的理解,book2成功的完成了复制的功能,但是步骤四却让人产生了疑虑,book2在改变images值的时候,book1中images的值也发送了改变,这明显不是我们想要的复制结果,通过查找资料发现,浅复制的复制方式
```
基本数据类型:复制成员变量以及它的值
引用数据类型:复制成员变量以及它的引用地址的值
```
Book对象中
* number(int):基本数据类型,复制的时候就是产生一个新的副本
* images(ArrayList):引用数据类型,复制完后book2中images引用地址的值和book1中的是相同的,book1和book2中的images引用的是同一个引用对象,我们在操作images时,都是对同一个引用对象进行改变,所以就导致了步骤四的问题
* title(String):引用数据类型,为什么就没问题呢?String对象用的final修饰,是一个不可变的对象,每次修改它的值都是会改变它的引用对象(而不是对它的引用对象进行改变)
## **深复制**
为了解决上面浅复制引用数据类型的问题,Java提供了深复制的功能来完成引用类型数据的复制
只需要在上面的代码中修改clone方法
```
@Override
public Book clone() {
Book book = new Book();
try {
book = (Book) super.clone(); // 代码1
// 深复制
book.images = (ArrayList<String>) this.images.clone(); // 代码2
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return book;
}
```
代码1处调用的clone方法是`Object`类中的提供的原生方法,代码2处调用的底层方法是`System`类中的`arraycopy`原生方法。