詳解Java設計模式中的裝飾模式
一、裝飾模式的定義和特點
在軟件開發(fā)過程中,有時想用一些現(xiàn)存的組件。這些組件可能只是完成了一些核心功能。但在不改變其結構的情況下,可以動態(tài)地擴展其功能。所有這些都可以釆用裝飾器模式來實現(xiàn)。
就像我們做菜,需要用到調料,菜,刀,火等一系列抽象的組件來最終完成一道菜。
裝飾模式的定義:
指在不改變現(xiàn)有對象結構的情況下,動態(tài)地給該對象增加一些職責(即增加其額外功能)的模式,它屬于對象結構型模式。就增加功能來說,裝飾模式比生成子類更加靈活。
特點:
- 裝飾器是繼承的有力補充,比繼承靈活,在不改變原有對象的情況下,動態(tài)的給一個對象擴展功能,即插即用
- 通過使用不用裝飾類及這些裝飾類的排列組合,可以實現(xiàn)不同效果
- 裝飾器模式完全遵守開閉原則
缺點
裝飾器模式會增加許多子類,過度使用會增加程序得復雜性。
二、裝飾模式的結構
裝飾模式的結構一般包含以下幾個角色
1. 抽象構件(Component)角色:定義一個抽象接口以規(guī)范準備接收附加責任的對象。
2. 具體構件(ConcreteComponent)角色:實現(xiàn)抽象構件,通過裝飾角色為其添加一些職責。
3. 抽象裝飾(Decorator)角色:繼承抽象構件,并包含具體構件的實例,可以通過其子類擴展具體構件的功能。
4. 具體裝飾(ConcreteDecorator)角色:實現(xiàn)抽象裝飾的相關方法,并給具體構件對象添加附加的責任。
圖示

三、咖啡點單案例演示
有一個需求,點一杯咖啡需要咖啡,材料等等,這個案例就很適合裝飾模式,類似于穿衣,點餐,買包子,等等,我們怎么把他設計成裝飾模式呢?
看類圖

這個結構就是我已經設計好的一個裝飾模式的類圖,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 Coffee
* @date 2021/12/28 10:31
* @Description 咖啡類
*/
public class Coffee extends Drink{
@Override
public float cost() {
return 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類即可。
四、總結
裝飾模式是為已有的功能動態(tài)的添加更多功能的一種方式,當系統(tǒng)需要新功能的時候,向舊的類中添加新的代碼,這些新加的代碼通常裝飾了原有類的核心職責或主要行為。
優(yōu)點:
把類中裝飾功能從類中移除,這樣可以簡化原來的類,
有效的把類的核心職責和裝飾功能分開了,而且可以去除相關類中的重復裝飾邏輯
可代替繼承。?
到此這篇關于詳解Java設計模式中的裝飾模式的文章就介紹到這了,更多相關Java裝飾模式內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Springboot中配置Mail和普通mail的實現(xiàn)方式
這篇文章主要介紹了Springboot中配置Mail和普通mail的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03
分別在Groovy和Java中創(chuàng)建并初始化映射的不同分析
這篇文章主要為大家介紹了分別在Groovy和Java中創(chuàng)建并初始化映射的不同分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-03-03
SpringBoot淺析安全管理之Spring Security配置
安全管理是軟件系統(tǒng)必不可少的的功能。根據經典的“墨菲定律”——凡是可能,總會發(fā)生。如果系統(tǒng)存在安全隱患,最終必然會出現(xiàn)問題,這篇文章主要介紹了SpringBoot安全管理Spring Security基本配置2022-08-08
Springboot并發(fā)調優(yōu)之大事務和長連接
這篇文章主要介紹了Springboot并發(fā)調優(yōu)之大事務和長連接,重點分享長事務以及長連接導致的并發(fā)排查和優(yōu)化思路和示例,具有一定的參考價值,感興趣的可以了解一下2022-05-05
mybatis foreach 循環(huán) list(map)實例
這篇文章主要介紹了mybatis foreach 循環(huán) list(map)實例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
關于idea引入spring boot <parent></parent>父依賴標紅問題
這篇文章主要介紹了idea引入spring boot <parent></parent>父依賴標紅問題,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10
mybatis水平分表實現(xiàn)動態(tài)表名的項目實例
本文主要介紹了mybatis水平分表實現(xiàn)動態(tài)表名的項目實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-07-07

