1. 程式人生 > >裝飾者模式及其應用

裝飾者模式及其應用

前幾天看了鴻洋大神的 Android 優雅的為RecyclerView新增HeaderView和FooterView,發現裝飾者模式 在某些情況下是設計得如此 優雅,現在總結如下:

本篇部落格主要講解一下幾個問題

  1. 什麼 是裝飾者模式
  2. 怎樣實現裝飾者模式
  3. 裝飾者模式的優缺點
  4. 裝飾者模式在Android中的應用

什麼是裝飾者模式

應用場景

咖啡店裡咖啡中可以加不同的配料–摩卡、牛奶、糖、奶泡;不同的飲品加上不同的配料有不同的價錢,怎樣實現呢?

可能你的第一印象會想到使用繼承,
1. 首先定義一個咖啡基類
2. 對於加糖的,加牛奶的,加摩卡的 ,加奶泡的,分別寫一個子類繼承
3. 對於加糖,又加奶的寫一個類,對於對於加糖,又摩卡的寫一個類,對於對於加糖、又奶泡的寫一個類,對於加糖,又加奶、摩卡的寫一個類—-
說到這裡,你會發現這裡四種配料就要寫十幾種實現類了,那如果我們的配料是二十幾種或者三十幾種呢,那麼使用繼承這種 方式肯定會使我們的子類爆炸,那要怎樣解決你,答案就是使用裝飾者模式

定義

我覺得裝飾者模式是在已有功能的基礎之上,動態地新增更多 功能的一種方式,這些新加的程式碼裝飾了原有類的 核心職責或主要行為。

類UML圖

效果圖

怎樣實現裝飾者模式呢?

首先我們先來看一下我們的設計類圖

  • 1) 首先我們定義一個Coffce基類
/**
 * @ explain:這裡Coffee相當於我們的Component,
 * 是要裝飾的類
 *
 * @ author:xujun on 2016/7/10 23:16
 * @ email:[email protected]
 */
public abstract class Coffee
{
/** * * @return 返回價格 */ public abstract int getPrice(); /** * 返回名字 * @return */ public abstract String getName(); }
  • 2) 接著 我們定義一個Decorator類繼承 我們的Coffice基類

/**
 * @ explain:
 * @ author:xujun on 2016/7/10 23:21
 * @ email:[email protected]
 */
public
abstract class Decorator extends Coffee{ protected Coffee mCoffee; /** * 通過組合的方式把Coffee物件傳遞進來 * @param coffee */ public Decorator(Coffee coffee){ mCoffee=coffee; } }
  • 3)接下來我們來看我們的子類是怎樣實現的
public class MilkDecorator extends Decorator {

    /**
     * 通過組合的方式把Coffee物件傳遞進來
     *
     * @param coffee
     */
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public int getPrice() {
        return mCoffee.getPrice()+10;
    }

    @Override
    public String getName() {
        return "addMilk";
    }
}

其實核心程式碼就下面一行,在原來的價格加上 加牛奶的價格

return mCoffee.getPrice()+10
  • 4)接下來不難想象加糖,就奶泡。就摩卡的操作,都是在原來的之上加上配料的價格
return mCoffee.getPrice()+2;
return mCoffee.getPrice()+15;
return mCoffee.getPrice()+20;

總結

以後你想要計算加糖,就牛奶,加奶泡的咖啡的價格,只需要這樣

mCoffee = new SimpleCoffee();
mCoffee = new SugarDecorator(mCoffee);
mCoffee = new MilkDecorator(mCoffee);
mCoffee = new MilkFoamDecorator(mCoffee);
int price1 = mCoffee.getPrice();
System.out.println("price1="+price1);

以後你想要計算加糖,就牛奶咖啡的價格,只需要這樣

mCoffee = new SimpleCoffee();
mCoffee = new SugarDecorator(mCoffee);
mCoffee = new MilkDecorator(mCoffee);

int price1 = mCoffee.getPrice();
System.out.println("price1="+price1);

裝飾者模式的優缺點

