一、引言
7大設(shè)計(jì)原則主要包括開閉原則、里氏替換原則、依賴倒置原則、單一職責(zé)原則、接口隔離原則、最小知識(shí)原則(迪米特原則)和合成復(fù)用原則。3大設(shè)計(jì)模式主要包括創(chuàng)建型、結(jié)構(gòu)型和行為型。
設(shè)計(jì)模式分為三種類型:
(1)創(chuàng)建型模式5種:?jiǎn)卫J?,抽象工廠模式,工廠模式,原型模式,建造者模式。
(口訣:?jiǎn)卧ㄔ煺?,東西二廠)
(2)結(jié)構(gòu)型模式7種:適配器模式,橋接模式,裝飾模式,組合模式,外觀模式,享元模式,代理模式。
(口訣:一器一橋一元一代理;裝飾組合外觀)
(3)行為型模式11種:觀察者模式,中介者模式,訪問者模式,解釋器模式,迭代器模式,備忘錄模式,責(zé)任鏈模式,狀態(tài)模式,策略模式,命令模式,模板模式。
(口訣:三者兩器、一錄一鏈一模板,狀態(tài)策略命令)
二、7大設(shè)計(jì)原則
1、開閉原則(Open Closed Principle)
對(duì)類的擴(kuò)展是開放,對(duì)修改關(guān)閉。
在程序需要擴(kuò)展的時(shí)候,對(duì)于一個(gè)類,不要去修改原來的代碼,而是通過繼承的方式去擴(kuò)展這個(gè)類。
目的:降低維護(hù)風(fēng)險(xiǎn)
2、單一職責(zé)原則(Single Responsiblity Principle)
每個(gè)類應(yīng)該且只有一個(gè)職責(zé)。
目的:提高可讀性
3、里式替換原則(Liskov Substitution Principle)
子類繼承父類時(shí),可以實(shí)現(xiàn)父類的抽象方法,不要 重寫 父類的方法,子類增加自己特有的方法。
目的:防止繼承帶來的問題
4、依賴倒置原則(Dependency Inversion Principle)
程序要依賴于抽象接口,不要依賴于具體實(shí)現(xiàn),針對(duì)接口編程。
目的:利于代碼升級(jí)
5、接口隔離原則(Interface Segregation Principle)
龐大的接口拆分成更小的和更具體的接口,一個(gè)接口只用于一個(gè)業(yè)務(wù)邏輯。
目的:使功能解耦,高內(nèi)聚、低耦合
6、迪米特原則(Principle of Least Knowledge)
一個(gè)對(duì)象應(yīng)當(dāng)對(duì) 其他 對(duì)象盡可能少的了解。
目的:自己做自己的事情
7、合成復(fù)用原則(Composite Reuse Principle)
使用對(duì)象組合,而不是繼承來達(dá)到復(fù)用的目的。
繼承破壞了封裝性,父類的任何改變,都可能導(dǎo)致子類出問題。
優(yōu)先考慮 合成復(fù)用,A類和B類的合成使用,而不是B繼承A的使用。
目的:少用繼承 降低耦合
三、 Android 中的23種設(shè)計(jì)模式
(1)單例模式:
簡(jiǎn)介:保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。
示例:Android中的系統(tǒng)級(jí)服務(wù)都是通過容器的單例模式實(shí)現(xiàn)方式,以單例形式存在,減少了資源消耗。
比如LayoutInflater Service,將這些服務(wù)以鍵值對(duì)的形式存儲(chǔ)在一個(gè)HashMap容器中,用戶使用時(shí)只需要根據(jù)key來獲取到對(duì)應(yīng)的ServiceFetcher,然后通過ServcieFetcher對(duì)象的getService函數(shù)來獲取到具體的服務(wù)對(duì)象,第一次獲取時(shí)會(huì)調(diào)用ServcieFetcher的createService函數(shù)創(chuàng)建服務(wù)對(duì)象,然后將該對(duì)象緩存到一個(gè)列表中,下次再取時(shí)直接從緩存中獲取,避免重復(fù)創(chuàng)建對(duì)象,從而達(dá)到單例的效果。
(2)抽象工廠模式:
簡(jiǎn)介:提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無需指定它們具體的類。
示例:Android底層對(duì)MediaPlayer的創(chuàng)建。
MediaPlayerFactory是Android底層為了創(chuàng)建不同的MediaPlayer所定義的一個(gè)類。
(3)工廠模式:
簡(jiǎn)介:定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定將哪一個(gè)類實(shí)例化。
示例:BitmapFactory位圖工廠,專門用來將指定的圖片轉(zhuǎn)換為指定的位圖Bitmap。
(4)原型模式:
簡(jiǎn)介:用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并且通過拷貝這個(gè)原型來創(chuàng)建新的對(duì)象。
示例:比如我們需要一張Bitmap的幾種不同格式:ARGB_8888、RGB_565、ARGB_4444、ALAPHA_8等。那我們就可以先創(chuàng)建一個(gè)ARGB_8888的Bitmap作為原型,在它的基礎(chǔ)上,通過調(diào)用Bitmap.copy(Config)來創(chuàng)建出其它幾種格式的Bitmap。另外一個(gè)例子就是Java中所有對(duì)象都有的一個(gè)名字叫clone的方法,已經(jīng)原型模式的代名詞了。在系統(tǒng)中要?jiǎng)?chuàng)建大量的對(duì)象,這些對(duì)象之間具有幾乎完全相同的功能,只是在細(xì)節(jié)上有一點(diǎn)兒差別。
(5)建造者模式:
簡(jiǎn)介:將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
示例:AlertDialog.Builder ImageLoader的初始配置。
(6)適配器模式:
簡(jiǎn)介:將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口。
示例:不同的數(shù)據(jù)提供者使用一個(gè)適配器來向一個(gè)相同的客戶提供服務(wù)。
ListView或GridView的Adapter。
(7)橋接模式:
簡(jiǎn)介:將抽象部分與它的實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地變化。
示例:Window和WindowManager之間的關(guān)系。
在FrameWork中Window和PhoneWindow構(gòu)成窗口的抽象部分,其中Window類為該抽象部分的抽象接口,PhoneWindow為抽象部分具體的實(shí)現(xiàn)及擴(kuò)展。而WindowManager則為實(shí)現(xiàn)部分的基類,WindowManagerImpl則為實(shí)現(xiàn)部分具體的邏輯實(shí)現(xiàn)。
(8)裝飾模式:
簡(jiǎn)介:動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就擴(kuò)展功能而言, 它比生成子類方式更為靈活。
示例:Activity繼承自ContextThemeWrapper,ContextThemeWrapper繼承自ContextWrapper,ContextWrapper才是繼承自Context。ContextWrapper就是我們找的裝飾者。
(9)組合模式:
簡(jiǎn)介:將對(duì)象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。
示例:View和ViewGroup的組合
(10)外觀模式
簡(jiǎn)介:為子系統(tǒng)中的一組接口提供一個(gè)一致的界面,F(xiàn)acade模式定義了一個(gè)高層接口,統(tǒng)一編程接口。
示例:ContextImpl
(11)享元模式:
簡(jiǎn)介:運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對(duì)象。
示例:Message.obtainMessage通過重用Message對(duì)象來避免大量的Message對(duì)象被頻繁的創(chuàng)建和銷毀。
(12)代理模式:
簡(jiǎn)介:為其他對(duì)象提供一個(gè)代理以控制對(duì)這個(gè)對(duì)象的訪問。
示例:所有的AIDL都一個(gè)代理模式的例子。假設(shè)一個(gè)Activity A去綁定一個(gè)Service S,那么A調(diào)用S中的每一個(gè)方法其實(shí)都是通過系統(tǒng)的Binder機(jī)制的中轉(zhuǎn),然后調(diào)用S中的對(duì)應(yīng)方法來做到的。Binder機(jī)制就起到了代理的作用。
(13)觀察者模式:
簡(jiǎn)介:一個(gè)對(duì)象發(fā)生改變時(shí),所有信賴于它的對(duì)象自動(dòng)做相應(yīng)改變。
示例:我們可以通過BaseAdapter.registerDataSetObserver和BaseAdapter.unregisterDataSetObserver兩方法來向BaseAdater注冊(cè)、注銷一個(gè)DataSetObserver。這個(gè)過程中,DataSetObserver就是一個(gè)觀察者,它一旦發(fā)現(xiàn)BaseAdapter內(nèi)部數(shù)據(jù)有變量,就會(huì)通過回調(diào)方法DataSetObserver.onChanged和DataSetObserver.onInvalidated來通知DataSetObserver的實(shí)現(xiàn)類。事件通知也是觀察者模式。
(14)中介者模式:
簡(jiǎn)介:用一個(gè)中介對(duì)象來封裝一系列的對(duì)象交互。中介者使各對(duì)象不需要顯式地相互引用,從而使其耦合松散,而且可以獨(dú)立地改變它們之間的交互。
示例:Binder機(jī)制。
(15) 訪問者模式:
簡(jiǎn)介:表示一個(gè)作用于某對(duì)象結(jié)構(gòu)中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。
示例:編譯時(shí)注解中的ElementVisitor中定義多個(gè)Visit接口,每個(gè)接口處理一種數(shù)據(jù)類型,這就是典型的訪問者模式,訪問者模式正好解決了數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)操作分離的問題,避免某些操作污染了數(shù)據(jù)對(duì)象類。
(16) 解釋器模式:
簡(jiǎn)介:給定一個(gè)語言,定義它的文法的一種表示,并定義一個(gè)解釋器,這個(gè)解釋器使用該表示來解釋語言中的句子。
示例:PackageParser這個(gè)類對(duì)AndroidManifest.xml這個(gè)配置文件的解析過程,
(17)迭代器模式
簡(jiǎn)介:提供一種方法順序訪問一個(gè)聚合對(duì)象中各個(gè)元素, 而又不需暴露該對(duì)象的內(nèi)部表示。
示例:在Android中除了各種數(shù)據(jù)結(jié)構(gòu)體,如List,Map,等包含的迭代器以外,Android源碼中也提供了迭代器遍歷模式,比如數(shù)據(jù)庫查詢使用Cursor,當(dāng)我們使用SQLiteDataBase的query方法查詢數(shù)據(jù)庫時(shí),會(huì)返回一個(gè)Cursor游標(biāo)對(duì)象,該游標(biāo)對(duì)象實(shí)際上就是一個(gè)具體的迭代器。
(18)備忘錄模式
簡(jiǎn)介:不需要了解對(duì)象的內(nèi)部結(jié)構(gòu)的情況下備份對(duì)象的狀態(tài),方便以后恢復(fù)。
示例:Activity的onSaveInstanceState和onRestoreInstanceState就是通過Bundle這種序列化的數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)Activity的狀態(tài),至于其中存儲(chǔ)的數(shù)據(jù)結(jié)構(gòu),這兩個(gè)方法不用關(guān)心。
(19)責(zé)任鏈模式
簡(jiǎn)介:有多個(gè)的對(duì)象可以處理一個(gè)請(qǐng)求,哪個(gè)對(duì)象處理該請(qǐng)求運(yùn)行時(shí)刻自動(dòng)確定。
示例: 責(zé)任鏈模式在Android源碼中比較類似的實(shí)現(xiàn)莫過于對(duì)事件的分發(fā)處理,每當(dāng)用戶接觸屏幕時(shí)候,Android都會(huì)將對(duì)應(yīng)的事件包裝成一個(gè)事件對(duì)象從ViewTree的頂部至上而下的分發(fā)傳遞。ViewGroup事件投遞的遞歸調(diào)用就類似一條責(zé)任鏈,一旦尋找到責(zé)任者,那么就由責(zé)任者持有并消費(fèi)該次事件,具體的體現(xiàn)在View的onTouchEvent方法中的返回值,如果OnTouchEvent返回false,那么意味著當(dāng)前View不會(huì)是該次事件的責(zé)任人,將不會(huì)對(duì)該事件持有。
(20)狀態(tài)模式:
簡(jiǎn)介:狀態(tài)發(fā)生改變時(shí),行為改變。
示例:View.onVisibilityChanged方法,就是提供了一個(gè)狀態(tài)模式的實(shí)現(xiàn),允許在View的visibility發(fā)生改變時(shí),引發(fā)執(zhí)行onVisibilityChanged方法中的動(dòng)作。
(21)策略模式
簡(jiǎn)介:定義了一系列封裝了算法、行為的對(duì)象,他們可以相互替換。
示例:Java.util.List就是定義了一個(gè)增(add)、刪(remove)、改(set)、查(indexOf)策略,至于實(shí)現(xiàn)這個(gè)策略的ArrayList、LinkedList等類,只是在具體實(shí)現(xiàn)時(shí)采用了不同的算法。但因?yàn)樗鼈儾呗砸粯樱豢紤]速度的情況下,使用時(shí)完全可以互相替換使用。
(22)命令模式
簡(jiǎn)介:把請(qǐng)求封裝成一個(gè)對(duì)象發(fā)送出去,方便定制、排隊(duì)、取消。
示例:Handler.post后Handler.handleMessage。
(23)模板模式
簡(jiǎn)介:定義一個(gè)操作中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
示例:android日常開發(fā)中的大量模版代碼