【Java設(shè)計模式】結(jié)構(gòu)型模式-裝飾模式

源代碼:https://gitee.com/AgentXiao/DecroatorPattern
要點(diǎn):
1、裝飾模式解決的問題
2、裝飾模式的各個模塊實(shí)現(xiàn)
3、裝飾模式的優(yōu)缺點(diǎn)
4、裝飾模式和橋接模式的區(qū)別

一、場景引入

場景引入

如上圖所示,有一個狗(Dog)類,下面有三個子類,分別是會飛的狗(FlyDog)、會游泳的狗(SwimDog)、會跑的狗(RunDog)。假設(shè)此時三個子類都是單一功能的,也就說FlyDog只會飛,游泳和跑步都不會。

如果此時需要一個既會飛也會跑的狗,我們可以通過繼承的方式實(shí)現(xiàn),一次類推,可以得到:

繼承具有新功能的狗

這顯然不是最好的方法!當(dāng)功能非常多時,需要繼承父類的子類數(shù)量將會大大增加!而裝飾模式就是解決這個問題的一種設(shè)計模式。

二、裝飾模式

裝飾模式是一種用于代替繼承的技術(shù),無需通過繼承增加子類就能夠擴(kuò)展對象的新功能。使用對象的組合關(guān)系(區(qū)分于“組合設(shè)計模式”)代替繼承關(guān)系,避免類型體系的快速膨脹。

簡單地說,裝飾模式用于動態(tài)增加一個對象的新功能,或成為功能增強(qiáng)。

裝飾模式實(shí)現(xiàn)細(xì)節(jié):

裝飾模式實(shí)現(xiàn)細(xì)節(jié).png

(1)抽象構(gòu)建角色Component。這是真實(shí)對象和裝飾對象都需要實(shí)現(xiàn)的接口,便于客戶端可以使用相同的方式交互裝飾對象和真實(shí)對象,指上文的Dog。
(2)真實(shí)對象ConcreteComponent。具體需要裝飾的對象,定義為MyDog。
(3)裝飾對象Decorator。持有一個抽象構(gòu)件的引用(核心)。裝飾對象接受所有客戶端的請求,并把這些請求通過引用轉(zhuǎn)發(fā)給真實(shí)對象。這樣,就能在真實(shí)對象調(diào)用前后增加新的功能,定義為SuperDog。
(4)具體裝飾對象ConcreteDecorator:指上文的Fly、Swim、Run。

三、裝飾模式的實(shí)現(xiàn)

1、抽象角色

/**
 * @InterfaceName Dog
 * @Description 抽象構(gòu)建角色
 * @Author xwd
 * @Date 2018/10/25 9:52
 */
public interface Dog {
    /**
     * @MethodName showPower
     * @Descrition 展示能力
     * @Param []
     * @return void
     */
    void showPower();
}

2、具體角色

/**
 * @ClassName MyDog
 * @Description 具體對象
 * @Author xwd
 * @Date 2018/10/25 9:53
 */
public class MyDog implements Dog{
    @Override
    public void showPower() {
        System.out.println("我還沒有什么能力!");
    }
}

3、裝飾角色(核心)

/**
 * @ClassName SuperDog
 * @Description 裝飾對象
 * @Author xwd
 * @Date 2018/10/25 9:54
 */
public class SuperDog implements Dog{
    protected Dog dog;//持有抽象構(gòu)建角色的引用

    public SuperDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public void showPower() {
        dog.showPower();
    }
}

4、具體的裝飾角色

/**
 * @ClassName Fly
 * @Description 飛行能力
 * @Author xwd
 * @Date 2018/10/25 9:57
 */
public class Fly extends SuperDog{
    public Fly(Dog dog) {
        super(dog);
    }

    @Override
    public void showPower() {
        super.showPower();
        System.out.println("我具備飛行功能!");
    }
}
/**
 * @ClassName Run
 * @Description 奔跑能力
 * @Author xwd
 * @Date 2018/10/25 9:57
 */
public class Run extends SuperDog{
    public Run(Dog dog) {
        super(dog);
    }

