日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

装饰者模式讲解

發(fā)布時間:2024/4/13 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 装饰者模式讲解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
這個模式比外觀模式稍微難了一點,但也不是太難,也是可以理解的,那現(xiàn)在我們引入一個場景,下班晚了,樓下有賣煎餅的,然后買個煎餅,在單位的茶水間,加個蛋,有時候加個腸,那我們現(xiàn)在就想一下,商家在賣這個煎餅,加蛋的時候,加香腸的時候,這個價格是怎么計算的,首先我們在這里創(chuàng)建一個裝飾者,我們先寫一個版本叫做v1 package com.learn.design.pattern.structural.decorator.v1;/*** 我們現(xiàn)在創(chuàng)建一個煎餅類* 他有兩個方法* * * @author Leon.Sun**/ public class Battercake {/*** 一個是獲取描述getDesc* * 我們把它寫成protected* 有的人喜歡在吃煎餅的時候加一個雞蛋* 再加一根香腸* * * @return*/protected String getDesc(){return "煎餅";}/*** 還有一個方法cost* 他的價格消費多少* 假設這個煎餅8元* 現(xiàn)在商家創(chuàng)建一個煎餅類* 我在賣的時候可以賣一個煎餅* 我也可以賣加蛋的煎餅* 那我們再創(chuàng)建一個類* * * @return*/protected int cost(){return 8;}} package com.learn.design.pattern.structural.decorator.v1;/*** 加蛋的煎餅* 繼承了Battercake* 這里我們重寫一下父類的方法* 因為權(quán)限在子類中重寫* * * * @author Leon.Sun**/ public class BattercakeWithEgg extends Battercake {/*** 首先獲取父類獲得一個描述* 加上" 加一個雞蛋"* * * * */@Overridepublic String getDesc() {return super.getDesc()+" 加一個雞蛋";}/*** 價格也是* 煎餅賣8元* 加一個蛋加1塊* 這個時候我們看一下* 對于權(quán)限的一個限制* 里面也說一下* * * */@Overridepublic int cost() {return super.cost()+1;} } package com.learn.design.pattern.structural.decorator.v1;/*** 這個類呢是加一個雞蛋* 再加一根香腸* 我只需要讓他繼承加蛋的煎餅就可以了* 同理重寫* 這兩個方法* * * @author Leon.Sun**/ public class BattercakeWithEggSausage extends BattercakeWithEgg {/*** 他調(diào)用super之后呢* 他繼續(xù)掉super* 加上后邊" 加一根香腸"* * */@Overridepublic String getDesc() {return super.getDesc()+ " 加一根香腸";}/*** 香腸兩塊錢* 加2* 咱們寫一個測試類* * */@Overridepublic int cost() {return super.cost()+2;} } package com.learn.design.pattern.structural.decorator.v1;/*** * @author Leon.Sun**/ public class Test {public static void main(String[] args) {/*** 先new一個普通的* * */Battercake battercake = new Battercake();/*** 直接輸出銷售價格* 前面加上他的描述battercake.getDesc()* * */System.out.println(battercake.getDesc()+" 銷售價格:"+battercake.cost());/*** battercakeWithEgg* * */Battercake battercakeWithEgg = new BattercakeWithEgg();System.out.println(battercakeWithEgg.getDesc()+" 銷售價格:"+battercakeWithEgg.cost());/*** 加腸的也是同理* 這三個小伙伴都得到了滿足* 吃了一個煎餅* 吃了一個加雞蛋的煎餅* 也有一個加了雞蛋加了香腸的煎餅* 這個時候又來了一個小伙伴* 我要吃一個煎餅* 加兩個雞蛋* 加兩根香腸* 這個時候老板有點迷茫* 那我沒有加兩個雞蛋加兩根香腸的類* 那現(xiàn)在我這個系統(tǒng)算不出來* 這個應該賣多少錢的* 這個沒有得到滿足* 商家也沒有掙到錢* 沒有賣出去* 因為系統(tǒng)不支持* 那這個UML非常簡單* * */Battercake battercakeWithEggSausage = new BattercakeWithEggSausage();System.out.println(battercakeWithEggSausage.getDesc()+" 銷售價格:"+battercakeWithEggSausage.cost());} }

