Java裝飾者模式的深入瞭解
一、裝飾模式的定義和特點
在軟件開發過程中,有時想用一些現存的組件。這些組件可能隻是完成瞭一些核心功能。但在不改變其結構的情況下,可以動態地擴展其功能。所有這些都可以釆用裝飾器模式來實現。
就像我們做菜,需要用到調料,菜,刀,火等一系列抽象的組件來最終完成一道菜。
裝飾模式的定義:
指在不改變現有對象結構的情況下,動態地給該對象增加一些職責(即增加其額外功能)的模式,它屬於對象結構型模式。就增加功能來說,裝飾模式比生成子類更加靈活。
特點:
裝飾器是繼承的有力補充,比繼承靈活,在不改變原有對象的情況下,動態的給一個對象擴展功能,即插即用
通過使用不用裝飾類及這些裝飾類的排列組合,可以實現不同效果
裝飾器模式完全遵守開閉原則
缺點
裝飾器模式會增加許多子類,過度使用會增加程序得復雜性。
二、裝飾模式的結構
裝飾模式的結構一般包含以下幾個角色
1. 抽象構件(Component)角色:定義一個抽象接口以規范準備接收附加責任的對象。
2. 具體構件(ConcreteComponent)角色:實現抽象構件,通過裝飾角色為其添加一些職責。
3. 抽象裝飾(Decorator)角色:繼承抽象構件,並包含具體構件的實例,可以通過其子類擴展具體構件的功能。
4. 具體裝飾(ConcreteDecorator)角色:實現抽象裝飾的相關方法,並給具體構件對象添加附加的責任。
圖示
三、咖啡點單案例演示
有一個需求,點一杯咖啡需要咖啡,材料等等,這個案例就很適合裝飾模式,類似於穿衣,點餐,買包子,等等,我們怎麼把他設計成裝飾模式呢?
看類圖
這個結構就是我已經設計好的一個裝飾模式的類圖,idea自動生成的,這裡的Drink就是我們上面說的抽象構建角色,裝飾者是Decorator,他是一個抽象裝飾,下面他的子類就是具體的裝飾者,那麼具體構建中間我們提供瞭一個中間構建,提供瞭coffee的一些共性,可以放在這裡,用的時候直接繼承,他的下面就是相應的具體構件,具體被裝飾者角色,裝飾者與被裝飾者共同繼承自component抽象構件,需要用到裝飾的就是我們點一杯咖啡,用裝飾去包裹即可,層層包裹,案例如下:
比如我要點一份加糖加奶的拿鐵咖啡
代碼實例:
component抽象構件角色:
package com.decoratorPattern.starBucks; /** * @author wang * @version 1.0 * @packageName com.decoratorPattern.starBucks * @className Drink * @date 2021/12/28 10:28 * @Description 飲料構件類抽象component */ public abstract class Drink { private String description; private float price = 0.0f; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } /** * @Date 2021/12/28 10:30 * @Param * @Return float * @MetodName cost * @Author wang * @Description 計算花費,訂單價格 */ public abstract float cost(); }
裝飾者類:
package com.decoratorPattern.starBucks; /** * @author wang * @version 1.0 * @packageName com.decoratorPattern.starBucks * @className Decorator * @date 2021/12/28 10:40 * @Description 裝飾者定義類,配料 */ public class Decorator extends Drink { private Drink drink; /** * @param drink * @Date 2021/12/28 10:42 * @Param * @Return null * @MetodName Decorator * @Author wang * @Description 傳入一個被裝飾者,由裝飾者進行裝飾 */ public Decorator(Drink drink) { this.drink = drink; } /** * @Date 2021/12/28 10:43 * @Param * @Return float * @MetodName cost * @Author wang * @Description 裝飾者的價格加上被裝飾者的價格 */ @Override public float cost() { return super.getPrice() + drink.cost(); } /** * @Date 2021/12/28 10:44 * @Param * @Return String * @MetodName getDescription * @Author wang * @Description 輸出訂單信息,包含裝飾者,裝飾者的價格,以及被裝飾者的信息 */ @Override public String getDescription() { return drink.getDescription() + "\n加入的材料:" + super.getDescription() + "\t材料價格:" + super.getPrice() ; } }
裝飾者類:
package com.decoratorPattern.starBucks; /** * @author wang * @version 1.0 * @packageName com.decoratorPattern.starBucks * @className Decorator * @date 2021/12/28 10:40 * @Description 裝飾者定義類,配料 */ public class Decorator extends Drink { private Drink drink; /** * @param drink * @Date 2021/12/28 10:42 * @Param * @Return null * @MetodName Decorator * @Author wang * @Description 傳入一個被裝飾者,由裝飾者進行裝飾 */ public Decorator(Drink drink) { this.drink = drink; } /** * @Date 2021/12/28 10:43 * @Param * @Return float * @MetodName cost * @Author wang * @Description 裝飾者的價格加上被裝飾者的價格 */ @Override public float cost() { return super.getPrice() + drink.cost(); } /** * @Date 2021/12/28 10:44 * @Param * @Return String * @MetodName getDescription * @Author wang * @Description 輸出訂單信息,包含裝飾者,裝飾者的價格,以及被裝飾者的信息 */ @Override public String getDescription() { return drink.getDescription() + "\n加入的材料:" + super.getDescription() + "\t材料價格:" + super.getPrice() ; } }
具體構件類:拿鐵
package com.decoratorPattern.starBucks; /** * @author wang * @version 1.0 * @packageName com.decoratorPattern.starBucks * @className latte * @date 2021/12/28 10:32 * @Description 拿鐵咖啡實類,被裝飾者 */ public class Latte extends Coffee{ public Latte() { setDescription("拿鐵咖啡"); setPrice(15.0f); } }
具體構件類:摩卡
package com.decoratorPattern.starBucks; /** * @author wang * @version 1.0 * @packageName com.decoratorPattern.starBucks * @className Mocha * @date 2021/12/28 10:36 * @Description 摩卡咖啡實類,被裝飾者 */ public class Mocha extends Coffee { public Mocha() { setDescription("摩卡咖啡"); setPrice(12.2f); } }
其他同上,不過多展示
具體裝飾類:牛奶
package com.decoratorPattern.starBucks; /** * @author wang * @version 1.0 * @packageName com.decoratorPattern.starBucks * @className Milk * @date 2021/12/28 10:47 * @Description 牛奶調味品,具體裝飾者 */ public class Milk extends Decorator{ /** * @param drink * @Date 2021/12/28 10:42 * @Param * @Return null * @MetodName Decorator * @Author wang * @Description 傳入一個被裝飾者,由裝飾者進行裝飾 */ public Milk(Drink drink) { super(drink); setDescription("牛奶"); setPrice(1.0f); } }
具體裝飾:糖
package com.decoratorPattern.starBucks; /** * @author wang * @version 1.0 * @packageName com.decoratorPattern.starBucks * @className sugar * @date 2021/12/28 10:50 * @Description 糖,裝飾者 */ public class Sugar extends Decorator{ /** * @param drink * @Date 2021/12/28 10:42 * @Param * @Return null * @MetodName Decorator * @Author wang * @Description 傳入一個被裝飾者,由裝飾者進行裝飾 */ public Sugar(Drink drink) { super(drink); setDescription("糖"); setPrice(0.5f); } }
訂單測試代碼:
package com.decoratorPattern.starBucks; /** * @author wang * @version 1.0 * @packageName com.decoratorPattern.starBucks * @className OrderTest * @date 2021/12/28 10:51 * @Description 前臺訂單類 */ public class OrderTest { public static void main(String[] args) { //點一份加糖加奶的拿鐵咖啡 System.out.println("+++++++沒加任何東西+++++++"); Drink latte = new Latte(); System.out.println("當前總價:" + latte.cost()); System.out.println("coffee:" +latte.getDescription()); //加糖 System.out.println("+++++++加糖後+++++++"); latte = new Sugar(latte); System.out.println("當前總價:" + latte.cost()); System.out.println("coffee:" + latte.getDescription()); System.out.println("+++++++加奶後+++++++"); latte = new Milk(latte); System.out.println("當前總價:" + latte.cost()); System.out.println("coffee:" +latte.getDescription()); } } /** * +++++++沒加任何東西+++++++ * 當前總價:15.0 * coffee:拿鐵咖啡 * +++++++加糖後+++++++ * 當前總價:15.5 * coffee:拿鐵咖啡 * 加入的材料:糖 材料價格:0.5 * +++++++加奶後+++++++ * 當前總價:16.5 * coffee:拿鐵咖啡 * 加入的材料:糖 材料價格:0.5 * 加入的材料:牛奶 材料價格:1.0 * * Process finished with exit code 0 */
綜上, 如果我們需要新的咖啡種類或者是新的調料,隻需要新增類去繼承coffee或者decorator類即可。
四、總結
裝飾模式是為已有的功能動態的添加更多功能的一種方式,當系統需要新功能的時候,向舊的類中添加新的代碼,這些新加的代碼通常裝飾瞭原有類的核心職責或主要行為。
優點:
把類中裝飾功能從類中移除,這樣可以簡化原來的類,
有效的把類的核心職責和裝飾功能分開瞭,而且可以去除相關類中的重復裝飾邏輯
可代替繼承。
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!