相關文章
設計模式系列java
公衆號有同窗留言設計模式,才發現很久沒有寫設計模式了。關於建立型設計模式只差原型模式沒寫了,這一篇就來填補這個空缺。
設計模式
定義:用原型實例指定建立對象的種類,並經過拷貝這些原型建立新的對象。數組
在原型模式中有以下角色:微信
須要注意的是,Prototype一般是不用本身定義的,由於拷貝這個操做十分經常使用,Java中就提供了Cloneable接口來支持拷貝操做,它就是原型模式中的Prototype。固然,原型模式也未必非得去實現Cloneable接口,也有其餘的實現方式。ide
原型模式的核心是clone方法,經過該方法進行拷貝,這裏舉一個名片拷貝的例子。
如今已經流行電子名片了,只要掃一下就能夠將名片拷貝到本身的名片庫中, 咱們先實現名片類。函數
public class BusinessCard implements Cloneable {
private String name;
private String company;
public BusinessCard(){
System.out.println("執行構造函數BusinessCard");
}
public void setName(String name) {
this.name = name;
}
public void setCompany(String company) {
this.company = company;
}
@Override
public BusinessCard clone() {
BusinessCard businessCard = null;
try {
businessCard = (BusinessCard) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return businessCard;
}
public void show() {
System.out.println("name:" + name);
System.out.println("company:" + company);
}
}複製代碼
BusinessCard類實現了Cloneable接口,它是一個標識接口,表示這個對象是可拷貝的,只要重寫clone方法就能夠實現拷貝。若是實現了Cloneable接口卻沒有重寫clone方法就會報錯。須要注意的是,clone方法不是在Cloneable接口中定義的(Cloneable接口中沒有定義任何方法),而是在Object中定義的。性能
public class Client {
public static void main(String[] args) {
BusinessCard businessCard = new BusinessCard();
businessCard.setName("錢三");
businessCard.setCompany("阿里");
//拷貝名片
BusinessCard cloneCard1 = businessCard.clone();
cloneCard1.setName("趙四");
cloneCard1.setCompany("百度");
BusinessCard cloneCard2 = businessCard.clone();
cloneCard2.setName("孫五");
cloneCard2.setCompany("騰訊");
businessCard.show();
cloneCard1.show();
cloneCard2.show();
}
}複製代碼
除了第一個名片,其餘兩個名片都是經過clone方法獲得的,須要注意的是,clone方法並不會執行cloneCard1和cloneCard2的構造函數,運行結果爲:
執行構造函數BusinessCard
name:錢三
company:阿里
name:趙四
company:百度
name:孫五
company:騰訊this
原型模式涉及到淺拷貝和深拷貝的知識點,爲了更好的理解它們,還須要舉一些例子。spa
上述的例子中,BusinessCard的字段都是String類型的,若是字段是引用的類型的,會出現什麼狀況呢?以下所示。設計
public class DeepBusinessCard implements Cloneable {
private String name;
private Company company = new Company();
public void setName(String name) {
this.name = name;
}
public void setCompany(String name, String address) {
this.company.setName(name);
this.company.setAddress(address);
}
@Override
public DeepBusinessCard clone() {
DeepBusinessCard businessCard = null;
try {
businessCard = (DeepBusinessCard) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return businessCard;
}
public void show() {
System.out.println("name:" + name);
System.out.println("company:" + company.getName() + "-address-" + company.getAddress());
}
}複製代碼
咱們定義了DeepBusinessCard 類,它的字段company是引用類型的,Company類以下所示。
public class Company {
private String name;
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}複製代碼
在客戶端使用DeepBusinessCard:
public class Client {
public static void main(String[] args) {
DeepBusinessCard businessCard=new DeepBusinessCard();
businessCard.setName("錢三");
businessCard.setCompany("阿里","北京望京");
DeepBusinessCard cloneCard1=businessCard.clone();
cloneCard1.setName("趙四");
cloneCard1.setCompany("百度","北京西二旗");
DeepBusinessCard cloneCard2=businessCard.clone();
cloneCard2.setName("孫五");
cloneCard2.setCompany("騰訊","北京中關村");
businessCard.show();
cloneCard1.show();
cloneCard2.show();
}
}複製代碼
運行結果爲:
name:錢三
company:騰訊-address-北京中關村
name:趙四
company:騰訊-address-北京中關村
name:孫五
company:騰訊-address-北京中關村
從結果能夠看出company字段爲最後設置的"騰訊"、"北京中關村"。這是由於Object類提供的clone方法,不會拷貝對象中的內部數組和引用對象,致使它們仍舊指向原來對象的內部元素地址,這種拷貝叫作淺拷貝。
company字段是引用類型,businessCard被拷貝後,company字段仍舊指向原來的businessCard對象的company字段的地址。這樣咱們每次設置company字段,都會覆蓋上一次設置的值,最終留下的就是最後一次設置的值:"騰訊"、"北京中關村"。
引用關係以下圖所示。
首先須要修改Company類,以下所示。
public class Company implements Cloneable{
private String name;
private String address;
...
public Company clone(){
Company company=null;
try {
company= (Company) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return company;
}
}複製代碼
爲了實現Company類能被拷貝,Company類也須要實現Cloneable接口而且覆寫clone方法。接着修改DeepBusinessCard的clone方法:
public class DeepBusinessCard implements Cloneable {
private String name;
private Company company = new Company();
...
@Override
public DeepBusinessCard clone() {
DeepBusinessCard businessCard = null;
try {
businessCard = (DeepBusinessCard) super.clone();
businessCard.company = this.company.clone();//1
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return businessCard;
}
...
}複製代碼
在註釋1處增長了對company字段的拷貝處理。最後在客戶端調用,輸出的結果爲:
name:錢三
company:阿里-address-北京望京
name:趙四
company:百度-address-北京西二旗
name:孫五
company:騰訊-address-北京中關村
原型模式是在內存中二進制流的拷貝,要比new一個對象的性能要好,特別是須要產生大量對象時。
直接在內存中拷貝,構造函數是不會執行的,這樣就減小了約束,這既是優勢也是缺點,須要在實際應用中去考量。
參考資料
《大話設計模式》
《設計模式之禪》
《Android源碼設計模式解析與實戰》
歡迎關注個人微信公衆號,第一時間得到博客更新提醒,以及更多成體系的Android相關原創技術乾貨。
掃一掃下方二維碼或者長按識別二維碼,便可關注。