優點

  • 把類中的裝飾功能從類中搬除,可以簡化原來的類
  • 可以把類的 核心職責和裝飾功能區分開來,結構清晰 明瞭並且可以去除相關類的重複的裝飾邏輯。

裝飾者模式在Android中的應用

效果圖

  • 下面我們來看一下我們是如何 優雅的為RecyclerView新增HeaderView和FooterView
/**
 * 部落格地址:http://blog.csdn.net/gdutxiaoxu
 * @author xujun
 * @time 2016/7/7 17:29.
 */
public class HeaderAndFooterWrapper<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static final int BASE_ITEM_TYPE_HEADER = 100000;
    private static final int BASE_ITEM_TYPE_FOOTER = 200000;

    private SparseArrayCompat<View> mHeaderViews = new SparseArrayCompat<>();
    private SparseArrayCompat<View> mFootViews = new SparseArrayCompat<>();

    private RecyclerView.Adapter mInnerAdapter;

    public HeaderAndFooterWrapper(RecyclerView.Adapter adapter) {
        mInnerAdapter = adapter;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (mHeaderViews.get(viewType) != null) {
            ViewHolder holder = ViewHolder.createViewHolder(parent.getContext(), mHeaderViews.get
                    (viewType));
            return holder;

        } else if (mFootViews.get(viewType) != null) {
            ViewHolder holder = ViewHolder.createViewHolder(parent.getContext(), mFootViews.get
                    (viewType));
            return holder;
        }
        return mInnerAdapter.onCreateViewHolder(parent, viewType);
    }

    @Override
    public int getItemViewType(int position) {
        if (isHeaderViewPos(position)) {
            return mHeaderViews.keyAt(position);
        } else if (isFooterViewPos(position)) {
            return mFootViews.keyAt(position - getHeadersCount() - getRealItemCount());
        }
        return mInnerAdapter.getItemViewType(position - getHeadersCount());
    }

    private int getRealItemCount() {
        return mInnerAdapter.getItemCount();
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (isHeaderViewPos(position)) {
            return;
        }
        if (isFooterViewPos(position)) {
            return;
        }
        mInnerAdapter.onBindViewHolder(holder, position - getHeadersCount());
    }

    @Override
    public int getItemCount() {
        return getHeadersCount() + getFootersCount() + getRealItemCount();
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        WrapperUtils.onAttachedToRecyclerView(mInnerAdapter, recyclerView, new WrapperUtils
                .SpanSizeCallback() {
            @Override
            public int getSpanSize(GridLayoutManager layoutManager, GridLayoutManager
                    .SpanSizeLookup oldLookup, int position) {
                int viewType = getItemViewType(position);
                if (mHeaderViews.get(viewType) != null) {
                    return layoutManager.getSpanCount();
                } else if (mFootViews.get(viewType) != null) {
                    return layoutManager.getSpanCount();
                }
                if (oldLookup != null)
                    return oldLookup.getSpanSize(position);
                return 1;
            }
        });
    }

    @Override
    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
        mInnerAdapter.onViewAttachedToWindow(holder);
        int position = holder.getLayoutPosition();
        if (isHeaderViewPos(position) || isFooterViewPos(position)) {
            WrapperUtils.setFullSpan(holder);
        }
    }

    private boolean isHeaderViewPos(int position) {
        return position < getHeadersCount();
    }

    private boolean isFooterViewPos(int position) {
        return position >= getHeadersCount() + getRealItemCount();
    }

    public void addHeaderView(View view) {
        mHeaderViews.put(mHeaderViews.size() + BASE_ITEM_TYPE_HEADER, view);
    }

    public void addFootView(View view) {
        mFootViews.put(mFootViews.size() + BASE_ITEM_TYPE_FOOTER, view);
    }

    public int getHeadersCount() {
        return mHeaderViews.size();
    }

    public int getFootersCount() {
        return mFootViews.size();
    }

}
  • 接著我們來看一下我們是如何使用它的?
mAdapter = new SinglePersonAdapter(this, mDatas, R.layout.main_chat_from_msg);
mHeaderAndFooterWrapper=new HeaderAndFooterWrapper(mAdapter);

