## **模式的定義**
用已經創建的原型實例來指定創建對象的種類,并通過拷貝這些原型創建新的對象并完成初始化。
白話文就是說通過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`原生方法。