簡易理解設(shè)計模式之:裝飾模式——穿衣服經(jīng)典案例

介紹:

裝飾模式屬于結(jié)構(gòu)型模式诵姜。它動態(tài)地給一個對象添加額外的職責(zé)同辣,就增加功能來說弯屈,裝飾模式比生成子類更加靈活工坊。

類圖:

裝飾模式UML類圖.png

Component(抽象組件):接口或者抽象類献汗,被裝飾的最原始的對象。
ConcreteComponent(具體組件):實現(xiàn)抽象組件的接口王污。
Decorator(抽象裝飾角色):一般是抽象類罢吃,持有一個被裝飾者的引用,用來調(diào)用被裝飾者的方法昭齐,同時可以給被裝飾者增加新的職責(zé)尿招。
ConcreteDecorator(具體裝飾類):抽象裝飾角色的具體實現(xiàn)。

用法:

? 當(dāng)不適合采用繼承的方式對系統(tǒng)進行新增功能時阱驾。
? 需要透明且動態(tài)地擴展類的功能時就谜。

按照以上兩點,個人理解翻譯一下:
? 不適合用繼承擴展的情況有哪些呢啊易?假設(shè)有Parent吁伺、Child饮睬、GrandChild三個類租谈,我需要擴展其中的Child類很明顯用繼承不合適,因為可能會影響到GrandChild捆愁;又或者用繼承的方法會令到子類的數(shù)量暴增并且可能存在大量重復(fù)代碼割去,造成代碼臃腫。

? 所謂動態(tài)昼丑,就是給一個對象添加一些額外的職責(zé)呻逆,同時也可以動態(tài)取消,實現(xiàn)功能的動態(tài)組合菩帝;所謂透明咖城,要給一個對象增加功能,但是不能讓這個對象知道呼奢,也就是不能去改動這個對象宜雀。

例子:

裝飾模式應(yīng)用廣泛,例如Java I/O標(biāo)準(zhǔn)庫的設(shè)計就是Java語言中的最著名的例子握础。而這次我們參考《大話設(shè)計模式》書中辐董,穿衣服的經(jīng)典案例。

眾所周知禀综,人會根據(jù)不同的場合穿著不同的衣服简烘。就以男人為例苔严,上班時會著裝正式(領(lǐng)帶、襯衫孤澎、外套届氢、西褲、皮鞋亥至、手表等)悼沈,睡覺時會穿舒適(睡衣、睡褲等)姐扮,運動時會穿運動服(T恤衫絮供、運動褲、運動鞋等)茶敏。

需求:輸出男人在以上三種場合的著裝要求

1壤靶、原始代碼

新手寫代碼很容易寫成把所有的衣服都放在一個類里面,我們先看一下沒有用任何涉及模式的例子:

1.1惊搏、新建一個男人類

public class Man {
    public String name;

    public Man(String name) {
        this.name = name;
    }

    public void dress() {
        System.out.println("裝扮的" + name);
    }

    public void dressTie() {
        System.out.println("系一條領(lǐng)帶");
    }

    public void dressTShirt() {
        System.out.println("穿一件TShirt");
    }

    public void dressSuit() {
        System.out.println("穿一件西裝");
    }

    public void dressSportShoes(){
        System.out.println("穿運動鞋");
    }

    //省略一堆代碼
}

1.2贮乳、調(diào)用這個男人類,根據(jù)不同場合任意搭配

public static void main(String[] args) {
    //場合一:
    Man xiaoMing = new Man("小明");
    xiaoMing.dressTShirt();
    xiaoMing.dressTie();
    xiaoMing.dressSuit();

    //場合二:省略一堆代碼
}
存在的問題

分析一下恬惯,實現(xiàn)這個需求看起來沒什么問題向拆。根據(jù)場合任意搭配可以實現(xiàn)這個需求,但是問題來了:需要為新場合新增衣服時酪耳,改動了原來的類浓恳,違背了開閉原則。要記住碗暗,在實際開發(fā)中颈将,需求永遠都是在變的。

2言疗、繼承的方案

這個方案就不用代碼例子晴圾,用類圖說明:


image.png

此部分內(nèi)容可以參考我另外一篇的文章哦:橋接模式——穿衣服經(jīng)典案例2

存在的問題

這種方案,在新增場景的情況又不需要改動原來的類噪奄,隨心所欲增加任何的功能死姚。看起來沒什么問題勤篮。但是都毒,三種場景還能接受,但如果需求是三十種場景叙谨,上百件不同的衣物呢温鸽?恐怕只能根據(jù)場合繼承一堆“XX場景的男人”類了。用繼承的方法會令到子類的數(shù)量暴增并且可能存在大量重復(fù)代碼,造成代碼臃腫涤垫,最終就是難以維護姑尺。

3、利用裝飾模式

重點終于來了蝠猬,裝飾模式可以說是繼承的一種替代方案切蟋,因為通過組合的方式也能擴展功能。在這個例子中榆芦,可以理解成“錢財乃身外之物”柄粹,所有的衣服都是人的一種裝飾。

