流行框架源碼分析(16)-Decorator裝飾模式

主目錄見:Android高級進(jìn)階知識(這是總目錄索引)
?今天要講裝飾模式其實跟之前的代理模式實現(xiàn)上有點(diǎn)相似,但是在使用上會有些不同滚朵,在我理解上呢冤灾,代理側(cè)重對被代理對象的功能修改,同時限制了其他類對被代理對象的訪問辕近。然而裝飾模式更側(cè)重被裝飾對象功能的嵌套增強(qiáng)且不限制其他類對被裝飾對象的訪問韵吨,為什么這么說呢?在等會要講的IO流你就知道移宅,為了增強(qiáng)功能归粉,IO流可以嵌套多層來增強(qiáng)功能而且可以單獨(dú)使用。這里我們首先看下裝飾模式的UML類圖,今天不畫漏峰,直接copy一張:

裝飾模式

角色介紹:

  • Component:抽象組件糠悼,可以是一個接口或抽象類,是被裝飾的原始對象;
  • ConcreteComponent:組件的具體實現(xiàn)類浅乔。是被裝飾的具體對象倔喂,就像上面英文說的這是我們要動態(tài)添加行為的類。
  • Decorator:抽象裝飾者靖苇,職責(zé)是裝飾被裝飾的對象席噩。內(nèi)部一定有一個對被裝飾者的引用。一般情況下也是一個抽象類顾复,根據(jù)具體邏輯實現(xiàn)不同的子類班挖。如果邏輯簡單可以直接是實現(xiàn)類鲁捏。
  • ConcreteDecorator:具體裝飾者類芯砸,裝飾者可以添加新的方法萧芙,而且能在原有的方法前面或者后面添加新的行為。

一.目標(biāo)

今天有一個目標(biāo)也是以前自己學(xué)IO流時候留下的問題假丧,因為以前學(xué)IO流的時候總感覺怎么這么多類嵌套來嵌套去双揪,感覺都用不起來。那么今天目標(biāo)就是:
1.從裝飾模式看IO流的使用包帚;
2.明白裝飾模式在什么場景下使用渔期。

二.模式講解

我們這里也來想象一個場景,比如你今天要去參加一個party渴邦,你挑了一件T恤疯趟,一條牛仔,一雙奧康皮鞋準(zhǔn)備出席谋梭。然后出門發(fā)現(xiàn)天氣挺冷信峻,所以進(jìn)門加了件毛衣,然后走到路上瓮床,發(fā)現(xiàn)大家穿著時髦盹舞,所以想了想,趕緊去店里買了個帽子隘庄,然后出席了party踢步。所以我們首先來看抽象組件角色:

public interface Component {
    void decorate();
}

然后我們看下我們具體的組件角色:

public class PersonComponent implements Component {

    @Override
    public void decorate() {
        System.out.println("我穿了一件T恤,一條牛仔丑掺,一雙奧康皮鞋");
    }
}

可以看到這個組件是可以獨(dú)立運(yùn)行的获印,已經(jīng)是完整的實現(xiàn)了。但是如果我們這是要增加他的功能呢吼鱼?我們接下來看抽象裝飾者角色:

public abstract class Decorator implements Component {
    private Component component;
    
     public Decorator(Component component) {
         this.component = component;
    }

    @Override
    public void decorate() {
        if (null != component) {
            component.decorate();
        }
    }
}

可以看到這個抽象裝飾者實現(xiàn)了Component蓬豁,并且持有了Component的一個引用。同時調(diào)用了組件的decorate()方法菇肃。然后我們分別看下兩個具體的裝飾類:

public class SweaterDecorator extends Decorator {

    public SweaterDecorator(Component component) {
        super(component);
    }

    @Override
    public void decorate() {
        super.decorate();
        System.out.println("加了件毛衣");
    }
}

還有一個是帽子的裝飾類:

public class HatDecorator extends Decorator {

    public HatDecorator(Component component) {
        super(component);
    }

    @Override
    public void decorate() {
        super.decorate();
        System.out.println("加個帽子");
    }
}

可以看到各個角色非常明顯地粪,然后我們看下使用:

Decorator hatDecorator = new HatDecorator(new SweaterDecorator(new PersonComponent()));
hatDecorator.decorate();

看到這里你是不是很自然地想起來I/O流的使用方法。那么我們就引出我們的I/O流的使用琐谤。

1.I/O流的使用方法

我們這里先來看幾張I/O流的族譜蟆技,首先我們來看字節(jié)流的族譜:

OutputStream

然后我們再來看InputStream的繼承結(jié)構(gòu):
InputStream

從圖中我們可以很清楚地看到幾個裝飾者模式的角色。我們以InputStream為例來分析斗忌,首先我們看到這里的InputStream就是裝飾者模式里面的Component角色质礼,看看他的實現(xiàn):
public abstract class InputStream implements Closeable {
......
}
這個InputStream里面有一些方法:
方法

然后接著看具體組件角色ConcreteComponent這里分別有:

ByteArrayInputStream
FileInputStream
ObjectInputStream
PipedInputStream
SequenceInputStream
StringBufferInputStream

這里的具體組件角色都有他特定的功能,比如說织阳,F(xiàn)ileInputStream代表一個文件輸入流并提供讀取文件內(nèi)容的功能眶蕉,ObjectInputStream提供了對象反序列化的功能。他們都是可以獨(dú)立使用的具體組件角色唧躲。接著我們看到抽象裝飾者角色Decorator,這里就是FilterInputStream造挽,我們來看下他的實現(xiàn):

