本著不學習就要落後,落後就要捱打的態度,我也開始搗鼓起了設計模式。但只看設計模式又不免有些索然無味,索性就連Android原始碼也一起研究研究,現在看來效果不錯。昨天晚上剛看了裝飾者模式,正好今天總結一番分享給大家。新手上路,如有不足之處,還請大家多指教。
裝飾者模式
Decorator模式(別名Wrapper):動態將職責附加到物件上,若要擴充套件功能,裝飾者提供了比繼承更具彈性的代替方案。
遵循的設計原則
- 多用組合,少用繼承。利用繼承設計子類的行為,是在編譯時靜態決定的,而且所有的子類都會繼承到相同的行為。然而,如果能夠利用組合的做法擴充套件物件的行為,就可以在執行時動態地進行擴充套件。
- 類應設計的對擴充套件開放,對修改關閉。
實現
裝飾者的UML圖大概如下
在裝飾模式結構圖中包含如下幾個角色:
- Component(抽象構件):它是具體構件和抽象裝飾類的共同父類,宣告瞭在具體構件中實現的業務方法,它的引入可以使客戶端以一致的方式處理未被裝飾的物件以及裝飾之後的物件,實現客戶端的透明操作。
- Concrete Component(具體構件):它是抽象構件類的子類,用於定義具體的構件物件,實現了在抽象構件中宣告的方法,裝飾器可以給它增加額外的職責(方法)。
- Decorator(抽象裝飾類):它也是抽象構件類的子類,抽象裝飾類不一定是抽象方法。用於給具體構件增加職責,但是具體職責在其子類中實現。它維護一個指向抽象構件物件的引用,通過該引用可以呼叫裝飾之前構件物件的方法,並通過其子類擴充套件該方法,以達到裝飾的目的。
- Concrete Decorator(具體裝飾類):它是抽象裝飾類的子類,負責向構件新增新的職責。每一個具體裝飾類都定義了一些新的行為,它可以呼叫在抽象裝飾類中定義的方法,並可以增加新的方法用以擴充物件的行為。
接下來我們對應UML圖實現就好。
我們先定義一個Component,可以是介面也可以是抽象類:
1 2 3 4 |
public interface Component { void operation(); } |
接下來是Concrete Component:
1 2 3 4 5 6 7 |
public class ConcreteComponent implements Component { public void operation() { // Write your code here } } |
然後是Decorator:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class Decorator implements Component { private Component component; public Decorator(Component component) { this.component = component; } public void operation() { component.operation(); } } |
最後是Concrete Decorator:
在Concrete Component的行為之前或之後,加上自己的行為,以“貼上”附加的職責。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class ConcreteDecorator extends Decorator { public void operation() { //addBehavior也可以在前面 super.operation(); addBehavior(); } private void addBehavior() { //your code } } |
優點
- Decorator模式與繼承關係的目的都是要擴充套件物件的功能,但是Decorator可以提供比繼承更多的靈活性。
- 通過使用不同的具體裝飾類以及這些裝飾類的排列組合,設計師可以創造出很多不同行為的組合。
Context類簇中裝飾者模式的實現
有句話叫“沒吃過豬肉,還沒見過豬跑麼?”。我們可能沒有自己在程式碼中應用過裝飾者模式,但是我們一定見過(可能當時不認識)。比如java中的I/O庫,以及Android中的Context的設計等等。接下來我們看看Context是如何組織的。
uml圖
中間省略了部分類,比如ContextWrapper的實現類裡邊還有MutableContextWrapper、BackupAgent類等,感興趣的朋友可以自己研究一下。
Context類
/**
* Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities,broadcasting and receiving intents, etc.
*/
註釋的意思大概是這樣的:這是一個由Android系統提供其實現的抽象類,它是提供應用環境(application environment)資訊的介面。通過它可以訪問到應用的資源和類,以及進行一些系統級別的操作,比如載入activity、傳送廣播和接收intent等。
粗略瀏覽一下里邊的屬性和方法,我們還可以看到一些熟悉的東西,比如getSharedPreferences(String name, int mode),以及mode引數的幾種可選值;再比如getColor(@ColorRes int id)、getDrawable(@DrawableRes int id)等獲取系統資源的方法等等。可以這樣說,Content類是application的管家,它有權管理application的大部分資源。
這個類對應裝飾者模式中的Component。
Context的實現類
ContextImpl類
/**Common implementation of Context API, which provides the base context object for Activity and other application components.
*/
ContextImpl是Context抽象類的一個直接子類,有一個私有的構造方法,是Context的具體實現類。原始碼位於android.app包中,但它在API文件中找不到,是一個預設訪問許可權的類,也就是說它只允許android.app包中的類可以呼叫它,或者只有和它同包的類才可以通過其父類的方法使用它。它為Activity、Service等應用元件提供基本的context物件。
這個類對應裝飾者模式中的Concrete Component。
ContextWrapper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/** * Proxying implementation of Context that simply delegates all of its calls to * another Context. Can be subclassed to modify behavior without changing * the original Context. */ public class ContextWrapper extends Context { Context mBase; public ContextWrapper(Context base) { mBase = base; } /** * Set the base context for this ContextWrapper. All calls will then be * delegated to the base context. Throws * IllegalStateException if a base context has already been set. * * @param base The new base context for this wrapper. */ protected void attachBaseContext(Context base) { if (mBase != null) { throw new IllegalStateException("Base context already set"); } mBase = base; } } |
註釋描述的很明顯:Context類的代理實現,ContextWrapper中實現Context的方法全是通過mBase來實現的。這樣它(ContextWrapper)派生出的子類就可以在不改變原始context(mBase)的情況下擴充套件Context的行為。
這個類對應裝飾者模式中的Decorator。
具體擴充套件
這裡我們就不做過多的分析了,我們簡單看下Activity的父類ContextThemeWrapper。
/**
* A context wrapper that allows you to modify or replace the theme of the wrapped context.
*/
註釋中說的很清楚,這個類擴充套件的功能就是允許我們去修改或者替換包裝的context的主題。
我們再來看看setTheme(int resid)方法。
1 2 3 4 5 6 7 |
@Override public void setTheme(int resid) { if (mThemeResource != resid) { mThemeResource = resid; initializeTheme(); } } |
這裡我們沒有呼叫父類的實現,而是自己處理了設定主題的邏輯。這樣我們就用組合的方式擴充套件了ContextImpl中的setTeme(int resid)方法。
這個類對應裝飾者模式中的Concrete Decorator。其他的Service和Application等都大同小異,只不過擴充套件了不同的行為。
參考連結:
http://blog.csdn.net/yanbober/article/details/45967639
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式