介紹:
裝飾模式屬于結(jié)構(gòu)型模式诵姜。它動態(tài)地給一個對象添加額外的職責(zé)同辣,就增加功能來說弯屈,裝飾模式比生成子類更加靈活工坊。
類圖:
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言疗、繼承的方案
這個方案就不用代碼例子晴圾,用類圖說明:
此部分內(nèi)容可以參考我另外一篇的文章哦:橋接模式——穿衣服經(jīng)典案例2
存在的問題
這種方案,在新增場景的情況又不需要改動原來的類噪奄,隨心所欲增加任何的功能死姚。看起來沒什么問題勤篮。但是都毒,三種場景還能接受,但如果需求是三十種場景叙谨,上百件不同的衣物呢温鸽?恐怕只能根據(jù)場合繼承一堆“XX場景的男人”類了。用繼承的方法會令到子類的數(shù)量暴增并且可能存在大量重復(fù)代碼,造成代碼臃腫涤垫,最終就是難以維護姑尺。
3、利用裝飾模式
重點終于來了蝠猬,裝飾模式可以說是繼承的一種替代方案切蟋,因為通過組合的方式也能擴展功能。在這個例子中榆芦,可以理解成“錢財乃身外之物”柄粹,所有的衣服都是人的一種裝飾。
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è)計模式之:訪問者模式——員工考核例子