分類
設(shè)計(jì)模式共分為三種類型:創(chuàng)建型辆布、結(jié)構(gòu)型檬贰、行為型
- 創(chuàng)建型:用于創(chuàng)建對象庐扫,為設(shè)計(jì)類實(shí)例化新對象提供指南
- 結(jié)構(gòu)型:用于處理類或?qū)ο蟮慕M合瞳脓,對類如何設(shè)計(jì)以形成更大的結(jié)構(gòu)提供指南
- 行為型:用于描述類或?qū)ο蟮慕换ヒ约奥氊?zé)的分配塑娇,對類之間交互以及分配職責(zé)的方式提供指南
定義來自權(quán)威的軟考
常見的設(shè)計(jì)模式有如下幾種
創(chuàng)建型:構(gòu)建者、單例劫侧、工廠
結(jié)構(gòu)型:適配器钝吮、代理、外觀
行為型:策略板辽、觀察者、責(zé)任鏈
正文
Builder構(gòu)建者
場景
用于生成對象的類其內(nèi)部結(jié)構(gòu)過于復(fù)雜棘催,為屏蔽類的復(fù)雜性劲弦,需要將類的構(gòu)建和表示進(jìn)行分離,用最少的參數(shù)生成對象-
例子
OkHttpClient
產(chǎn)生實(shí)際對象的必需參數(shù)是從builder對象中取出的
即使什么參數(shù)也不傳Builder也會生成默認(rèn)參數(shù)醇坝,以支持對象的生成
每次添加參數(shù)時邑跪,記得返回Builder對象次坡,用以鏈?zhǔn)降膫鬟f
Singleton單例
- 場景
保證實(shí)例是唯一的存在画畅,以保證操作的唯一性
單例模式的實(shí)現(xiàn)有兩種:飽漢砸琅、餓漢模式
聯(lián)想記憶:飽漢不餓,需要的時候再吃轴踱;餓漢很饑症脂,提前搶著吃
飽漢其實(shí)是懶加載,不必提前占內(nèi)存
- 例子
//飽漢模式
public class SingletonClass{
private static volatile SingletonClass instance=null;//靜態(tài)變量保證對象的唯一性淫僻,volatile關(guān)鍵字防止指令重排
public static SingletonClass getInstance(){//使用內(nèi)部加鎖诱篷,避免每次調(diào)用時無謂的加鎖,提升了性能
if(instance==null){//指令重排的話雳灵,其他線程看到instance不空棕所,則不會進(jìn)入,也不會加鎖悯辙,直接返回半成品instance琳省,從而導(dǎo)致異常
synchronized(SingletonClass.class){//鎖對象最好是類對象(個人觀點(diǎn))
if(instance==null)//再判斷一遍,避免多個線程在上一行同時被鎖住躲撰,釋放后進(jìn)入针贬,再次實(shí)例化對象
instance=new SingletonClass();//指令重排發(fā)生地
}
}
return instance;
}
private SingletonClass(){//私有構(gòu)造方法,防止實(shí)例化
}
}
//餓漢模式
public static class Singleton{//靜態(tài)類直接進(jìn)入方法區(qū)常量池
private static final Singleton instance = new Singleton();//靜態(tài)常量進(jìn)入方法區(qū)常量池
private Singleton(){//私有構(gòu)造方法茴肥,防止實(shí)例化
}
public static Singleton getInstance(){//靜態(tài)方法
return instance;
}
}
餓漢模式坚踩,由于事先分配內(nèi)存空間不存在飽漢的多線程問題,但其常駐內(nèi)存會造成開銷問題瓤狐,不同的場景需采用不同的手段以保證消耗與效率的平衡瞬铸。
Factory工廠
場景
多態(tài)場景下,用以管理生成不同的對象础锐,并且耦合度不能夠過高例子
簡單工廠模式
public interface Phone {//Phone是產(chǎn)品抽象
}
public class Honor implements Phone{//Honor是具體的產(chǎn)品
}
public class Mate20 implements Phone{//Mate20是具體的產(chǎn)品
}
public class HuaWei {//具體的廠商
public static Phone create(String str){//廠商根據(jù)要求生產(chǎn)手機(jī)
if(str.equalsIgnoreCase("honor")){
return new Honor();
}
else if(str.equalsIgnoreCase("mate20")){
return new Mate20();
}
return null;
}
}
工廠方法模式
public interface Phone {//Phone是產(chǎn)品抽象
}
public interface Factory {//Factory是廠商抽象
public Phone create();
}
public class HWPhone implements Phone{//華為手機(jī)
}
public class MPhone implements Phone{//小米手機(jī)
}
public class HuaWei implements Factory {//華為產(chǎn)華為手機(jī)
public Phone create(){
return new HWPhone();
}
}
public class XiaoMi implements Factory {//小米產(chǎn)小米手機(jī)
public Phone create(){
return new MPhone();
}
}
簡單工廠模式:一個工廠類嗓节,工廠生產(chǎn)各種產(chǎn)品
工廠方法模式:一個工廠接口,多個工廠類皆警,不同工廠生產(chǎn)不同產(chǎn)品
工廠方法模式的改進(jìn)在于拦宣,減輕了簡單工廠模式中工廠類的復(fù)雜度,具體的產(chǎn)出交由具體的工廠類信姓,降低了耦合度鸵隧。
抽象工廠模式
public interface Phone {//Phone是產(chǎn)品抽象
}
public interface OS {//OS是產(chǎn)品抽象
}
public interface Factory {//Factory是廠商抽象
public Phone create();
public OS develop();
}
public class HWPhone implements Phone{//華為手機(jī)
}
public class MPhone implements Phone{//小米手機(jī)
}
public class MIUI implements OS{//系統(tǒng)
}
public class EMUI implements OS{//系統(tǒng)
}
public class HuaWei implements Factory{//華為產(chǎn)華為手機(jī)
public Phone create(){
return new HWPhone();
}
public OS develop(){
return new EMUI();
}
}
public class XiaoMi implements Factory{//小米產(chǎn)小米手機(jī)
public Phone create(){
return new MPhone();
}
public OS develop(){
return new MIUI();
}
}
抽象工廠模式較工廠方法模式的區(qū)別在于,不生產(chǎn)單一產(chǎn)品意推,使工廠能夠生產(chǎn)不同類型的相關(guān)產(chǎn)品豆瘫,從而提高擴(kuò)展性
在Retrofit中
使用的是工廠方法模式,將工廠抽象
初始化階段菊值,將實(shí)例化的不同工廠放在List中外驱,根據(jù)參數(shù)使用情景的不同育灸,再在List中取出合適的工廠進(jìn)行處理。
Adapter適配器
場景
已有類的功能不滿足需求昵宇,需將功能進(jìn)行轉(zhuǎn)換磅崭,以達(dá)到匹配例子
類適配器模式
原有類并不具備某功能,通過創(chuàng)建Adapter類瓦哎,繼承原有功能砸喻、實(shí)現(xiàn)目標(biāo)功能接口,從滿足功能要求
public class Source {//現(xiàn)有類
public void method1() {
System.out.println("this is original method!");
}
}
public interface Targetable {//目標(biāo)功能
public void method1();
public void method2();//缺失功能
}
public class Adapter extends Source implements Targetable {
@Override
public void method2() {//補(bǔ)足缺失
System.out.println("this is the targetable method!");
}
}
對象適配器模式
不同于類適配器模式杭煎,通過繼承恩够、實(shí)現(xiàn)這種高耦合手段,以滿足功能要求羡铲。對象適配器模式采用的是聚合的手段蜂桶,創(chuàng)建新類Wrapper通過持有原類對象具備原有功能外;并且類Wrapper實(shí)現(xiàn)功能接口補(bǔ)足缺失功能
如OkHttpClient中的Cache類
在OkHttpClient中緩存攔截器一層使用的是InternalCache也切,見注釋扑媚,官方已經(jīng)不建議使用此類改用Cache
Cache類本身并沒有實(shí)現(xiàn)InternalCache接口,而是持有一個InternalCache對象雷恃,且對象內(nèi)的方法都是調(diào)用Cache內(nèi)的
接口適配器模式
不同于類適配器模式疆股、對象適配器模式的補(bǔ)足功能,接口適配器模式恰恰相反:不暴露功能倒槐。
當(dāng)接口方法過多旬痹,而我們關(guān)心的卻寥寥可數(shù)時,通過實(shí)現(xiàn)接口的方式就會空實(shí)現(xiàn)很多不必要的方法讨越。通過两残,創(chuàng)建新類(或抽象類)空實(shí)現(xiàn)所有方法,實(shí)際使用時繼承自新類重寫關(guān)心的方法把跨,就避免了每次實(shí)現(xiàn)方法過多的問題人弓,這種設(shè)計(jì)的原則是接口隔離,對接口知道的越少越好
如OkHttp中的回調(diào)監(jiān)聽EventListener
所有階段的回調(diào)都空實(shí)現(xiàn)着逐,當(dāng)我關(guān)心某一階段的回調(diào)時崔赌,就重寫對應(yīng)方法,否則20個回調(diào)方法每添加一次監(jiān)聽就都要實(shí)現(xiàn)一遍耸别,代碼的易讀性也不好
Proxy代理
代理分靜態(tài)代理和動態(tài)代理健芭,這里列舉的是靜態(tài)代理
場景
原有類的功能需要進(jìn)行擴(kuò)充例子
public interface Sourceable {
public void method();
}
public class Source implements Sourceable {//原類
@Override
public void method() {
System.out.println("the original method!");
}
}
public class Proxy implements Sourceable {//代理類
private Source source;
public Proxy(){
super();
this.source = new Source();
}
@Override
public void method() {
before();
source.method();
atfer();
}
private void atfer() {
System.out.println("after proxy!");
}
private void before() {
System.out.println("before proxy!");
}
}
原類與代理類都實(shí)現(xiàn)了相同的接口,方法的實(shí)際執(zhí)行是由代理對象觸發(fā)的秀姐,只不過代理對象在方法觸發(fā)前后增加了其他功能吟榴。
有點(diǎn)和對象適配器模式類似都實(shí)現(xiàn)相關(guān)接口、持有原類對象囊扳,但
- 對象適配器模式是為了彌補(bǔ)功能上的不足
- 代理模式是給功能進(jìn)行加強(qiáng)
一個是彌補(bǔ)功能吩翻,一個是加強(qiáng)功能這是兩種模式的區(qū)別
從上來看對象適配器模式中的Cache例子放錯位置了,它應(yīng)該屬于靜態(tài)代理模式锥咸,Cache是被代理類狭瞎,InternalCache是代理類
Facade外觀
場景
多個類間有依賴關(guān)系時,由多個類組合創(chuàng)建新類例子
OkHttpClient和Retrofit類就是明顯的外觀模式搏予,其內(nèi)部由多個功能不同的類對象組成熊锭,外部的單一操作實(shí)際影響內(nèi)部多個對象間的聯(lián)動。
Strategy策略
場景
相同的方法雪侥,根據(jù)不同的情景有不同的實(shí)現(xiàn)例子
以前做過比特幣的自動交易軟件碗殷,實(shí)際操作就兩種:買、賣速缨,但是針對不同的行情锌妻、手上的持倉和現(xiàn)金情況,買和賣就變得有學(xué)問了:
行情好的時候采用激進(jìn)策略旬牲,大膽買賣仿粹;
行情差的時候就要高拋低吸,慢慢來原茅;
Observer觀察者
場景
某一對象狀態(tài)發(fā)生變化時吭历,其他對象需要及時的告知例子
android中的回調(diào)就是觀察者模式,簡單點(diǎn)的:給一個button設(shè)置onClickListener擂橘,此時觀察者就是onClickListener被觀察者是button晌区,setOnClickListener是給兩者創(chuàng)建關(guān)聯(lián),當(dāng)被觀察者button被單擊通贞,觀察者onClickListener就會作出回應(yīng)朗若。
Chain of Responsibility責(zé)任鏈
場景
問題一次得不到解決,需要層層處理并傳遞滑频,每次將任務(wù)細(xì)化例子
最有名的當(dāng)數(shù)OkHttp捡偏,其中的鏈?zhǔn)黔h(huán)形鏈
有些自己用的比較熟的或沒太多重點(diǎn)要記錄的就沒有貼例子,一般這種模式比較常見且簡單