裝飾模式

簡介

裝飾模式也稱爲包裝模式,使用一種對客戶端透明的方式來動態擴展對象的功能,同時也是繼承關係的一種替代方案。日常生活中很多裝飾模式的例子,我們穿着衣服就是對我們自己的一種裝飾。

定義

動態地將責任附加到對象上。若要擴展功能,裝飾着提供比繼承更加有彈性的替代方案。

使用場景

  • 需要透明並且動態地擴張類的功能;
  • 當不能採用繼承的方式對系統擴展或者不採用繼承不利於系統擴展和維護時;

UML類圖


這裏寫圖片描述

  • Component:抽象構件
    接口或抽象類,被裝飾的原始對象。

  • ConcreteComponent:具體構件
    抽象構件的基本實現,是我們要裝飾的具體對象。

  • Decorator:抽象裝飾類
    我們的抽象裝飾類,用於給具體構件增加職責,但是具體的職責在它的子類中實現。

  • ConcreteDecorator:具體裝飾類
    抽象裝飾類的子類,負責向構件添加新的職責。

裝飾模式簡單實現

以人穿衣服爲實例demo來實現如下:
點擊查看

透明裝飾模式

我們看看客戶端的調用代碼:

public class Main {
    public static void main(String[] args){
        Person person,personWrap;
        person = new XiaoYe();
        personWrap = new PersonClothWrapper(person);
        personWrap.dress();
    }
}

我們具體類和要包裝的類都可以通過定義Person接口來進行訪問。客戶端可以完全針對接口抽象編程。這是透明裝飾模式的一種使用。

透明裝飾模式可以讓客戶透明的使用裝飾之前的對象和裝飾之後的對象,無需關心它們的區別,此外,還可以對一個已經裝飾過的對象多次裝飾,得到更加複雜的對象。

半透明裝飾模式

上面我們看了透明的方式來指定裝飾者和被裝飾者,現在如果我們想要客戶端調用裝飾者的額外添加的方法,使用上面那種方式是不能實現的,那麼客戶端在定義裝飾者的時候要爲具體的裝飾者對象了,這樣裝飾者纔可以調用額外添加的方法。
半透明裝飾模式可以給系統帶來更多的靈活性。但是缺點是不能對一個對象進行多次裝飾。(不知道爲啥)

Android中裝飾模式的使用

Context實現

我們看看我們常用的Context類的這個系統的源碼,它的整套設計就是一個裝飾模式,基本的類圖如下:


這裏寫圖片描述

仔細一看Context的設計模式真的完全遵循裝飾設計模式。

Context相關問題

我們在Activity中可以使用Context來做很多事情,對於Context我們有必要了解它的來龍去脈。

  • Activity的Context啥時候創建的,如何創建的?
    Activity的啓動流程我們這裏略過,看到ActivityThread的perfromLauncheActvity方法,從啓動一個Activity開始看Activity的Context是如何關聯上的。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        ...

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            ...
                appContext.setOuterContext(activity);
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);

                ...

        return activity;
    }

看幾個關鍵的代碼,通過createBaseContextForActivity創建Context對象,然後通過appContext.setOuterContext(activity);在Context裏面關聯Activity然後調用activity.attach方法傳入Context對象。

  • Application的Context啥時候創建,如何創建?
    就本地而言所有的這些操作都是從ActivityThread的內部的Handler H開始分發下來,看到handleBindApplication方法。
private void handleBindApplication(AppBindData data) {
        ...
        try {
            // If the app is being launched for full backup or restore, bring it up in
            // a restricted environment with the base application class.
            Application app = data.info.makeApplication(data.restrictedBackupMode, null);
            mInitialApplication = app;
           ...
    }

看到makeApplication方法裏面:

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }
        ...
        Application app = null;
        ...
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        ...
        mActivityThread.mAllApplications.add(app);
        mApplication = app;
        ...
        return app;
    }

通過ContextImpl創建Context,調用Context的setOuterContext關聯我們的Application,在創建Application的時候傳入appContext對象,我們的Application可以使用Context了。

  • Service 的Context也是一樣通過調用handleCreateService方法,使用上面的方式創建和綁定Context對象。
  • 應用中的Context數量?
    Application,Activity,Service一個實例都創建一個Context對象。其餘兩大組件沒有創建Context它們間接的使用Context。

總結

  • 裝飾模式優缺點

    • 優點:
      擴展一個對象的功能比繼承更加靈活,不會導致類的個數急劇增加;

      可以通過動態的方式來擴展一個對象的功能,可以在運行時選擇具體的裝飾類;

      可以對一個對象多次裝飾,可以有多種組合;
      具體的構件類與具體的裝飾類可以獨立變化,依據需求來增加模塊而不修改之前的;

    • 缺點:
      類數量增多,我們整了一些抽象構件,具體抽象對象,抽象裝飾類,具體裝飾類;

      對於多次裝飾的時候,排錯會更加困難;

  • 裝飾模式和代理模式對比

    代理模式中,代理類對被代理的對象有控制權,決定其執行或者不執行。而裝飾模式中,裝飾類對代理對象沒有控制權,只能爲其增加一層裝飾,以加強被裝飾對象的功能,僅此而已

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章