Android 設計模式之裝飾模式

在平常開發過程當中時常須要用到設計模式,可是設計模式有23種,如何將這些設計模式瞭然於胸而且能在實際開發過程當中應用得駕輕就熟呢?和我一塊兒跟着《Android源碼設計模式解析與實戰》一書邊學邊應用吧!

設計模式系列文章

今天咱們要講的是裝飾模式(包裝模式)


定義

動態的給一個對象添加一些額外的職責。就增長功能來講,裝飾模式比生成子類更爲靈活設計模式

使用場景

  • 須要透明且動態地擴展類的功能時

使用例子

  • Android源碼中的ContextWrapper

實現

四大角色

  • 抽象組件:能夠是抽象類或接口,是被裝飾類的原始對象
  • 組件具體實現類:該類是抽象組件的具體實現,也是咱們裝飾的具體對象
  • 抽象裝飾者:爲了裝飾咱們的組件對象,其內部必定要有一個指向組件對象的引用。在大多數狀況下,該類爲抽象類,須要根據不一樣的裝飾邏輯實現不一樣的子類。若是裝飾邏輯單一,只有一個的狀況下咱們能夠省略該類直接做爲具體的裝飾者
  • 具體的裝飾者:對抽象裝飾作具體的實現

實現的要點

  • 要有具體的被裝飾對象
  • 根據須要建立抽象裝飾者
  • 不管是抽象裝飾者仍是具體的裝飾者,都會持有被裝飾組件的引用
  • 具體的裝飾者中確定須要有被裝飾組件的方法,並根據須要加以擴展

實現方式

首先先熟悉下裝飾模式的概念

public class DecoratorActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);        
        initData();        
        initView();        
    }
    
    private void initData() {
        //初始化數據
    }
    
    private void initView() {
        //初始化頁面
    }
}
複製代碼
  • 上面的代碼咱們應該比較熟悉,這就比較相似裝飾模式中裝飾者的職責,就是動態地擴展了類的功能

下面咱們以對在代理模式一文中的示例代碼進行改造來簡單應用裝飾模式

首先抽象主題類Notify類不變
public abstract class Notify {

    protected Context context;
    protected NotificationManager notificationManager;
    protected NotificationCompat.Builder builder;

    public Notify(Context context) {
        this.context = context;
        notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        builder = new NotificationCompat.Builder(context);
        builder.setSmallIcon(R.drawable.ic_launcher)
                .setContentIntent(PendingIntent.getActivity(context, 0,
                        new Intent(context, NotifyActivity.class),
                        PendingIntent.FLAG_UPDATE_CURRENT));
    }

    /**
     * 發送一條通知
     */
    public abstract void send();

    /**
     * 取消一條通知
     */
    public abstract void cancel();
}
複製代碼
被代理類(這裏是被裝飾類)NotifyNormal要稍微變更下
public class NotifyNormal extends Notify {

    public NotifyNormal(Context context) {
        super(context);
    }

    @Override
    public void send() {
        Notification notification = builder.build();
        notificationManager.notify(0, notification);
    }

    @Override
    public void cancel() {
        notificationManager.cancel(0);
    }
}
複製代碼

接下來是抽象裝飾者

public abstract class NotifyDecorator extends Notify {
    private Notify notify;

    public NotifyDecorator (Context context, Notify mNotify) {
        super(context);
        this.notify = mNotify;
    }

    @Override
    public void send() {
        notify.send();
    }

    @Override
    public void cancel() {
        notify.cancel();
    }
}
複製代碼
  • 這裏NotifyDecorator持有了被裝飾組件Notify的引用,而且包含Notify的send方法和cancel方法
具體的裝飾者,原來分別有NotifyNormal、NotifyBig、NotifyHeadersUp,這裏對應三個具體的裝飾者
  • NotifyNormalDecorator
public class NotifyNormalDecorator extends NotifyDecorator {

    public NotifyNormalDecorator (Context context, Notify notify) {
        super(context, notify);
    }

    @Override
    public void send() {
        builder.setContent(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal));
        super.send();
    }
}
複製代碼
  • NotifyBigDecorator
public class NotifyBigDecorator extends NotifyDecorator {

    public NotifyBigDecorator(Context context, Notify notify) {
        super(context, notify);
    }

    @Override
    public void send() {
        builder.setContent(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal));
        builder.setCustomBigContentView(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal));
        super.send();
    }
}
複製代碼
  • NotifyHeadsUpDecorator
public class NotifyHeadsUpDecorator extends NotifyDecorator {

    public NotifyHeadsUpDecorator(Context context, Notify notify) {
        super(context, notify);
    }

    @Override
    public void send() {
        builder.setContent(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal));
        builder.setCustomBigContentView(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal));
        builder.setCustomHeadsUpContentView(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal));
        super.send();
    }
}
複製代碼
以上都是在被裝飾對象NotifyNormal的基礎上增長或更改了通知的佈局

代理類NotifyProxy也要相應的作修改

public class NotifyProxy extends Notify{
    private NotifyDecorator notifyDecorator;

    public NotifyProxy (Context context) {
        super(context);

        Notify notify = new NotifyNormal(context);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            notifyDecorator = new NotifyHeadsUpDecorator(context, notify);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            notifyDecorator = new NotifyBigDecorator(context, notify);
        } else {
            notifyDecorator = new NotifyNormalDecorator(context, notify);
        }
    }

    @Override
    public void send() {
        notifyDecorator.send();
    }

    @Override
    public void cancel() {
        notifyDecorator.cancel();
    }
}

複製代碼

調用的入口依然沒變

new NotifyProxy(MainActivity.this).send();
複製代碼

總結

  • 從上面咱們對代理模式中的示例代碼進行改造的過程咱們能夠看出,裝飾模式主要在於擴展了類的功能。
  • 裝飾模式經過在被裝飾組件的方法執行以前或以後加入新的方法來實現功能的擴展
裝飾模式和代理模式的區別
  • 裝飾模式是對客戶端以透明的方式擴展對象的功能,是繼承關係的一種替代;而代理模式則是給一個對象提供一個代理對象,並由代理對象來控制對原有對象的引用
  • 裝飾模式應該爲所裝飾的對象增長功能,而代理對象對所代理的對象施加控制,但不對對象自己的功能進行加強

歡迎關注個人微信公衆號,期待與你一塊兒學習,一塊兒交流,一塊兒成長! bash

AntDream
相關文章
相關標籤/搜索