image.png

3.1匆绣、目前只考慮男人的情況下驻右,將Component與ConcreteComponent二合一

public class Man {
    public String name;

    public Man(){

    }

    public Man(String name) {
        this.name = name;
    }

    public void dress() {
        System.out.println("裝扮的" + name);
    }
}

很簡單,就一個dress方法崎淳。Man類就是一個需要被裝飾的對象堪夭,裝飾器可以給它增加額外的職責(zé)。

3.2拣凹、創(chuàng)建一個裝飾者類森爽,命名為Finery(服飾)。

public class Finery extends Man{
    protected Man man;

    public void decorate(Man man){
        this.man = man;
    }

    public void dress(){
        if (man != null){
            man.dress();
        }
    }
}

3.3嚣镜、創(chuàng)建一堆具體裝飾者類爬迟,它們繼承自Finery

public class TShirt extends Finery {

    @Override
    public void dress() {
        System.out.println("T恤衫");
        super.dress();
    }
}
public class SportShoes extends Finery {
    @Override
    public void dress() {
        System.out.println("運動鞋");
        super.dress();
    }
}

省略一堆代碼。菊匿。付呕。

3.4、實現(xiàn)需求

public static void main(String[] args) {
    Man xiaoMing = new Man("小明");

    //場合一:運動
    Finery sportShoes = new SportShoes();
    sportShoes.decorate(xiaoMing);   //穿了運動鞋的小明

    Finery tShirt = new TShirt();
    tShirt.decorate(sportShoes);     //穿了運動鞋的小明再穿一件T恤衫
    tShirt.dress();                  //裝扮好了

    //場合二:睡覺
    //省略一堆代碼....
}

運行效果

T恤衫
運動鞋
裝扮的小明

用裝飾模式修改代碼的方案就基本完成了捧请,新增場合通過組合的方式就完事了凡涩。但使用此模式的同時會產(chǎn)生很多小對象(各種Finery子類)棒搜,大量小對象的產(chǎn)生勢必會占用更多的系統(tǒng)資源疹蛉,在一定程序上影響程序的性能。這正正是這個模式的缺點力麸,不可避免可款。

4、透明裝飾模式與半透明裝飾模式

在實際使用過程中克蚂,由于新增行為可能需要單獨調(diào)用闺鲸,因此這種形式的裝飾模式也經(jīng)常出現(xiàn),這種裝飾模式被稱為半透明(Semi-transparent)裝飾模式埃叭,而標(biāo)準(zhǔn)的裝飾模式是透明(Transparent)裝飾模式摸恍。

4.1、下面我要為具體裝飾類新增一個增加顏色的方法:

public class TShirt extends Finery {

    @Override
    public void dress() {
        System.out.println("T恤衫");
        super.dress();
    }

    public void changeColor(String color){
        System.out.print(color);
    }
}

4.2、代碼區(qū)別

public static void main(String[] args) {
    Man xiaoMing = new Man("小明");

    //透明裝飾模式
    Finery tShirt = new TShirt();
    tShirt.decorate(xiaoMing);       //穿了一件T恤衫
    tShirt.dress();                  //裝扮好了

    System.out.println("===========");

     //半透明裝飾模式
    TShirt tShirt2 = new TShirt();
    tShirt2.decorate(xiaoMing);     //穿了一件T恤衫
    tShirt2.changeColor("紅色");    //染上紅色
    tShirt2.dress();               //裝扮好了
}
T恤衫
裝扮的小明
===========
紅色T恤衫
裝扮的小明

很直觀立镶,在透明裝飾模式中壁袄,要求客戶端完全針對抽象編程,裝飾模式的透明性要求客戶端程序全部聲明為抽象類型媚媒。在上述例子中嗜逻,被修飾的對象(Man類)和裝飾的對象(T-Shirt對象用Finery類聲明)都要是抽象類型。

而在半透明模式缭召,為了能夠調(diào)用到新增方法栈顷,用具體裝飾類型來定義裝飾之后的對象,而具體構(gòu)件類型還是可以使用抽象構(gòu)件類型來定義嵌巷,這種裝飾模式即為半透明裝飾模式萄凤。被修飾的對象(Man類)用抽象類型Man,具體裝飾用具體裝飾聲明(T-Shirt對象用T-Shirt類聲明)搪哪。

感謝您的閱讀~

轉(zhuǎn)載請注明出處喔:http://www.reibang.com/p/191e761b07a1

推薦閱讀

