1.裝飾模式講解1.1定義
動態給一個對象添加一些額外的職責。就增加功能來說,裝飾模式比產生子類更加靈活。
1.2裝飾模式要點
透明的給一個對象增加功能,換句話說就是要給一個對象增加功能,但是不能讓這個對象知道,也就是不能去改動這個對象。
物件導向設計的一個基本規則就是:盡量使用對象組合,而不是使用對象繼承。
裝飾者和被裝飾對象有相同的超類型。
可以用一個或多個裝飾者封裝一個對象。
裝飾者可以在所委託被裝飾者的行為之前或之後,加上自己的行為,以達到特定的目的。
對象可以在任何時候被裝飾,所以可以在運行時動態,不限量的用你喜歡的裝飾者來裝飾對象。
裝飾模式中使用繼承的關鍵是想達到裝飾者和被裝飾對象的類型匹配,而不是獲得其行為。
裝飾者一般對組件的客戶是透明的,除非客戶程式依賴於組件的具體類型。在實際項目中可以根據需要為裝飾者添加新的行為,做到“半透明”裝飾者。
適配器模式的用意是改變對象的介面而不一定改變對象的效能,而裝飾模式的用意是保持介面並增加對象的職責。
1.3裝飾模式的結構圖和說明
抽象構件(Component)角色:給出一個抽象介面,以規範準備接收附加責任的對象。
具體構件(Concrete Component)角色:定義一個將要接收附加責任的類。
裝飾(Decorator)角色:持有一個構件(Component)對象的執行個體,並定義一個與抽象構件介面一致的介面。
具體裝飾(Concrete Decorator)角色:負責給構件對象添加上附加的責任。
1.4裝飾模式範例程式碼
package demo21.decorator.example3;/** * 組件對象的介面,可以給這些對象動態添加職責 */public abstract class Component {/** * 樣本方法 */public abstract void operation();}***************************************************************************************************package demo21.decorator.example3;/** * 具體實現組件對象介面的對象 */public class ConcreteComponent extends Component {public void operation() {//相應的功能處理}}**************************************************************************************************package demo21.decorator.example3;/** * 裝飾器介面,維持一個指向組件對象的介面對象, * 並定義一個與組件介面一致的介面 */public abstract class Decorator extends Component {/** * 持有組件對象 */protected Component component;/** * 構造方法,傳入組件對象 * @param component 組件對象 */public Decorator(Component component) {this.component = component;}public void operation() {//轉寄請求給組件對象,可以在轉寄前後執行一些附加動作component.operation();}}**************************************************************************************************package demo21.decorator.example3;/** * 裝飾器的具體實現對象,向組件對象添加職責 */public class ConcreteDecoratorA extends Decorator {public ConcreteDecoratorA(Component component) {super(component);}/** * 添加的狀態 */private String addedState;public String getAddedState() {return addedState;}public void setAddedState(String addedState) {this.addedState = addedState;}public void operation() {//調用父類的方法,可以在調用前後執行一些附加動作//在這裡進行處理的時候,可以使用添加的狀態super.operation();}}**************************************************************************************************package demo21.decorator.example3;/** * 裝飾器的具體實現對象,向組件對象添加職責 */public class ConcreteDecoratorB extends Decorator {public ConcreteDecoratorB(Component component) {super(component);}/** * 需要添加的職責 */private void addedBehavior() {//需要添加的職責實現}public void operation() {//調用父類的方法,可以在調用前後執行一些附加動作super.operation();addedBehavior();}}1.5裝飾模式的本質
動態結合
1.6裝飾模式的優缺點
優點:
比繼承更加靈活
更容易複用功能
簡化高層定義
缺點:
會產生很多細粒度對象
1.7何時選用
如果需要以動態透明的方式給對象添加職責,可以使用裝飾模式
如果不適合使用子類來進行擴充的時候,可以考慮使用裝飾模式
2.舉例說明裝飾模式
最最常見的例子就是java中的I/O資料流了,大家有時間可以看看他的繼承實現結構圖
假如你剛剛買了一輛汽車,是一個裸車,他不符合你的自己的個人化的要求,比如說外觀不好看,輪胎不好,發動機馬力不足等等。那麼你就需要對外表進行裝飾,換換顏色,把車裡面增加一些坐墊。那麼,這裡就需要用到我們剛剛學過的裝飾模式。
執行個體代碼如下,代碼注釋的很清楚,我就不再贅述了
2.1對應Component
package demo21.decorator.example1;/** * 組件對象---車 * * @author 王玉超 * */public abstract class Car {/** * 行駛功能 */public abstract void run();}2.2對應ConcreteComponent
package demo21.decorator.example1;/** * 具體的車,假如是奧迪 * * @author 王玉超 * */public class AudiCar extends Car {@Overridepublic void run() {System.out.println("奧迪行駛在馬路上...");}}2.3對應Decorator
package demo21.decorator.example1;/** * 裝飾器介面,維持一個指向組件對象的介面對象, 並定義一個與組件介面一致的介面,這是是裝飾的介面 */public abstract class Decorator extends Car {/** * 持有組件對象 */private Car car;/** * 構造方法,傳入組件對象 * * @param car * 組件對象 */public Decorator(Car car) {this.car = car;}@Overridepublic void run() {// 轉寄給component組件對象carthis.car.run();}}2.4對應 ConcreteDecoratorA
package demo21.decorator.example1;/** * 裝飾器的具體實現對象,向組件對象添加職責 ,這個是添加顏色的車 */public class AddColorCar extends Decorator {public AddColorCar(Car car) {super(car);}/** * 添加的狀態,更改外觀 */private String face;public void setFace(String face) {this.face = face;}public void addColor() {System.out.println("我添加了顏色" + this.face);}@Overridepublic void run() {// 調用父類的方法,可以在調用前後執行一些附加動作// 在這裡進行處理的時候,可以使用添加的狀態super.run();this.addColor();}}2.5對應 ConcreteDecoratorB
package demo21.decorator.example1;/** * 裝飾器的具體實現對象,向組件對象添加職責 ,這個是添加坐墊的車 */public class AddSeatCar extends Decorator {public AddSeatCar(Car car) {super(car);}/** * 添加的狀態,添加坐墊 */private String seat;public void setSeat(String seat) {this.seat = seat;}public void addSeat() {System.out.println("我添加了坐墊" + this.seat);}@Overridepublic void run() {// 調用父類的方法,可以在調用前後執行一些附加動作// 在這裡進行處理的時候,可以使用添加的狀態super.run();this.addSeat();}}2.6用戶端使用
package demo21.decorator.example1;public class Client {public static void main(String[] args) {// 被裝飾的對象Car car = new AudiCar();// 裝飾者對象Decorator colorCar = new AddColorCar(car);((AddColorCar) colorCar).setFace("紅色");Decorator seatCar = new AddSeatCar(colorCar);((AddSeatCar) seatCar).setSeat("夏天清涼坐墊");// 汽車跑起來吧seatCar.run();}}
如何看完以後,還是不明白,我建議讀者看看java I/O資料流裡面的各種類,以及他們之間的關係,或許就明白了。