1.1 什麼是裝飾者模式java
裝飾者模式指的是在沒必要改變原類文件和使用繼承的狀況下,動態地擴展一個對象的功能。它是經過建立一個包裝對象,也就是裝飾者來包裹真實的對象。編程
因此裝飾者能夠動態地將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性的方案。設計模式
1.2 裝飾者模式組成結構架構
1.3 裝飾者模式 UML 圖解ide
1.4 裝飾者模式應用場景函數
1.5 裝飾者模式特色測試
2.1 問題描述this
星巴茲咖啡訂單系統:星巴茲店提供了各式各樣的咖啡,以及各類咖啡調料。爲了適應飲料需求供應,因此讓你設計一個更新訂單系統。spa
2.2 使用繼承設計
在購買咖啡時,能夠要求在咖啡中添加各類調料,例如:豆漿 (Soy
)、摩卡 (Mocha
)、奶泡等。因爲各類調料的價格不相同,因此訂單系統必需要考慮這些因素。因而就有了下面的嘗試
2.3 繼承類圖
這還只是列出了一部分的類,這簡直是類爆炸,能夠看出這樣作顯然是不行的。因此咱們要慎用繼承,儘可能用組合和委託。
2.4 裝飾者模式登場
裝飾者模式涉及到的一個重要的設計原則 (固然還涉及到了其餘的設計原則,好比多用組合,少用繼承等):類應該對擴展開放,對修改關閉。
在設計過程當中,咱們容許類容易擴展,在不修改原有代碼的狀況下,就能夠擴展新的行爲。這樣的設計具備彈性能夠應對改變,能夠接受新的功能來應對新的需求。
將裝飾者模式應用到問題中去:假如咱們想要摩卡和豆漿深焙咖啡,那麼,要作的是:
DarkRoast
) 對象Mocha
) 裝飾它Soy
) 裝飾它cost()
方法,並依賴委託將調料的價錢加上去
(1) 裝飾者模式設計圖
(2)代碼實現
飲料 Beverage
抽象類 (抽象構件)
package com.jas.decorator; public abstract class Beverage { String description = "Unknown Beverage"; public String getDescription() { return description; } public abstract double cost(); }
濃咖啡 Espresso
類 (具體構件)
package com.jas.decorator; public class Espresso extends Beverage { public Espresso(){ description = "Espresso "; } @Override public double cost() { return 1.99; } }
黑咖啡 HouseBlend
類 (具體構件)
package com.jas.decorator; public class HouseBlend extends Beverage { public HouseBlend(){ description = "House Blend Coffee "; } @Override public double cost() { return 0.80; } }
調料 CondimentDecorator
抽象類 (抽象裝飾構件)
package com.jas.decorator; public abstract class CondimentDecorator extends Beverage{ @Override public abstract String getDescription(); }
摩卡 Mocha
類 (具體裝飾構件)
package com.jas.decorator; public class Mocha extends CondimentDecorator { private Beverage beverage = null; //用一個實例變量來記錄飲料,也就是被裝飾者 public Mocha(Beverage beverage){ this.beverage = beverage; //經過構造函數將被裝飾者實例化 } @Override public String getDescription() { return beverage.getDescription() + ", Mocha "; //用來加上調料,一塊兒描述飲料 } @Override public double cost() { return 0.2 + beverage.cost(); //計算摩卡飲料的價錢,爲摩卡價錢 + 飲料價錢 } }
豆漿 Soy
類 (具體裝飾構件)
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(); } }
測試代碼 StarbuzzCoffee
類
package com.jas.decorator; public class StarbuzzCoffee { public static void main(String[] args) { //簡單要一杯濃咖啡 Beverage beverage1 = new Espresso(); System.out.println(beverage1.getDescription() + "$" + beverage1.cost()); //兩份摩卡加一份豆漿的濃咖啡 Beverage beverage2 = new Espresso(); beverage2 = new Mocha(beverage2); beverage2 = new Mocha(beverage2); beverage2 = new Soy(beverage2); System.out.println(beverage2.getDescription() + "$" + beverage2.cost()); //一份摩卡加一份豆漿的黑咖啡 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 裝飾者模式問題總結
DarkRoast
與裝飾類 Mocha
和 Soy
都繼承自 Beverage
(飲料))。3.1 瞭解 Java I/O 裝飾者模式
在瞭解了裝飾者模式以後,I/O 相關的類對你來講就更有意義了,由於這其中不少類都是裝飾者。好比下面相關的類
裝飾 I/O 類
3.2 自定義 Java I/O 裝飾者
問題描述:讀取文件,把輸入流內的全部大寫字符轉爲小寫。
裝飾者 LowerCaseInputStream
類
package com.jas.decorator; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; /** * 擴展 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; } }
測試 InputTest
類
package com.jas.decorator; import java.io.*; public class InputTest { public static void main(String[] args) { int c = 0; InputStream in = null; try { //設置 FileInputStream ,先用 BufferedInputStream 裝飾它,再用 LowerCaseInputStream 進行裝飾 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 */
4.1 裝飾者模式的優缺點
優勢
缺點
《Head First 設計模式》