摘要:裝飾者模式組成結(jié)構(gòu)抽象構(gòu)件給出抽象接口或抽象類,以規(guī)范準(zhǔn)備接收附加功能的對(duì)象。裝飾者模式圖解裝飾者模式應(yīng)用場(chǎng)景需要擴(kuò)展一個(gè)類的功能,或給一個(gè)類添加附加職責(zé)。裝飾者對(duì)象接受所有來(lái)自客戶端的請(qǐng)求。參考資料設(shè)計(jì)模式
一、了解裝飾者模式
1.1 什么是裝飾者模式
裝飾者模式指的是在不必改變?cè)愇募褪褂美^承的情況下,動(dòng)態(tài)地?cái)U(kuò)展一個(gè)對(duì)象的功能。它是通過(guò)創(chuàng)建一個(gè)包裝對(duì)象,也就是裝飾者來(lái)包裹真實(shí)的對(duì)象。
所以裝飾者可以動(dòng)態(tài)地將責(zé)任附加到對(duì)象上。若要擴(kuò)展功能,裝飾者提供了比繼承更有彈性的方案。
1.2 裝飾者模式組成結(jié)構(gòu)
抽象構(gòu)件 (Component):給出抽象接口或抽象類,以規(guī)范準(zhǔn)備接收附加功能的對(duì)象。
具體構(gòu)件 (ConcreteComponent):定義將要接收附加功能的類。
抽象裝飾 (Decorator):裝飾者共同要實(shí)現(xiàn)的接口,也可以是抽象類。
具體裝飾 (ConcreteDecorator):持有一個(gè) Component 對(duì)象,負(fù)責(zé)給構(gòu)件對(duì)象“貼上”附加的功能。
1.3 裝飾者模式 UML 圖解
1.4 裝飾者模式應(yīng)用場(chǎng)景
需要擴(kuò)展一個(gè)類的功能,或給一個(gè)類添加附加職責(zé)。
需要?jiǎng)討B(tài)的給一個(gè)對(duì)象添加功能,這些功能可以再動(dòng)態(tài)的撤銷。
需要增加由一些基本功能的排列組合而產(chǎn)生的非常大量的功能,從而使繼承關(guān)系變的不現(xiàn)實(shí)。
當(dāng)不能采用生成子類的方法進(jìn)行擴(kuò)充時(shí)。可能有大量獨(dú)立的擴(kuò)展,為支持每一種組合將產(chǎn)生大量的子類,使得子類數(shù)目呈爆炸性增長(zhǎng)。
1.5 裝飾者模式特點(diǎn)
裝飾者對(duì)象和具體構(gòu)件有相同的接口。這樣客戶端對(duì)象就能以和真實(shí)對(duì)象相同的方式和裝飾對(duì)象交互。
裝飾者對(duì)象包含一個(gè)具體構(gòu)件的引用(reference)。
裝飾者對(duì)象接受所有來(lái)自客戶端的請(qǐng)求。它把這些請(qǐng)求轉(zhuǎn)發(fā)給具體構(gòu)件。
裝飾者對(duì)象可以在轉(zhuǎn)發(fā)這些請(qǐng)求以前或以后動(dòng)態(tài)增加一些功能。
二、裝飾者模式具體應(yīng)用2.1 問(wèn)題描述
星巴茲咖啡訂單系統(tǒng):星巴茲店提供了各式各樣的咖啡,以及各種咖啡調(diào)料。為了適應(yīng)飲料需求供應(yīng),所以讓你設(shè)計(jì)一個(gè)更新訂單系統(tǒng)。
2.2 使用繼承
在購(gòu)買(mǎi)咖啡時(shí),可以要求在咖啡中添加各種調(diào)料,例如:豆?jié){ (Soy)、摩卡 (Mocha)、奶泡等。由于各種調(diào)料的價(jià)格不相同,所以訂單系統(tǒng)必須要考慮這些因素。于是就有了下面的嘗試
2.3 繼承類圖
這還只是列出了一部分的類,這簡(jiǎn)直是類爆炸,可以看出這樣做顯然是不行的。所以我們要慎用繼承,盡量用組合和委托。
2.4 裝飾者模式登場(chǎng)
裝飾者模式涉及到的一個(gè)重要的設(shè)計(jì)原則 (當(dāng)然還涉及到了其他的設(shè)計(jì)原則,比如多用組合,少用繼承等):類應(yīng)該對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。
在設(shè)計(jì)過(guò)程中,我們?cè)试S類容易擴(kuò)展,在不修改原有代碼的情況下,就可以擴(kuò)展新的行為。這樣的設(shè)計(jì)具有彈性可以應(yīng)對(duì)改變,可以接受新的功能來(lái)應(yīng)對(duì)新的需求。
將裝飾者模式應(yīng)用到問(wèn)題中去:假如我們想要摩卡和豆?jié){深焙咖啡,那么,要做的是:
拿一個(gè)深焙咖啡 (DarkRoast) 對(duì)象
以摩卡 (Mocha) 裝飾它
以豆?jié){ (Soy) 裝飾它
調(diào)用 cost() 方法,并依賴委托將調(diào)料的價(jià)錢(qián)加上去
(1) 裝飾者模式設(shè)計(jì)圖
(2)代碼實(shí)現(xiàn)
飲料 Beverage 抽象類 (抽象構(gòu)件)
package com.jas.decorator; public abstract class Beverage { String description = "Unknown Beverage"; public String getDescription() { return description; } public abstract double cost(); }
濃咖啡 Espresso 類 (具體構(gòu)件)
package com.jas.decorator; public class Espresso extends Beverage { public Espresso(){ description = "Espresso "; } @Override public double cost() { return 1.99; } }
黑咖啡 HouseBlend 類 (具體構(gòu)件)
package com.jas.decorator; public class HouseBlend extends Beverage { public HouseBlend(){ description = "House Blend Coffee "; } @Override public double cost() { return 0.80; } }
調(diào)料 CondimentDecorator 抽象類 (抽象裝飾構(gòu)件)
package com.jas.decorator; public abstract class CondimentDecorator extends Beverage{ @Override public abstract String getDescription(); }
摩卡 Mocha 類 (具體裝飾構(gòu)件)
package com.jas.decorator; public class Mocha extends CondimentDecorator { private Beverage beverage = null; //用一個(gè)實(shí)例變量來(lái)記錄飲料,也就是被裝飾者 public Mocha(Beverage beverage){ this.beverage = beverage; //通過(guò)構(gòu)造函數(shù)將被裝飾者實(shí)例化 } @Override public String getDescription() { return beverage.getDescription() + ", Mocha "; //用來(lái)加上調(diào)料,一起描述飲料 } @Override public double cost() { return 0.2 + beverage.cost(); //計(jì)算摩卡飲料的價(jià)錢(qián),為摩卡價(jià)錢(qián) + 飲料價(jià)錢(qián) } }
豆?jié){ Soy 類 (具體裝飾構(gòu)件)
package com.jas.decorator; public class Soy extends CondimentDecorator { private Beverage beverage = null; public Soy(Beverage beverage){ this.beverage = beverage; } @Override public String getDescription() { return beverage.getDescription() + ", Soy "; } @Override public double cost() { return 0.1 + beverage.cost(); } }
測(cè)試代碼 StarbuzzCoffee 類
package com.jas.decorator; public class StarbuzzCoffee { public static void main(String[] args) { //簡(jiǎn)單要一杯濃咖啡 Beverage beverage1 = new Espresso(); System.out.println(beverage1.getDescription() + "$" + beverage1.cost()); //兩份摩卡加一份豆?jié){的濃咖啡 Beverage beverage2 = new Espresso(); beverage2 = new Mocha(beverage2); beverage2 = new Mocha(beverage2); beverage2 = new Soy(beverage2); System.out.println(beverage2.getDescription() + "$" + beverage2.cost()); //一份摩卡加一份豆?jié){的黑咖啡 Beverage beverage3 = new HouseBlend(); beverage3 = new Mocha(beverage3); beverage3 = new Soy(beverage3); System.out.println(beverage3.getDescription() + "$" + beverage3.cost()); } } /** * 輸出 * Espresso $1.99 * Espresso , Mocha , Mocha , Soy $2.49 * House Blend Coffee , Mocha , Soy $1.1 */
2.5 裝飾者模式問(wèn)題總結(jié)
裝飾者與被裝飾對(duì)象有相同的超類型 (DarkRoast 與裝飾類 Mocha 和 Soy 都繼承自 Beverage(飲料))。
可以使用一個(gè)或多個(gè)裝飾對(duì)象包裝一個(gè)對(duì)象。
因?yàn)檠b飾者與被裝飾者具有相同的超類型,所以在任何需要原始對(duì)象的情況下,都可以用裝飾過(guò)的對(duì)象去代替它。
裝飾者可以在所委托被裝飾者的行為之前與之后,加上自己的行為,以達(dá)到特定的目的。
對(duì)象可以在任何時(shí)候被裝飾,所以在運(yùn)行時(shí)動(dòng)態(tài)地、不限量地用你喜歡的裝飾者去裝飾對(duì)象。
三、真實(shí)世界的裝飾者 Java I/O3.1 了解 Java I/O 裝飾者模式
在了解了裝飾者模式之后,I/O 相關(guān)的類對(duì)你來(lái)說(shuō)就更有意義了,因?yàn)檫@其中很多類都是裝飾者。比如下面相關(guān)的類
裝飾 I/O 類
3.2 自定義 Java I/O 裝飾者
問(wèn)題描述:讀取文件,把輸入流內(nèi)的所有大寫(xiě)字符轉(zhuǎn)為小寫(xiě)。
裝飾者 LowerCaseInputStream 類
package com.jas.decorator; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; /** * 擴(kuò)展 FilterInputStream,這是所有 InputStream 的抽象裝飾者 */ public class LowerCaseInputStream extends FilterInputStream { public LowerCaseInputStream(InputStream inputStream){ super(inputStream); } @Override public int read() throws IOException{ int c = super.read(); return (c == -1 ? c : Character.toLowerCase((char)c)); } @Override public int read(byte[] bytes, int offset, int len) throws IOException{ int result = super.read(bytes, offset, len); for (int i = offset; i < offset + result; i++) { bytes[i] = (byte) Character.toLowerCase((char)bytes[i]); } return result; } }
測(cè)試 InputTest 類
package com.jas.decorator; import java.io.*; public class InputTest { public static void main(String[] args) { int c = 0; InputStream in = null; try { //設(shè)置 FileInputStream ,先用 BufferedInputStream 裝飾它,再用 LowerCaseInputStream 進(jìn)行裝飾 in = new LowerCaseInputStream( new BufferedInputStream( new FileInputStream("test.txt"))); while ((c = in.read()) >= 0){ System.out.print((char)c); } in.close(); } catch (IOException e) { e.printStackTrace(); } } } /**在文件中為“HELLO WORLD” * * 輸出 * hello world */四、裝飾者模式總結(jié)
4.1 裝飾者模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
Decorator 模式與繼承關(guān)系的目的都是要擴(kuò)展對(duì)象的功能,但是 Decorator 可以提供比繼承更多的靈活性。
通過(guò)使用不同的具體裝飾類以及這些裝飾類的排列組合,設(shè)計(jì)者可以創(chuàng)造出很多不同行為的組合。
缺點(diǎn)
這種比繼承更加靈活機(jī)動(dòng)的特性,也同時(shí)意味著更加多的復(fù)雜性。
裝飾模式會(huì)導(dǎo)致設(shè)計(jì)中出現(xiàn)許多小類 (I/O 類中就是這樣),如果過(guò)度使用,會(huì)使程序變得很復(fù)雜。
裝飾模式是針對(duì)抽象組件(Component)類型編程。但是,如果你要針對(duì)具體組件編程時(shí),就應(yīng)該重新思考你的應(yīng)用架構(gòu),以及裝飾者是否合適。
參考資料《Head First 設(shè)計(jì)模式》
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/77260.html
摘要:相關(guān)設(shè)計(jì)模式裝飾者模式和代理模式裝飾者模式關(guān)注再一個(gè)對(duì)象上動(dòng)態(tài)添加方法代理模式關(guān)注再對(duì)代理對(duì)象的控制訪問(wèn),可以對(duì)客戶隱藏被代理類的信息裝飾著模式和適配器模式都叫包裝模式關(guān)于新職責(zé)適配器也可以在轉(zhuǎn)換時(shí)增加新的職責(zé),但主要目的不在此。 0x01.定義與類型 定義:裝飾模式指的是在不必改變?cè)愇募褪褂美^承的情況下,動(dòng)態(tài)地?cái)U(kuò)展一個(gè)對(duì)象的功能。它是通過(guò)創(chuàng)建一個(gè)包裝對(duì)象,也就是裝飾來(lái)包裹真實(shí)的...
摘要:裝飾者模式是動(dòng)態(tài)地將責(zé)任附加到對(duì)象上。然后我們?cè)谧宇愑?jì)算價(jià)格的時(shí)候加上父類中計(jì)算好的配料的價(jià)格。結(jié)果可樂(lè)加冰可樂(lè)加冰加糖在的類庫(kù)中就有很多實(shí)際應(yīng)用到了裝飾模式,比如就可以用來(lái)裝飾,提供更加強(qiáng)大的功能。 裝飾者模式是動(dòng)態(tài)地將責(zé)任附加到對(duì)象上。若要擴(kuò)展功能,裝飾者提供了比繼承更有彈性的替代方案。 假設(shè)我們有一個(gè)需求,是給一家飲料店做一個(gè)計(jì)算各種飲料價(jià)格的功能。聽(tīng)起來(lái)很簡(jiǎn)單,我們創(chuàng)建一個(gè)抽象...
摘要:測(cè)試類設(shè)計(jì)模式裝飾者模式工廠模式只能讀啦會(huì)報(bào)錯(cuò)只讀異常可以正確運(yùn)行第二部分定義抽象組件是具體組件和抽象裝飾類的共同父類,聲明了在具體組件中實(shí)現(xiàn)的方法。 前言 本篇文章分為四個(gè)部分:第一部分會(huì)舉一個(gè)例子引出裝飾者模式,讓讀者對(duì)裝飾者模式有個(gè)感官上的認(rèn)識(shí);第二部分會(huì)給出裝飾者模式的定義(當(dāng)然我們主要不是來(lái)背定義,就當(dāng)做積累專業(yè)名詞來(lái)記吧,我個(gè)人是很不喜歡下定義的);第三部分,我會(huì)拿jdk中...
摘要:若要擴(kuò)展功能,裝飾者提供了比繼承更有彈性的替代方案。裝飾者模式意味著一群裝飾者類,這些類用來(lái)包裝具體組件。裝飾者類反映出被裝飾組件類型。裝飾者會(huì)導(dǎo)致設(shè)計(jì)中出現(xiàn)許多小對(duì)象,如果過(guò)度使用,會(huì)讓程序變得很復(fù)雜。 嘿嘿嘿,你是不是很喜歡用繼承呢?感覺(jué)沒(méi)什么事情是一個(gè)爸爸類搞不定的,有的話就兩個(gè),快來(lái)跟我看看這個(gè)模式吧,它能讓你斷奶,給愛(ài)用繼承的人一個(gè)全新的設(shè)計(jì)眼界。 直奔主題,你是否有聽(tīng)說(shuō)...
摘要:適配器模式不應(yīng)在設(shè)計(jì)階段考慮,它是為了解決已經(jīng)上線的問(wèn)題的存在。組合模式將對(duì)象組合成樹(shù)形結(jié)構(gòu)以表示部分整體的層次結(jié)構(gòu),使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。 代理模式 代理模式之前已經(jīng)講過(guò),附上鏈接代理模式 裝飾者模式 裝飾者模式定義:動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來(lái)說(shuō),裝飾模式相比生成子類更為靈活。 裝飾模式博主在第一次學(xué)習(xí)是懵逼的,是因?yàn)榇砟J街写韺?duì)象和...
閱讀 3722·2021-10-18 13:34
閱讀 2422·2021-08-11 11:15
閱讀 1210·2019-08-30 15:44
閱讀 703·2019-08-26 10:32
閱讀 998·2019-08-26 10:13
閱讀 2073·2019-08-23 18:36
閱讀 1786·2019-08-23 18:35
閱讀 534·2019-08-23 17:10