詳解Java設(shè)計(jì)模式中的裝飾模式
一、裝飾模式的定義和特點(diǎn)
在軟件開發(fā)過程中,有時(shí)想用一些現(xiàn)存的組件。這些組件可能只是完成了一些核心功能。但在不改變其結(jié)構(gòu)的情況下,可以動(dòng)態(tài)地?cái)U(kuò)展其功能。所有這些都可以釆用裝飾器模式來實(shí)現(xiàn)。
就像我們做菜,需要用到調(diào)料,菜,刀,火等一系列抽象的組件來最終完成一道菜。
裝飾模式的定義:
指在不改變現(xiàn)有對(duì)象結(jié)構(gòu)的情況下,動(dòng)態(tài)地給該對(duì)象增加一些職責(zé)(即增加其額外功能)的模式,它屬于對(duì)象結(jié)構(gòu)型模式。就增加功能來說,裝飾模式比生成子類更加靈活。
特點(diǎn):
- 裝飾器是繼承的有力補(bǔ)充,比繼承靈活,在不改變?cè)袑?duì)象的情況下,動(dòng)態(tài)的給一個(gè)對(duì)象擴(kuò)展功能,即插即用
- 通過使用不用裝飾類及這些裝飾類的排列組合,可以實(shí)現(xiàn)不同效果
- 裝飾器模式完全遵守開閉原則
缺點(diǎn)
裝飾器模式會(huì)增加許多子類,過度使用會(huì)增加程序得復(fù)雜性。
二、裝飾模式的結(jié)構(gòu)
裝飾模式的結(jié)構(gòu)一般包含以下幾個(gè)角色
1. 抽象構(gòu)件(Component)角色:定義一個(gè)抽象接口以規(guī)范準(zhǔn)備接收附加責(zé)任的對(duì)象。
2. 具體構(gòu)件(ConcreteComponent)角色:實(shí)現(xiàn)抽象構(gòu)件,通過裝飾角色為其添加一些職責(zé)。
3. 抽象裝飾(Decorator)角色:繼承抽象構(gòu)件,并包含具體構(gòu)件的實(shí)例,可以通過其子類擴(kuò)展具體構(gòu)件的功能。
4. 具體裝飾(ConcreteDecorator)角色:實(shí)現(xiàn)抽象裝飾的相關(guān)方法,并給具體構(gòu)件對(duì)象添加附加的責(zé)任。
圖示
三、咖啡點(diǎn)單案例演示
有一個(gè)需求,點(diǎn)一杯咖啡需要咖啡,材料等等,這個(gè)案例就很適合裝飾模式,類似于穿衣,點(diǎn)餐,買包子,等等,我們?cè)趺窗阉O(shè)計(jì)成裝飾模式呢?
看類圖
這個(gè)結(jié)構(gòu)就是我已經(jīng)設(shè)計(jì)好的一個(gè)裝飾模式的類圖,idea自動(dòng)生成的,這里的Drink就是我們上面說的抽象構(gòu)建角色,裝飾者是Decorator,他是一個(gè)抽象裝飾,下面他的子類就是具體的裝飾者,那么具體構(gòu)建中間我們提供了一個(gè)中間構(gòu)建,提供了coffee的一些共性,可以放在這里,用的時(shí)候直接繼承,他的下面就是相應(yīng)的具體構(gòu)件,具體被裝飾者角色,裝飾者與被裝飾者共同繼承自component抽象構(gòu)件,需要用到裝飾的就是我們點(diǎn)一杯咖啡,用裝飾去包裹即可,層層包裹,案例如下:
比如我要點(diǎn)一份加糖加奶的拿鐵咖啡
代碼實(shí)例:
component抽象構(gòu)件角色:
package com.decoratorPattern.starBucks; /** * @author wang * @version 1.0 * @packageName com.decoratorPattern.starBucks * @className Drink * @date 2021/12/28 10:28 * @Description 飲料構(gòu)件類抽象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 計(jì)算花費(fèi),訂單價(jià)格 */ 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 傳入一個(gè)被裝飾者,由裝飾者進(jìn)行裝飾 */ public Decorator(Drink drink) { this.drink = drink; } /** * @Date 2021/12/28 10:43 * @Param * @Return float * @MetodName cost * @Author wang * @Description 裝飾者的價(jià)格加上被裝飾者的價(jià)格 */ @Override public float cost() { return super.getPrice() + drink.cost(); } /** * @Date 2021/12/28 10:44 * @Param * @Return String * @MetodName getDescription * @Author wang * @Description 輸出訂單信息,包含裝飾者,裝飾者的價(jià)格,以及被裝飾者的信息 */ @Override public String getDescription() { return drink.getDescription() + "\n加入的材料:" + super.getDescription() + "\t材料價(jià)格:" + 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(); } }
具體構(gòu)件類:拿鐵
package com.decoratorPattern.starBucks; /** * @author wang * @version 1.0 * @packageName com.decoratorPattern.starBucks * @className latte * @date 2021/12/28 10:32 * @Description 拿鐵咖啡實(shí)類,被裝飾者 */ public class Latte extends Coffee{ public Latte() { setDescription("拿鐵咖啡"); setPrice(15.0f); } }
具體構(gòu)件類:摩卡
package com.decoratorPattern.starBucks; /** * @author wang * @version 1.0 * @packageName com.decoratorPattern.starBucks * @className Mocha * @date 2021/12/28 10:36 * @Description 摩卡咖啡實(shí)類,被裝飾者 */ 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 牛奶調(diào)味品,具體裝飾者 */ public class Milk extends Decorator{ /** * @param drink * @Date 2021/12/28 10:42 * @Param * @Return null * @MetodName Decorator * @Author wang * @Description 傳入一個(gè)被裝飾者,由裝飾者進(jìn)行裝飾 */ 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 傳入一個(gè)被裝飾者,由裝飾者進(jìn)行裝飾 */ public Sugar(Drink drink) { super(drink); setDescription("糖"); setPrice(0.5f); } }
訂單測(cè)試代碼:
package com.decoratorPattern.starBucks; /** * @author wang * @version 1.0 * @packageName com.decoratorPattern.starBucks * @className OrderTest * @date 2021/12/28 10:51 * @Description 前臺(tái)訂單類 */ public class OrderTest { public static void main(String[] args) { //點(diǎn)一份加糖加奶的拿鐵咖啡 System.out.println("+++++++沒加任何東西+++++++"); Drink latte = new Latte(); System.out.println("當(dāng)前總價(jià):" + latte.cost()); System.out.println("coffee:" +latte.getDescription()); //加糖 System.out.println("+++++++加糖后+++++++"); latte = new Sugar(latte); System.out.println("當(dāng)前總價(jià):" + latte.cost()); System.out.println("coffee:" + latte.getDescription()); System.out.println("+++++++加奶后+++++++"); latte = new Milk(latte); System.out.println("當(dāng)前總價(jià):" + latte.cost()); System.out.println("coffee:" +latte.getDescription()); } } /** * +++++++沒加任何東西+++++++ * 當(dāng)前總價(jià):15.0 * coffee:拿鐵咖啡 * +++++++加糖后+++++++ * 當(dāng)前總價(jià):15.5 * coffee:拿鐵咖啡 * 加入的材料:糖 材料價(jià)格:0.5 * +++++++加奶后+++++++ * 當(dāng)前總價(jià):16.5 * coffee:拿鐵咖啡 * 加入的材料:糖 材料價(jià)格:0.5 * 加入的材料:牛奶 材料價(jià)格:1.0 * * Process finished with exit code 0 */
綜上, 如果我們需要新的咖啡種類或者是新的調(diào)料,只需要新增類去繼承coffee或者decorator類即可。
四、總結(jié)
裝飾模式是為已有的功能動(dòng)態(tài)的添加更多功能的一種方式,當(dāng)系統(tǒng)需要新功能的時(shí)候,向舊的類中添加新的代碼,這些新加的代碼通常裝飾了原有類的核心職責(zé)或主要行為。
優(yōu)點(diǎn):
把類中裝飾功能從類中移除,這樣可以簡(jiǎn)化原來的類,
有效的把類的核心職責(zé)和裝飾功能分開了,而且可以去除相關(guān)類中的重復(fù)裝飾邏輯
可代替繼承。?
到此這篇關(guān)于詳解Java設(shè)計(jì)模式中的裝飾模式的文章就介紹到這了,更多相關(guān)Java裝飾模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot中配置Mail和普通mail的實(shí)現(xiàn)方式
這篇文章主要介紹了Springboot中配置Mail和普通mail的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03分別在Groovy和Java中創(chuàng)建并初始化映射的不同分析
這篇文章主要為大家介紹了分別在Groovy和Java中創(chuàng)建并初始化映射的不同分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03SpringBoot淺析安全管理之Spring Security配置
安全管理是軟件系統(tǒng)必不可少的的功能。根據(jù)經(jīng)典的“墨菲定律”——凡是可能,總會(huì)發(fā)生。如果系統(tǒng)存在安全隱患,最終必然會(huì)出現(xiàn)問題,這篇文章主要介紹了SpringBoot安全管理Spring Security基本配置2022-08-08Springboot并發(fā)調(diào)優(yōu)之大事務(wù)和長(zhǎng)連接
這篇文章主要介紹了Springboot并發(fā)調(diào)優(yōu)之大事務(wù)和長(zhǎng)連接,重點(diǎn)分享長(zhǎng)事務(wù)以及長(zhǎng)連接導(dǎo)致的并發(fā)排查和優(yōu)化思路和示例,具有一定的參考價(jià)值,感興趣的可以了解一下2022-05-05mybatis foreach 循環(huán) list(map)實(shí)例
這篇文章主要介紹了mybatis foreach 循環(huán) list(map)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03java關(guān)于list集合做刪除操作時(shí)的坑及解決
這篇文章主要介紹了java關(guān)于list集合做刪除操作時(shí)的坑及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11關(guān)于idea引入spring boot <parent></parent>父依賴標(biāo)紅問題
這篇文章主要介紹了idea引入spring boot <parent></parent>父依賴標(biāo)紅問題,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10mybatis水平分表實(shí)現(xiàn)動(dòng)態(tài)表名的項(xiàng)目實(shí)例
本文主要介紹了mybatis水平分表實(shí)現(xiàn)動(dòng)態(tài)表名的項(xiàng)目實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07