就是一個單純的繼承,那這個擴展性還是非常有限制的,我們想一下對于煎餅的組合呢,非常非常多,加一個雞蛋,加兩個雞蛋,加10個雞蛋的都有,那我們下邊的子類呢,不會發(fā)生類爆炸的情況嗎,如果按照現(xiàn)在的這種寫法來擴展的話,肯定會發(fā)生的,那么這個時候我們就要考慮,怎么才能讓我們的代碼更優(yōu)雅,我們創(chuàng)建一個V2版本 我們現(xiàn)在要對煎餅進行抽象,所謂的裝飾者模式,是說我們要有一個抽象的實體類,還要有確定的實體類,同時還需要有抽象的裝飾者,還要有確定的裝飾者,那在這個場景中,裝飾的主體是煎餅,裝飾者是雞蛋,還有香腸,在裝飾者模式中,四個角色在這個業(yè)務場景,是比較全的,抽象的食物,或者我們創(chuàng)建一個抽象的煎餅,因為這個煎餅具體的時候,怎么樣的還沒有確定,然后是實體的煎餅,緊接著是抽象的裝飾者,具體的裝飾者,香腸和雞蛋,那我們現(xiàn)在創(chuàng)建一個抽象的煎餅,用A開頭代表抽象類

現(xiàn)在我們來看一下整體的UML,是非常清晰的,首先最上層抽象煎餅,所以呢是一個接口,或者抽象類,但是這個抽象角色呢,并不是必須的,而BatterCake這個煎餅是具體的,要被裝飾的實體類,要被裝飾的對象也可以有多個,那AbstractDecorator就是抽象的裝飾角色,而下邊的雞蛋和香腸,是具體的裝飾角色,負責給這個煎餅擴展功能,那我們現(xiàn)在來run一下,新建Test package com.learn.design.pattern.structural.decorator.v2;/*** 前邊加上abstract* 那這個方法我們直接拿過來* 前面要加上abstract* 因為在抽象類里面* 這兩個方法要做成抽象方法* 那這個要被裝飾的實體呢* 我們也要聲明一個* 那就是實體煎餅* * * @author Leon.Sun**/ public abstract class ABattercake {protected abstract String getDesc();protected abstract int cost();} package com.learn.design.pattern.structural.decorator.v2;/*** 他要繼承ABattercake* 實現(xiàn)方法* 現(xiàn)在重要的裝飾者就登場了* 首先我們讓抽象的裝飾者* 也繼承這個抽象的實體* * * @author Leon.Sun**/ public class Battercake extends ABattercake {@Overrideprotected String getDesc() {return "煎餅";}@Overrideprotected int cost() {return 8;} } package com.learn.design.pattern.structural.decorator.v2;/*** 創(chuàng)建AbstractDecorator這個類* 他繼承ABattercake這個抽象類* 然后實現(xiàn)里面的方法* 讓AbstractDecorator來繼承ABattercake* 很簡單* 現(xiàn)在AbstractDecorator和實體的Battercake他們都是抽象類的子類* 那這個時候我們可以想象一下* 我如何讓這兩個子類建立關系呢* 我們可以通過它繼承的父類* 來達到這個目的* * AbstractDecorator這個類現(xiàn)在并不是抽象類* 但是也能完成擴展的目的* 那為什么要加一層抽象的裝飾者呢* 很簡單* 我們來寫一下* 現(xiàn)在把它改成抽象的類* 我們寫個方法* * * * @author Leon.Sun**/ public abstract class AbstractDecorator extends ABattercake {/*** 我們讓父類來聲明一個ABattercake* 這個抽象的煎餅放到這里了* * */private ABattercake aBattercake;/*** 然后就是他的構(gòu)造器* 通過構(gòu)造器把這個抽象的煎餅放進來* 那現(xiàn)在我們看一下* 我們可以放抽象的煎餅進來* 就可以放實體的煎餅進來* 那這兩個也非常簡單* 因為我們已經(jīng)把煎餅放進來了* 我們在調(diào)用這個抽象的裝飾者的時候* 其實是把這個行為委托給抽象的煎餅來執(zhí)行的* 這個時候我們就要實現(xiàn)實體的裝飾者類* 我們有一個蛋裝飾者* * * @param aBattercake*/public AbstractDecorator(ABattercake aBattercake) {this.aBattercake = aBattercake;}/*** 我們想象一下* 如果作為抽象的裝飾者* 能夠保證子類實現(xiàn)某個方法的話* 那么這個抽象的裝飾者呢* 放到這里才會有意義* 所以這個類是不是抽象的類* 還要看具體的業(yè)務場景* 那在剛剛講的這個場景當中呢* 他不是抽象的裝飾者* 也是OK的* 因為并沒有抽象方法* 新建的doSomething* 那如果我們創(chuàng)建了這個抽象方法* 那我們這個類應該是抽象類* 這樣對于子類來說* 我們來看一下這個類* 是必須要實現(xiàn)doSomething方法的* * * */protected abstract void doSomething();@Overrideprotected String getDesc() {return this.aBattercake.getDesc();}@Overrideprotected int cost() {return this.aBattercake.cost();} } package com.learn.design.pattern.structural.decorator.v2;/*** EggDecorator這個類也是同理* * * @author Leon.Sun**/ public class EggDecorator extends AbstractDecorator {public EggDecorator(ABattercake aBattercake) {super(aBattercake);}/*** 那具體這個方法如何使用* 還是要看具體的業(yè)務場景* 例如老板在做煎餅* 加蛋的時候會有一個小動作* 又或者加腸的時候* 也有一些特定的小動作* 而這兩個小動作呢* 分別屬于各自的裝飾者實現(xiàn)* 那這個時候?qū)τ趦蓚€實體的裝飾者的父類* 用抽象的裝飾者* 才會比較有意義* 具體最上層的裝飾者* 是否使用裝飾類* 要根據(jù)具體的業(yè)務場景* 這個呢并沒有硬規(guī)定* 那我們再看一下圖* * */@Overrideprotected void doSomething() {}/*** 描述寫一下* " 加一個雞蛋"* * */@Overrideprotected String getDesc() {return super.getDesc()+" 加一個雞蛋";}/*** 一個雞蛋一元錢* * */@Overrideprotected int cost() {return super.cost()+1;} } package com.learn.design.pattern.structural.decorator.v2;/*** 首先用香腸的實體裝飾者類* 繼承抽象的裝飾者類* 然后實現(xiàn)這個默認的構(gòu)造器* 那為什么要實現(xiàn)這個構(gòu)造器呢* 很簡單* 這個父類已經(jīng)沒有無參構(gòu)造器了* 因為我們聲明了一個有參構(gòu)造器* 然后重寫父類的這兩個方法* 很簡單* * * @author Leon.Sun**/ public class SausageDecorator extends AbstractDecorator{public SausageDecorator(ABattercake aBattercake) {super(aBattercake);}@Overrideprotected void doSomething() {}/*** " 加一根香腸"* * */@Overrideprotected String getDesc() {return super.getDesc()+" 加一根香腸";}/*** 香腸賣兩元* * */@Overrideprotected int cost() {return super.cost()+2;} } package com.learn.design.pattern.structural.decorator.v2;/*** * @author Leon.Sun**/ public class Test {public static void main(String[] args) {/*** 我們聲明一個抽象的煎餅* 剛剛說的第四個小伙伴來買這個煎餅* 老板給他做* 程序也能跑* 怎么跑呢* 看一下* * */ABattercake aBattercake;/*** 首先我們要給一個煎餅* new一個Battercake* * */aBattercake = new Battercake();/*** 這個時候注意* 他要兩個雞蛋* 我們用雞蛋裝飾者來包裝一下這個煎餅* 然后呢* 再返回這個被包裝的這個煎餅* 因為這個裝飾者他繼承抽象的裝飾者* 而抽象的裝飾者呢* 看一下UML* 他繼承抽象的煎餅* 所以他的類型是可以被抽象的煎餅接收的* 同時我們注意UML里面的這個組合* 一個抽象的裝飾者里面有一個抽象的煎餅* * * */aBattercake = new EggDecorator(aBattercake);/*** 這個時候小伙伴還需要一個雞蛋* 那就加一個雞蛋* * */aBattercake = new EggDecorator(aBattercake);/*** 然后這個小伙伴還是覺得有點餓* 加一根香腸* * */aBattercake = new SausageDecorator(aBattercake);/*** 這個時候我們就要打印一下* 老板煎餅也做完了* 價格從這個程序里跑了一下* 我們看一下結(jié)果* 煎餅* 加一個雞蛋* 又加一個雞蛋* 加一根香腸* 銷售價格8元加1元加1元加兩元* 12元* 那這樣通過裝飾者* 就把這個煎餅裝飾出來了* 那現(xiàn)在講到這里* 我們看一下前面悄悄地埋了一個伏筆* 我們看一下抽象的裝飾者類* * */System.out.println(aBattercake.getDesc()+" 銷售價格:"+aBattercake.cost());} } 它是一個AbstractDecorator,那裝飾者模式在實際的應用場景,也比較多,當然怎么用還是要看應用模型的,如果這個業(yè)務模型抽象可以的話,打個比方,假設有一個訂單,而這個訂單是一個旅行訂單,旅行保險,我們想象一下,是否可以用保險裝飾一下,和雞蛋裝飾煎餅是一樣的,當然這個是需要看實際的業(yè)務模型,而且還有難度,那這里只是打個比方,那這個裝飾者模式就講到這里面

?

總結(jié)

以上是生活随笔為你收集整理的装饰者模式讲解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。