《Android源碼設計模式解析與實戰》讀書筆記(二十一)
第二十一章、裝飾模式
裝飾模式也稱為封裝模式,是結構型設計模式之一。裝飾模式是一種用於替代繼承技術的一種方案。
1.定義
動態給一個對象添加一些額外的職責。就增加功能來說,裝飾模式相比產生子類更為靈活。
2.使用情境
(1)需要透明且動態地擴充類的功能時。且在不影響其他對象的情況下。
(2)當不能採用繼承對系統進行擴充時可以使用裝飾模式。比如final類。
3.UML類圖
(1)Component:抽象組件。可以是一個介面或抽象類別,其充當的就是被裝飾的原始對象。
(2)ConcreteComponent:組件具體實作類別,該類是Component類的基本實現,也是我們裝飾的具體對象。
(3)Decorator:抽象裝飾者,其職責就是裝飾我們的組件對象,通過其子類擴充該方法以達到裝飾的目的。其內部一定要有一個指向組件對象的引用。在大多數情況下,該類為抽象類別,需要根據不同的裝飾邏輯實現不同的具體子類。
(4)ConcreteDecoratorA、ConcreteDecoratorB:裝飾著具體實作類別。負責向構件添加新的職責。
4.簡單實現
以一個男孩穿衣裝扮為例。實現給男孩在家與出門的穿衣裝扮。
抽象組件類(Component):
public abstract class Person { /** * Person下有一個穿著的抽象方法 */ public abstract void dressed();}
具體實作類別(ConcreteComponent):表示要裝扮的Boy
public class Boy extends Person{ @Override public void dressed() { System.out.println("Boy穿了內衣內褲"); }}
抽象裝飾類(Decorator):PersonCloth 表示人所穿著的衣服
public class PersonCloth extends Person{ protected Person mPerson; //保持一個Person類的引用 public PersonCloth(Person mPerson) { super(); this.mPerson = mPerson; } @Override public void dressed() { mPerson.dressed(); }}
出門穿的衣服:
public class OutsideCloth extends PersonCloth{ public OutsideCloth(Person mPerson) { super(mPerson); } /** * 穿短袖 */ private void dressShirt(){ System.out.println("穿件短袖"); } /** * 穿牛仔褲 */ private void dressJean(){ System.out.println("穿牛仔褲"); } /** * 穿鞋子 */ private void dressShoes(){ System.out.println("穿鞋子 "); } @Override public void dressed() { super.dressed(); dressShirt(); dressJean(); dressShoes(); }}
在家穿的衣服:
public class HomeCloth extends PersonCloth{ public HomeCloth(Person mPerson) { super(mPerson); } /** * 穿短褲 */ private void dressShorts(){ System.out.println("穿短褲");//在家裡隨便點 } @Override public void dressed() { super.dressed(); dressShorts(); }}
裝扮:
public class Client { public static void main(String[] args) { //首先有一個男孩 Person person = new Boy(); //在家 PersonCloth personCloth = new HomeCloth(person); personCloth.dressed(); System.out.println("--------------"); //出門 PersonCloth personCloth1 = new OutsideCloth(person); personCloth1.dressed(); }}
結果
Boy穿了內衣內褲穿短褲--------------Boy穿了內衣內褲穿件短袖穿牛仔褲穿鞋子
5.Android源碼中的實現1.Context
Context類在Android中被稱為“上帝對象”,它的本質就是一個抽象類別,在裝飾模式中相當於抽象組件,而在內部定義了大量的抽象方法,比如我們經常用到的startActivity方法。而真正實現是在ContextImpl中完成,那麼ContextImpl 就是具體實作類別。因為ContextWrapper 繼承於Context ,所以ContextWrapper 就是裝飾者。具體大家可以自行查看源碼。
6.區別1.與代理模式的區別
(1)裝飾模式是以對用戶端透明的方式擴充項物件的功能,是繼承方案的一個替代;而代理模式則是給一個對象提供一個代理對象,並有代理對象來控制對原有對象的引用。
(2)裝飾模式應該為所裝飾的對象增強功能;代理模式是對代理對象施加控制,不對對象本身功能進行增強。
2.與適配器模式的區別
適配器模式是用新介面來調用原介面,原介面對新系統是不可見的;裝飾模式增強了其他對象的功能而同時又不改變它的介面。
7.總結
在實際開發中我們應該寫過如下代碼:其實這些新增方法的調用就類似裝飾模式中的裝飾者的職責,只不過這裡我們沒有保持對組件類的引用。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初始化資料 initData(); //初始化控制項 initViews(); //初始化事件 initEvent(); }
1.優點
(1)對於擴充一個對象的功能,裝飾模式比繼承更加靈活性,不會導致類的個數急劇增加。
(2)可以通過一種動態方式在運行時選擇不同的具體裝飾類,從而實現不同的行為。
(3)可以對一個對象進行多次裝飾,通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創造出很多不同行為的組合,得到功能更為強大的對象。
(4)具體構件類與具體裝飾類可以獨立變化,使用者可以根據需要增加新的具體構件類和具體裝飾類,原有類庫代碼無須改變,符合“開閉原則”。
2.缺點
(1)使用裝飾模式進行系統設計時將產生很多小對象,這些對象的區別在於它們之間相互串連的方式有所不同,而不是它們的類或者屬性值有所不同,大量小對象的產生勢必會佔用更多的系統資源,在一定程式上影響程式的效能。
(2)對於多次裝飾的對象,調試時尋找錯誤可能需要逐級排查,較為繁瑣。