public class FilterInputStream extends InputStream {
  protected volatile InputStream in;
  protected FilterInputStream(InputStream in) {
        this.in = in;
    }

  public int read() throws IOException {
        return in.read();
    }
.....
}

可以看到這個抽象裝飾者角色持有了具體組件角色的引用碱璃,然后調(diào)用了具體組件角色的方法。然后我們看到繼承結(jié)構(gòu)中具體裝飾者ConcreteDecorator有四個:

BufferedInputStream
DataInputStream
LineNumberInputStream
PushbackInputStream

我們這里以BufferedInputStream為例饭入,我們看下他的read()方法:

   public synchronized int read() throws IOException {
        if (pos >= count) {
            fill();
            if (pos >= count)
                return -1;
        }
        return getBufIfOpen()[pos++] & 0xff;
    }

?這里的方法邏輯就是如果pos>=count,那么我們就開始填充緩存嵌器,在fill()方法里面會調(diào)用InputStream來讀數(shù)據(jù)到緩存里面,否則直接從緩存里面讀取谐丢。這里我們不詳細(xì)展開爽航,我們知道BufferedInputStream就是一個具體裝飾者角色,它能為一個原本沒有緩沖功能的InputStream添加上緩沖的功能乾忱。

?有了上面的的基礎(chǔ)我們就知道怎么使用I/O流了讥珍,F(xiàn)ileInputStream這個具體組件角色本來是沒有緩存功能的,但是我們在讀取文件的時候我們希望他有緩存功能窄瘟,所以我們就可以用裝飾模式來使用他:

       InputStream in = new FileInputStream("test.txt");
        // 字節(jié)緩存流
        BufferedInputStream bis = new BufferedInputStream(in);
        byte[] bs = new byte[20];
        int len = 0;
        while ((len = bis.read(bs)) != -1) {

            System.out.print(new String(bs, 0, len));
            // ABCD
            // hello
        }
        // 關(guān)閉流
        bis.close();

所以以后我們以此類推串述,我們就可以使用好我們的I/O流了。

2.Android中的裝飾者模式

Context繼承結(jié)構(gòu)圖

這邊選擇了一張看著比較清楚的圖寞肖,我們這里不展開講纲酗,只是說說這里面的裝飾者模式的角色。
1.抽象組件角色:Context
2.具體組件角色:ContextImpl
3.抽象裝飾角色:ContextWrapper
4.具體裝飾角色:Service新蟆,Application觅赊,ContextThemeWrapper
這里的角色非常清晰明顯,具體的代碼大家可以自己去看看琼稻。

總結(jié):裝飾模式在使用中還是非常廣泛和容易的吮螺,如果你有需求正好是對一個已有的類進(jìn)行功能增強(qiáng)的話,那么你可以考慮考慮這個設(shè)計模式是不是適用帕翻,設(shè)計模式就是用的多了才有感覺鸠补,希望大家一起努力哈。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嘀掸,一起剝皮案震驚了整個濱河市紫岩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌睬塌,老刑警劉巖泉蝌,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異揩晴,居然都是意外死亡勋陪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門硫兰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诅愚,“玉大人,你說我怎么就攤上這事劫映∥バⅲ” “怎么了壕曼?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長等浊。 經(jīng)常有香客問我,道長摹蘑,這世上最難降的妖魔是什么筹燕? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮衅鹿,結(jié)果婚禮上撒踪,老公的妹妹穿的比我還像新娘。我一直安慰自己大渤,他們只是感情好制妄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著泵三,像睡著了一般耕捞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烫幕,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天俺抽,我揣著相機(jī)與錄音,去河邊找鬼较曼。 笑死磷斧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的捷犹。 我是一名探鬼主播弛饭,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼萍歉!你這毒婦竟也來了侣颂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤枪孩,失蹤者是張志新(化名)和其女友劉穎横蜒,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體销凑,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丛晌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了斗幼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澎蛛。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蜕窿,靈堂內(nèi)的尸體忽然破棺而出谋逻,到底是詐尸還是另有隱情呆馁,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布毁兆,位于F島的核電站浙滤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏气堕。R本人自食惡果不足惜纺腊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望茎芭。 院中可真熱鬧揖膜,春花似錦、人聲如沸梅桩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宿百。三九已至趁仙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間垦页,已是汗流浹背幸撕。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留外臂,地道東北人坐儿。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像宋光,于是被迫代替她去往敵國和親貌矿。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1 場景問題# 1.1 復(fù)雜的獎金計算## 考慮這樣一個實際應(yīng)用:就是如何實現(xiàn)靈活的獎金計算罪佳。 獎金計算是相對復(fù)雜...
    七寸知架構(gòu)閱讀 4,007評論 4 67
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,147評論 25 707
  • 設(shè)計模式匯總 一逛漫、基礎(chǔ)知識 1. 設(shè)計模式概述 定義:設(shè)計模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 3,947評論 1 15
  • 中秋之夜赘艳,托著下巴酌毡,看著窗外,好久沒有靜靜的觀望月亮了蕾管,它可真美枷踏,美的我不知改用什么詞匯來形容,我怕任何一個詞語...
    lemontree_aeca閱讀 301評論 0 2
  • 一掰曾、本期目標(biāo): 建立和諧的家庭關(guān)系旭蠕,改善緩和父子關(guān)系。 愿景:擁有一個幸福和諧的家庭,一家人友好相處相互信...
    夏寧點(diǎn)點(diǎn)閱讀 179評論 0 0