TextView t1 = new TextView(this);
t1.setPadding(10,10,10,10);
t1.setBackgroundColor(Color.GRAY);
t1.setText("Header 1");
TextView t2 = new TextView(this);
t2.setText("Header 2");
t2.setPadding(10,10,10,10);
t2.setBackgroundColor(Color.GRAY);
mHeaderAndFooterWrapper.addHeaderView(t1);
mHeaderAndFooterWrapper.addHeaderView(t2);
mRecyclerView.setAdapter(mHeaderAndFooterWrapper);

是不是很簡單,只需要簡單的幾行程式碼,就能在原有Adapter的基礎之上新增headerView或者Foot而View,具體的程式碼分析請見鴻洋大神的 部落格Android 優雅的為RecyclerView新增HeaderView和FooterView

相關推薦

最後的最後,賣一下廣告,歡迎大家關注我的微信公眾號,掃一掃下方二維碼或搜尋微訊號 stormjun,即可關注。 目前專注於 Android 開發,主要分享 Android開發相關知識和一些相關的優秀文章,包括個人總結,職場經驗等。

相關推薦

裝飾模式及其應用

前幾天看了鴻洋大神的 Android 優雅的為RecyclerView新增HeaderView和FooterView,發現裝飾者模式 在某些情況下是設計得如此 優雅,現在總結如下: 本篇部落格主要講解一下幾個問題 什麼 是裝飾者模式 怎樣實現裝飾者模式

設計模式裝飾模式介紹及程式碼示例 && JDK裡關於裝飾模式應用

# 0、背景 來看一個專案需求:咖啡訂購專案。 咖啡種類有很多:美式、摩卡、義大利濃咖啡; 咖啡加料:牛奶、豆漿、可可。 要求是,擴充套件新的咖啡種類的時候,能夠方便維護,不同種類的咖啡需要快速**計算多少錢**,客戶單點咖啡,也可以咖啡+料。 ### 最差方案 直接想,就是一個咖啡基類,然

System.Web.Abstractions中的裝飾模式及其在Asp.net Mvc中的應用

