1:單例模式
只能有一個實例
推薦:靜態(tài)內(nèi)部類單例模式
理由:靜態(tài)內(nèi)部類,當(dāng)你使用它的時候才加載,這種方式不僅能夠確保線程安全,也能夠保證單例對象的唯一性,同時也延遲了單例的實例化,所以推薦使用
public class Singleton {
private Singleton(){}
/**
* 類級的內(nèi)部類,也就是靜態(tài)的成員式內(nèi)部類,該內(nèi)部類的實例與外部類的實例
* 沒有綁定關(guān)系,而且只有被調(diào)用到時才會裝載,從而實現(xiàn)了延遲加載。
*/
private static class SingletonHolder{
/**
* 靜態(tài)初始化器,由JVM來保證線程安全
*/
private static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
優(yōu)缺點:
單例只有在使用時才會被實例化,在一定程度上節(jié)約了資源
單例類的職責(zé)過重,里面的代碼可能會過于復(fù)雜,在一定程度上違背了“單一職責(zé)原則”
Android中單例對象如果持有Context,那么很容易引發(fā)內(nèi)存泄露,此時需要注意傳遞給單例對象的Context最好是Application Context
參考:
《JAVA與模式》之單例模式
《Android源碼設(shè)計模式》--單例模式
2:簡單工廠模式
產(chǎn)品抽象實現(xiàn)多態(tài),而工廠單一的模式
一個工廠,一個抽象產(chǎn)品,多個產(chǎn)品子類
簡單工廠模式不是 23 種里的一種,簡而言之,就是有一個專門生產(chǎn)某個產(chǎn)品的類
3:工廠方法模式
產(chǎn)品抽象實現(xiàn)多態(tài),且工廠抽象實現(xiàn)多態(tài)的模式
一個抽象工廠,多個工廠子類,一個抽象產(chǎn)品和多個產(chǎn)品子類
和簡單工廠的區(qū)別:將工廠也抽象,避免了當(dāng)產(chǎn)品過多,一個工廠的復(fù)雜性
更符合開-閉原則
符合單一職責(zé)原則
不使用靜態(tài)工廠方法,可以形成基于繼承的等級結(jié)構(gòu)。
4:抽象方法模式
工廠升級,需要生產(chǎn)多個方向的不同產(chǎn)品,需要將產(chǎn)品進(jìn)一步抽象
就是抽象,可拓展,進(jìn)一步抽象,不妨使用“接口”。
抽象工廠模式與工廠方法模式的最大區(qū)別就在于,工廠方法模式針對的是一個產(chǎn)品等級結(jié)構(gòu);而抽象工廠模式則需要面對多個產(chǎn)品等級結(jié)構(gòu)。
優(yōu)點:新增工廠容易擴(kuò)展
缺點: 如果是新的產(chǎn)品,需要修改抽象工廠,從而修改所有工廠子類
參考: 《JAVA與模式》之抽象工廠模式
5:建造者模式
復(fù)雜對象的創(chuàng)建和他的表現(xiàn)分離,可以生產(chǎn)很多不同表現(xiàn)的對象
通常會將Builder設(shè)計為鏈?zhǔn)秸{(diào)用,他的關(guān)鍵點是每個setter方法都返回自身,也就是return this,這樣就使得setter方法可以鏈?zhǔn)秸{(diào)用
參考:Builder模式
builder模式另一個重要特性是:它可以對參數(shù)進(jìn)行合法性驗證
/**
* 創(chuàng)建外部類person
* @return
*/
public Person create(){
Person person = new Person(this);
//線程不安全的,所以需要對象創(chuàng)建之后進(jìn)行合法性驗證
if(person.age > 40){
throw new IllegalStateException("年齡超過限制!");
}
return person;
}
參考:Android設(shè)計模式之建造者模式(builder pattern)
缺點:會產(chǎn)生多余的Builder對象以及Director對象,消耗內(nèi)存
對象的構(gòu)建過程暴露
參考: 《Android源碼設(shè)計模式》--Builder模式
6:原型模式
要求對象實現(xiàn)一個可以“克隆”自身的接口,通過一個實例對象本身來創(chuàng)建一個新的實例
如下:通過調(diào)用operation(Prototype example)方法傳入不同的實例對象,克隆一個新的對象,而且可以更加傳入的不同實例創(chuàng)建不同的對象的實例對象。
public class Client {
/**
* 持有需要使用的原型接口對象
*/
private Prototype prototype;
/**
* 構(gòu)造方法,傳入需要使用的原型接口對象
*/
public Client(Prototype prototype){
this.prototype = prototype;
}
public void operation(Prototype example){
//需要創(chuàng)建原型接口的對象
Prototype copyPrototype = prototype.clone();
}
}
java 的克隆過程,存在一個淺度克隆和深度克隆的問題
淺度克隆:不復(fù)制它所引用的對象
深度克隆:除了淺度克隆要克隆的值外,還負(fù)責(zé)克隆引用類型的數(shù)據(jù)。那些引用其他對象的變量將指向被復(fù)制過的新對象,而不再是原有的那些被引用的對象。換言之,深度克隆把要復(fù)制的對象所引用的對象都復(fù)制了一遍,而這種對被引用到的對象的復(fù)制叫做間接復(fù)制
方法:可以利用序列化實現(xiàn)深度克隆
適用場景
~創(chuàng)建新對象成本較大(如初始化占用較長的時間,占用太多CPU或網(wǎng)絡(luò)資源)
~如果系統(tǒng)要保存對象的狀態(tài),而對象的狀態(tài)變化很小