什麼是原型模式
原型設計模式簡單來說就是克隆
原型表明了有一個樣板實例,這個原型是可定製的。原型模式多用於創建複雜的或者構造耗時的實例,因爲這種情況下,複製一個已經存在的實例可使程序運行更高效。
原型模式的應用場景
- 類初始化需要消化非常多的資源,這個資源包括數據、硬件資源等。這時我們就可以通過原型拷貝避免這些消耗。
- 通過new產生的一個對象需要非常繁瑣的數據準備或者權限,這時可以使用原型模式。
- 一個對象需要提供給其他對象訪問,而且各個調用者可能都需要修改其值時,可以考慮使用原型模式拷貝多個對象供調用者使用,即保護性拷貝。
我們Spring框架中的多例就是使用原型。
原型模式的使用方式
-
實現Cloneable接口。在java語言有一個Cloneable接口,它的作用只有一個,就是在運行時通知虛擬機可以安全地在實現了此接口的類上使用clone方法。在java虛擬機中,只有實現了這個接口的類纔可以被拷貝,否則在運行時會拋出CloneNotSupportedException異常。
-
重寫Object類中的clone方法。Java中,所有類的父類都是Object類,Object類中有一個clone方法,作用是返回對象的一個拷貝,但是其作用域protected類型的,一般的類無法調用,因此Prototype類需要將clone方法的作用域修改爲public類型。
原型模式分爲淺複製和深複製
-
(淺複製)只是拷貝了基本類型的數據,而引用類型數據,只是拷貝了一份引用地址。
-
(深複製)在計算機中開闢了一塊新的內存地址用於存放複製的對象。
代碼演示
- 創建User類
package com.lijie;
import java.util.ArrayList;
public class User implements Cloneable {
private String name;
private String password;
private ArrayList<String> phones;
protected User clone() {
try {
User user = (User) super.clone();
//重點,如果要連帶引用類型一起復制,需要添加底下一條代碼,如果不加就對於是複製了引用地址
user.phones = (ArrayList<String>) this.phones.clone();//設置深複製
return user;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
//省略所有屬性Git Set方法......
}
- 測試複製
package com.lijie;
import java.util.ArrayList;
public class Client {
public static void main(String[] args) {
//創建User原型對象
User user = new User();
user.setName("李三");
user.setPassword("123456");
ArrayList<String> phones = new ArrayList<>();
phones.add("17674553302");
user.setPhones(phones);
//copy一個user對象,並且對象的屬性
User user2 = user.clone();
user2.setPassword("654321");
//查看倆個對象是否是一個
System.out.println(user == user2);
//查看屬性內容
System.out.println(user.getName() + " | " + user2.getName());
System.out.println(user.getPassword() + " | " + user2.getPassword());
//查看對於引用類型拷貝
System.out.println(user.getPhones() == user2.getPhones());
}
}
- 如果不需要深複製,需要刪除User 中的
//默認引用類型爲淺複製,這是設置了深複製
user.phones = (ArrayList<String>) this.phones.clone();