裝飾模式也是一種結構型模式,主要是目的是相對於類與類之間的繼承關係來講,使用裝飾模式能夠下降耦合度。JDK中有很多地方都使用到了裝飾模式,例如Java的各類I/O流,javax.swing包中一些圖形界面構件功能的加強等地方都運用了裝飾模式。 html
裝飾模式的定義是:在不改變原類文件以及不使用繼承的狀況下,動態的擴展一個對象的功能。裝飾模式是經過建立一個包裝對象來實現的,也就是用裝飾來包裹真實的對象。java
仍是老規矩,舉例說明,在給親朋好友過生日時會買生日蛋糕,而後生日蛋糕又有各類各樣的輔料來進行裝飾,例如:奶油,水果,芝士,巧克力等等。若是沒有這些輔料來進行裝飾,就是普通的雞蛋糕。因此咱們能夠把作蛋糕的這個過程來用代碼實現出來:設計模式
首先定義蛋糕接口ide
/** * 蛋糕 */ public interface CakeGoods { /** * 展現蛋糕 */ void showCake(); /** * 展現價格 */ BigDecimal showPrice(); }
具體的雞蛋糕post
/** * 雞蛋糕 */ @Data public class SpongeCake implements CakeGoods{ //蛋糕名稱 private String name; //蛋糕價格 private BigDecimal price; public SpongeCake(String name,BigDecimal price){ this.name = name; this.price = price; } /** * 展現蛋糕 */ @Override public void showCake() { System.out.println("的"+this.name+"蛋糕"); } /** * 展現價格 */ @Override public BigDecimal showPrice() { return this.price; } }
輔料的抽象類性能
/** * 輔料的抽象類 */ public abstract class Decorator implements CakeGoods{ private CakeGoods cakeGoods; public void setCakeGoods(CakeGoods cakeGoods){ this.cakeGoods = cakeGoods; } /** * 展現蛋糕 */ @Override public void showCake() { cakeGoods.showCake(); } /** * 展現價格 */ @Override public BigDecimal showPrice() { return cakeGoods.showPrice(); } }
水果學習
/** * 水果 */ public class Fruits extends Decorator { /** * 展現蛋糕 */ @Override public void showCake() { System.out.print("加水果"); super.showCake(); } /** * 展現價格 */ @Override public BigDecimal showPrice() { return new BigDecimal(20.00).add(super.showPrice()); } }
奶油測試
/** * 奶油 */ public class Cream extends Decorator { /** * 展現蛋糕 */ @Override public void showCake() { System.out.print("加奶油"); super.showCake(); } /** * 展現價格 */ @Override public BigDecimal showPrice() { return new BigDecimal(15.00).add(super.showPrice()); } }
測試ui
public class Tests { public static void main(String[] args) { //製造雞蛋糕 CakeGoods cakeGoods = new SpongeCake("生日祝福",new BigDecimal(50)); Decorator cream = new Cream(); Decorator fruits = new Fruits(); //加奶油 cream.setCakeGoods(fruits); //加水果 fruits.setCakeGoods(cakeGoods); //展現 cream.showCake(); System.out.println("的價格是:"+cream.showPrice()+"元"); } }
運行結果:this
加奶油加水果的生日祝福蛋糕
的價格是:85元
上面的這個蛋糕製造的例子使用的就是裝飾模式,在爲雞蛋糕SpongeCake進行擴展的時候並無影響它原來的類的結構,也沒有使用繼承的關係,最終卻達到了裝飾的目的。下面咱們來分析一下裝飾模式具體是由那幾部分組成。
裝飾模式的結構圖如上所示,主要由如下幾個角色組成。
抽象構件角色:(上圖的CakeGoods)定義一個抽象接口,以規範準備接受裝飾的對象,想當於Java中的IO流裏的InputStram/OutputStream和Reader/Writer。
具體的構件角色:(上圖的SpongeCake)定義一個將要接受裝飾的類,至關於I/O流裏面的FileOutputStream和FileInputStream。
裝飾角色:(上圖的Decorator)定義一個持有抽象構件角色的引用,並定義一個與抽象構件一直的接口。至關於I/O裏面的FilterOutputStream和FilterInputStream。
具體的裝飾角色:(上圖的Fruits和Cream)負責各構件角色對象加上相應的裝飾品,至關於I/O流裏的BufferedOutputStream、BufferedInputStream。
在使用的時候,必須擴展CakeGoods的功能,可是咱們是經過Fruits和Cream來對CakeGoods進行擴展的,因此相對於CakeGoods來講無需知道Decorator的存在,就能擴展功能了。
在不影響其餘對象的狀況下,以動態、透明的方式給單個對象添加職責。
當不能採用繼承的方式對系統進行擴展或者採用繼承不利於系統擴展和維護時可使用裝飾模式。不能採用繼承的狀況主要有兩類:第一類是系統中存在大量獨立的擴展,爲支持每一種擴展或者擴展之間的組合將產生大量的子類,使得子類數目呈爆炸性增加;第二類是由於類已定義爲不能被繼承(如Java語言中的final類)。
加油,給本身打氣,克服惰性!!!
想了解更多的設計模式請查看Java設計模式學習記錄-GoF設計模式概述。