Wrapper模式的實現 作為.net framework 3.5 sp1 新新增的一個程式集,System.Web.Abstractions裡所有的類,都是Wrapper/Decorator模式的。(System.Web.Abstractions裡的類可以參見後面的附錄,System.Web.Abstra

結構型:裝飾模式及相關應用

文章目錄 裝飾者(Decorator) 優缺點 應用場景 Java I/O中的應用 Spring中的應用 MyBatis中的應用 參考資料 裝飾者(Decorator) 在不

PHP進階5 裝飾模式在Laravel中中介軟體的應用

                    不積跬步無以至千里不積小流無以成江海 裝飾者模式是在開放-關閉原則下實現動態新增或者減少功能的一種方式,類似於洋蔥,分很多層,每一層都有一定的功能,可以

RecyclerView中裝飾模式應用

近段時間一直在加班,在趕一個專案,現在專案接近尾聲,那麼需要對過去一段時間工作內容進行復盤,總結下比較好的解決方案,積累一些經驗,我認為的學習方式,是「理論—實踐—總結—分享」,這一種很好的沉澱方式。 在之前專案中,有個需求是這樣的,要顯示書的閱讀足跡列表,具體要求是顯示最近30天閱讀情況,佈局是用列表項佈局

設計模式 | 裝飾模式及典型應用

前言 本文的主要內容: 介紹裝飾者模式 示例 原始碼分析裝飾者模式的典型應用 Java I/O 中的裝飾者模式 spring session 中的裝飾者模式 Mybatis 快取中的裝飾者模式 總結 裝飾者模式 裝飾者模式(Decorator Patt

javaIO(1):OutputStream和FileOutputStream原始碼分析及“裝飾模式”在IO中的應用

前言 一,IO體系 從現在起,我們將基於JDK1.8詳細介紹java.io包中的關於輸入輸出有關的類。瞭解過這個包的都知道,裡面的類繼承關係錯綜複雜,光是弄清楚這些類的關係就夠喝一壺的了。說實話,我也沒有什麼好的方法來一下子就能弄清這些類,但是如果你瞭解“裝

設計模式--裝飾模式(在IO體系中的應用

上一篇介紹了介面卡模式,它是將一個類的介面,轉化成客戶期望的另一個介面,介面卡讓原本介面不相容的類可以合作無間。裝飾者模式:動態的將責任附加到物件上(因為利用組合而不是繼承來實現,而組合是可以在執行時進行隨機組合的)用來擴充套件功能。若要擴充套件功能,裝飾者提供

裝飾模式

優先 方式 由於 排列組合 tps 接收 class 巧克力 不同 轉載請註明出處!!。http://blog.csdn.net/zhonghuan1992 全部配套代碼均在github上:https://github.com/ZHONGHuanGit

Java設計模式裝飾模式

解決 over 裝飾者模式 pack img 應該 ora 我們 lan 目錄      一、問題引入  二、設計原則  三、用裝飾者模式解決問題  四、裝飾者模式的特點  五、裝飾者模式的定義  六、裝飾者模式的實現  七、java.io包內的裝飾者模式

設計模式裝飾模式

一點 ron 測試類 實現類 stub generated class void nbsp 一.裝飾者模式特點:1.裝飾者和被裝飾者對象有相同的超類2.可以用一個或多個裝飾者包裝一個對象3.由於裝飾者和被裝飾者具有相同超類,所以任何需要被包裝對象的場合,可以用裝飾過的對象代

過濾器 & 裝飾模式

自動 設計模式 加載 null type nbsp list 正文 多個 一.過濾器概述 ------------------------------------------------ 1.1.什麽是過濾器? Servlet技術規範中, 定義了S

觀察模式實際應用:監聽線程,意外退出線程後自動重啟

lee text 實時 之間 最終 ren tap instance and 摘要:  觀察者模式,定義對象之間的一種一對多的依賴關系,當對象的狀態發生改變時,所有依賴於它的對象都得到通知並且被自動更新。觀察者模式在JDK中有現成的實現,java.util.Obsera

7,裝飾模式(Decorator Pattern)動態的給一個對象添加一些額外的職責。就增加功能來說,此模式比生成子類更為靈活。繼承關系的一個替換方案。

做到 活性 splay .com 重新 裝飾 run play 情況 裝飾( Decorator )模式又叫做包裝模式。通過一種對客戶端透明的方式來擴展對象的功能,是繼承關系的一個替換方案。 裝飾模式就是把要添加的附加功能分別放在單獨的類中,並讓這個

設計模式(三)裝飾模式Decorator

不知道 operation 總結 界面 都是 per @override stat override   裝飾者模式針對的問題是:對一個結構已經確定的類,在不改變該類的結構的情況下,動態增加一些功能。   一般來說,都是對一些已經寫好的架構增加自己的功能,或者應對多種情況,

09.設計模式_裝飾模式

9.png 組件 復雜 2-2 就會 蘋果手機 apple pat 轉載 轉載自 http://www.cnblogs.com/zhili/p/DecoratorPattern.html 一、引言 在軟件開發中,我們經常想要對一類對象添加不同的功能,例如要給手機添加貼膜

【設計模式裝飾模式-明月裝飾了你的窗子

return rgs light 刪除 clas pan net public 不改變 裝飾者模式   使用裝飾者模式,可以動態的給一個對象添加一些額外的職責。這適用於,我們只希望給某個對象而不是整個類添加一些功能的場景。通過使用含有某個特定功能的類來“包裹”原始的類,提

裝飾模式的魅力

app lin err space system override using public sin 1 using System; 2 3 namespace ConsoleApplication2 4 { 5 class Program

headfirst設計模式(3)—裝飾模式

其中 拖延 穩定 放棄 等等 logs headfirst 自己的 定義 序 好久沒寫設計模式了,自從寫了兩篇之後,就放棄治療了,主要還是工作太忙了啊(借口,都是借口),過完年以後一直填坑,填了好幾個月,總算是穩定下來了,可以打打醬油了。 為什麽又重新開始寫設計模式呢?學習