基礎(chǔ)篇:
設(shè)計模式前篇之——UML類圖必會知識點
設(shè)計模式前篇之——一起過一下面向?qū)ο蟮母拍?/a>
創(chuàng)建型模式:
簡易理解設(shè)計模式之:簡單工廠模式——來試試接入支付功能
簡易理解設(shè)計模式之:工廠方法模式——數(shù)據(jù)存儲例子
簡易理解設(shè)計模式之:抽象工廠模式——更換數(shù)據(jù)庫例子
簡易理解設(shè)計模式之:建造者模式——學(xué)習(xí)使用“鏈?zhǔn)秸{(diào)用”
簡易理解設(shè)計模式之:原型模式——深蛙卤、淺拷貝的概念
簡易理解設(shè)計模式之:單例模式——單例模式的幾種常用寫法
結(jié)構(gòu)型模式:
簡易理解設(shè)計模式之:適配器模式——Android列表視圖控件設(shè)計方式
簡易理解設(shè)計模式之:橋接模式——穿衣服經(jīng)典案例2
簡易理解設(shè)計模式之:組合模式——實現(xiàn)View中的樹狀結(jié)構(gòu)
簡易理解設(shè)計模式之:裝飾模式——穿衣服經(jīng)典案例
簡易理解設(shè)計模式之:外觀模式——第三方SDK的幫助類
簡易理解設(shè)計模式之:享元模式——五子棋游戲例子
簡易理解設(shè)計模式之:代理模式——iOS視圖控件設(shè)計方式
行為型模式:
簡易理解設(shè)計模式之:策略模式——優(yōu)化一下支付功能
簡易理解設(shè)計模式之:模板方法模式——Android中的BaseActivity基類
簡易理解設(shè)計模式之:觀察者模式——監(jiān)聽與回調(diào)
簡易理解設(shè)計模式之:狀態(tài)模式——優(yōu)化登錄操作
簡易理解設(shè)計模式之:備忘錄模式——Word文檔的工作原理
簡易理解設(shè)計模式之:迭代器模式——遍歷對象的好幫手
簡易理解設(shè)計模式之:命令模式——實現(xiàn)命令的參數(shù)化配置
簡易理解設(shè)計模式之:責(zé)任鏈模式——OA中請假流程示例
簡易理解設(shè)計模式之:中介者模式——多人聊天室例子
簡易理解設(shè)計模式之:解釋器模式——語言和文法
簡易理解設(shè)計模式之:訪問者模式——員工考核例子

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市噩死,隨后出現(xiàn)的幾起案子颤难,更是在濱河造成了極大的恐慌,老刑警劉巖已维,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件行嗤,死亡現(xiàn)場離奇詭異,居然都是意外死亡垛耳,警方通過查閱死者的電腦和手機栅屏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堂鲜,“玉大人栈雳,你說我怎么就攤上這事〉蘖” “怎么了哥纫?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長痴奏。 經(jīng)常有香客問我蛀骇,道長,這世上最難降的妖魔是什么读拆? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任擅憔,我火速辦了婚禮,結(jié)果婚禮上檐晕,老公的妹妹穿的比我還像新娘暑诸。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布个榕。 她就那樣靜靜地躺著啦逆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪笛洛。 梳的紋絲不亂的頭發(fā)上夏志,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機與錄音苛让,去河邊找鬼沟蔑。 笑死,一個胖子當(dāng)著我的面吹牛狱杰,可吹牛的內(nèi)容都是我干的瘦材。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼仿畸,長吁一口氣:“原來是場噩夢啊……” “哼食棕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起错沽,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤簿晓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后千埃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體憔儿,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年放可,在試婚紗的時候發(fā)現(xiàn)自己被綠了谒臼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡耀里,死狀恐怖蜈缤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情冯挎,我是刑警寧澤底哥,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站织堂,受9級特大地震影響叠艳,放射性物質(zhì)發(fā)生泄漏奶陈。R本人自食惡果不足惜易阳,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吃粒。 院中可真熱鬧潦俺,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至肖爵,卻和暖如春卢鹦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背劝堪。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工冀自, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人秒啦。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓熬粗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親余境。 傳聞我的和親對象是個殘疾皇子驻呐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

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

  • (轉(zhuǎn)載)原文地址 在閻宏博士的《JAVA與模式》一書中開頭是這樣描述裝飾(Decorator)模式的: 裝飾模式又...
    zjk_00閱讀 629評論 0 2
  • 裝飾模式 定義 裝飾模式又名包裝(Wrapper)模式。裝飾模式以對客戶端透明的方式擴展對象的功能芳来,是繼承關(guān)系的一...
    晨鳴code閱讀 1,314評論 0 0
  • 這個冬天依然很冷 太陽偶爾擠出點笑容 卻擋不住寒風(fēng)的頑皮 路人唱著聽不懂的歌 顫顫巍巍的擠進屋子 唯有你的文字 是...
    冰葉草閱讀 163評論 0 0
  • 掀開黎明的沙窗 從骨頭里取出 珍藏了千年的那粒種子 埋在了泥濘的心上 精心計算過播種的良辰 被時節(jié)猜透心事 嘀嗒的...
    荔波波波閱讀 378評論 14 26
  • 疏天穎緊閉著雙眸含末,不敢去設(shè)想自己會落得個什么下場。詩人但丁在《神曲》里寫到人死后要經(jīng)過三個地方地獄即舌、煉獄答渔、天堂,...
    嬴十一閱讀 279評論 0 0