Design Patterns in Android:裝飾模式

裝飾模式是幹嗎的呢?它在項目中有哪些用途呢?裝飾模式在Android源碼中有哪些應用呢?本文將和讀者朋友一塊兒分享探討裝飾者模式在Android中的應用和實踐。設計模式

本文原創做者MichaelX。 
CSDN博客:https://blog.csdn.net/xiong_it 
掘金主頁:https://juejin.im/user/56efe6461ea493005565dafd 
知乎專欄:https://zhuanlan.zhihu.com/c_144117654 
我的博客:http://blog.michaelx.tech 
複製代碼

轉載請註明出處。bash

裝飾模式定義

裝飾者模式:也叫wrapper模式。動態地給一個對象添加一些額外的職責,就增長功能來講,裝飾者模式相比生成子類更加靈活,提供了有別於繼承的另外一種選擇。app

裝飾模式的UML類圖

這裏寫圖片描述
有四個角色須要說明:

  • Component抽象構件 Component是一個接口或者是抽象類,就是定義咱們最核心的對象,也就是最原始的對象,如上面的成績單。

**注意:**在裝飾模式中,必然有一個最基本、最核心、最原始的接口或抽象類充當Component抽象構件。ide

  • ConcreteComponent 具體構件 ConcreteComponent是最核心、最原始、最基本的接口或抽象類的實現,你要裝飾的就是它。函數

  • Decorator裝飾角色 通常是一個抽象類,作什麼用呢?實現接口或者抽象方法,它裏面可不必定有抽象的方法呀,在它的屬性裏必然有一個private變量指向Component抽象構件。this

  • 具體裝飾角色 ConcreteDecoratorA和ConcreteDecoratorB是兩個具體的裝飾類,你要把你最核心的、最原始的、最基本的東西裝飾成其餘東西。spa

裝飾模式示例代碼

public abstract class Component {
     //抽象的方法
     public abstract void operate();
}
複製代碼
public class ConcreteComponent extends Component {
     //具體實現
     @Override
     public void operate() {
             System.out.println("do Something");
     }
}
複製代碼
public abstract class Decorator extends Component {
     private Component component = null;        
     //經過構造函數傳遞被修飾者
     public Decorator(Component _component){
             this.component = _component;
     }
     //委託給被修飾者執行
     @Override
     public void operate() {
             this.component.operate();
     }
}
複製代碼
public class ConcreteDecorator1 extends Decorator {
     //定義被修飾者
     public ConcreteDecorator1(Component _component){
             super(_component);
     }
     //定義本身的修飾方法
     private void method1(){
             System.out.println("method1 修飾");
     }
     //重寫父類的Operation方法
     public void operate(){
             this.method1();
             super.operate();
     }
}
複製代碼
public class ConcreteDecorator2 extends Decorator {
     //定義被修飾者
     public ConcreteDecorator2(Component _component){
             super(_component);
     }
     //定義本身的修飾方法
     private void method2(){
             System.out.println("method2修飾");
     }
     //重寫父類的Operation方法
     public void operate(){
             super.operate();
             this.method2();
     }
}
複製代碼

使用場景類.net

public class Client {
     public static void main(String[] args) {
             Component component = new ConcreteComponent();
             //第一次修飾
             component = new ConcreteDecorator1(component);
             //第二次修飾
             component = new ConcreteDecorator2(component);
             //修飾後運行
             component.operate();
     }
}
複製代碼

Android源碼中的裝飾模式

案例一

Context是Android中一個幾乎無處不在的角色,ContextWrapper/ContextThemeWrapper就在繼承過程當中承擔了ContextImpl的裝飾者角色。 設計

這裏寫圖片描述
ContextThemeWrapper部分代碼爲例:

public class ContextThemeWrapper extends ContextWrapper {
    private int mThemeResource;
    private Resources.Theme mTheme;
    private LayoutInflater mInflater;
    private Configuration mOverrideConfiguration;
    private Resources mResources;

    @Override
    public AssetManager getAssets() {
        // Ensure we're returning assets with the correct configuration. return getResourcesInternal().getAssets(); } @Override public Resources getResources() { return getResourcesInternal(); } private Resources getResourcesInternal() { if (mResources == null) { if (mOverrideConfiguration == null) { mResources = super.getResources(); } else { final Context resContext = createConfigurationContext(mOverrideConfiguration); mResources = resContext.getResources(); } } return mResources; } @Override public Resources.Theme getTheme() { if (mTheme != null) { return mTheme; } mThemeResource = Resources.selectDefaultTheme(mThemeResource, getApplicationInfo().targetSdkVersion); initializeTheme(); return mTheme; } @Override public Object getSystemService(String name) { if (LAYOUT_INFLATER_SERVICE.equals(name)) { if (mInflater == null) { mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this); } return mInflater; } return getBaseContext().getSystemService(name); } protected void onApplyThemeResource(Resources.Theme theme, int resId, boolean first) { theme.applyStyle(resId, true); } private void initializeTheme() { final boolean first = mTheme == null; if (first) { mTheme = getResources().newTheme(); final Resources.Theme theme = getBaseContext().getTheme(); if (theme != null) { mTheme.setTo(theme); } } onApplyThemeResource(mTheme, mThemeResource, first); } } 複製代碼

案例二

還有一個比較典型的例子是RecyclerView經過RecyclerView.ItemDecorator來擴展樣式。 不過這個是一個變種的裝飾者,這個實踐比較另類的地方在於:咱們一般是在裝飾者的的執行方法中擴展被代理對象的行爲,而RecyclerView+ItemDecorator的實踐則偏偏相反,ItemDecorator反倒成了被代理對象,RecyclerView成了裝飾者。3d

Android開發中的裝飾模式實踐

說實話,筆者本身也沒有實踐過裝飾模式,可是有一個場景需求應該是能夠應用裝飾模式的。好比一個直播場景,點擊禮物時須要禮物飛出來,雙擊有一個愛心❤️飄出來,那麼禮物和愛心就能夠當作是直播畫面的裝飾者,類關係以下:

這裏寫圖片描述
GirlView:主播畫面 GirlDecorator:主播畫面裝飾者 GiftView:禮物效果 LoveView:愛心效果

總結

特色:裝飾模式其實就是在代理某個對象過程當中,給特定的代理行爲先後加上不一樣的裝飾行爲,好比文中的ContextThemeWrapper就在代理ContextImplgetSystemService這個行爲過程當中,加上了返回LayoutInflater這個裝飾行爲。所以,咱們也能夠認爲裝飾模式實際上是一種特殊的代理模式

裝飾模式的優缺點 優勢:

  • 裝飾類和被裝飾類能夠獨立發展,而不會相互耦合。換句話說,Component類無須知道Decorator類,Decorator類是從外部來擴展Component類的功能,而Decorator也不用知道具體的構件。

  • 裝飾模式是繼承關係的一個替代方案。咱們看裝飾類Decorator,無論裝飾多少層,返回的對象仍是Component,實現的仍是is-a的關係。

  • 裝飾模式能夠動態地擴展一個實現類的功能,這不須要多說,裝飾模式的定義就是如此。

缺點:

  • 裝飾太多層時會增長系統複雜度,有時出現問題可能沒法快速定位。

當某個對象的行爲須要增強,而且可能有多種增強的需求時,那麼裝飾模式有可能就能排上用場了。

好了,今天的《設計模式Android篇:裝飾模式》就到這裏,請繼續關注《Design Patterns in Android》(設計模式Android篇)系列博文,歡迎各位讀者朋友評論區拍磚交流,共同進步。

相關文章
相關標籤/搜索