    @Override
    public void showPower() {
        super.showPower();
        System.out.println("我具備奔跑功能!");
    }
}
/**
 * @ClassName Swim
 * @Description 游泳能力
 * @Author xwd
 * @Date 2018/10/25 9:57
 */
public class Swim extends SuperDog{
    public Swim(Dog dog) {
        super(dog);
    }

    @Override
    public void showPower() {
        super.showPower();
        System.out.println("我具備游泳功能!");
    }
}

5、測試

/**
 * @ClassName Client
 * @Description 測試裝飾模式
 * @Author xwd
 * @Date 2018/10/25 9:59
 */
public class Client {
    public static void main(String[] args) {

        //原生態(tài)的狗,還沒有什么能力
        Dog dog = new MyDog();
        dog.showPower();
        System.out.println("*********************");

        //添加了裝飾模式的狗,但是還沒有添加具體功能
        SuperDog superDog = new SuperDog(dog);
        superDog.showPower();
        System.out.println("*********************");

        //添加了飛行能力的狗
        SuperDog flyDog = new Fly(dog);
        flyDog.showPower();
        System.out.println("*********************");

        //添加了游泳能力的狗
        SuperDog swimDog = new Swim(dog);
        swimDog.showPower();
        System.out.println("*********************");

        //既添加了飛行能力又添加了奔跑能力的狗
        SuperDog runDog = new Run(dog);
        SuperDog fsDog = new Fly(runDog);
        fsDog.showPower();
        System.out.println("*********************");
    }
}

6、測試結(jié)果

測試結(jié)果

由此可見,需要為一個對象添加新功能時,只需要建立這個功能,將具體對象傳入。如果傳入的對象是已經(jīng)具備某些功能的,就相當(dāng)遠(yuǎn)在那個基礎(chǔ)上添加新的功能。

四、開發(fā)中使用的場景

  • IO中輸入流和輸出流的設(shè)計。
  • Swing包中圖形界面構(gòu)件功能。
  • Servlet API 中提供了一個request對象的Decorator設(shè)計模式的默認(rèn)實(shí)現(xiàn)類HttpServletRequestWrapper,HttpServletRequestWrapper類,增強(qiáng)了request對象的功能。
  • Struts2中,request,response,session對象的處理。

在這里只解釋其中一種:
在IO流中,抽象構(gòu)建對象是InputStream、OutputStream、Reader、Writer。

真實(shí)對象是FileInputStream、FileOutputStream。

真實(shí)對象

裝飾對象是FilterInputStream、FilterOutputStream。

裝飾對象

具體的裝飾對象:BufferedOutputStream、BufferedInputStream等。

繼承裝飾對象
構(gòu)造器中傳入抽象構(gòu)建對象

五、總結(jié)

1、功能

裝飾模式(Decorator)也叫包裝器模式(Wrapper)。

裝飾模式降低系統(tǒng)的耦合度,可以動態(tài)的增加或刪除對象的職責(zé),并使得需要裝飾的具體構(gòu)建類和具體裝飾類可以獨(dú)立變化,以便增加新的具體構(gòu)建類和具體裝飾類。

2、優(yōu)點(diǎn)

  • 擴(kuò)展對象功能,比繼承靈活,不會導(dǎo)致類個數(shù)急劇增加。
  • 可以對一個對象進(jìn)行多次裝飾,創(chuàng)造出不同行為的組合,得到功能更加強(qiáng)大的對象。
  • 具體構(gòu)建類和具體裝飾類可以獨(dú)立變化,用戶可以根據(jù)需要自己增加新的具體構(gòu)件子類和具體裝飾子類。

3、缺點(diǎn)

  • 產(chǎn)生很多小對象。大量小對象占據(jù)內(nèi)存,一定程度上影響性能。
  • 裝飾模式易于出錯,調(diào)試排查比較麻煩。

4、裝飾模式和橋接模式的區(qū)別

兩個模式都是為了解決過多子類對象問題。但他們的誘因不一樣。

  • 橋接模式是對象自身現(xiàn)有機(jī)制沿著多個維度變化。
  • 裝飾模式是為了增加新的功能。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容