漫畫設計模式:什麼是 “裝飾器模式” ?


—————  第二天  —————

————————————





裝飾器模式都包含哪些核心角色呢?

1. Component接口

在我們上面的例子中,Component接口相當於汽車接口,所有的被包裝類、包裝類,都繼承於這個接口。

2. ConcreteComponent類

ConcreteComponent類是被包裝的實現類。在例子中,奔馳汽車、寶馬汽車、特斯拉汽車都屬於這個角色。

3. Decorator抽象類

所有的包裝類,都繼承自Decorator抽象類,而Decorator類又實現了Component接口,這麼做是爲了實現多層嵌套包裝。

4ConcreteDecorator類

具體的包裝類,用於擴充被包裝類的功能,比如例子中的自動駕駛功能、飛行功能擴展。

這四大核心角色的關係是怎樣的呢?我們可以用裝飾器模式的UML類圖來表達:


首先是汽車接口,也就是Component這個角色,裏面定義了run這個行爲:

public interface Car {
    void run();
}

接下來是各種汽車的實現類,也就是ConcreteComponent角色,不同的汽車對於run行爲有着不同的實現:

public class BenzCar implements Car{
    @Override
    public void run() {
        System.out.println("奔馳開車了!");
    }
}

public class BmwCar implements Car{
    @Override
    public void run() {
        System.out.println("寶馬開車了!");
    }
}

public class TeslaCar implements Car{
    @Override
    public void run() {
        System.out.println("特斯拉開車了!");
    }
}

下面是裝飾器的抽象類,也就是Decorator角色,這個角色包含了被裝飾的成員對象:

public class CarDecorator implements Car {

    protected Car decoratedCar;

    public CarDecorator(Car decoratedCar){
        this.decoratedCar = decoratedCar;
    }

    public void run(){
        decoratedCar.run();
    }
}

或許有人會覺得奇怪,爲什麼裝飾器類也要實現Car接口呢?這正是裝飾器模式的靈活之處。

繼承自Car接口,可以讓每一個裝飾器本身也可以被更外層的裝飾器所包裝,包裝的方式就是把Car對象作爲參數,傳入到外層裝飾器的構造函數當中。

接下來是具體的裝飾器實現類,也就是ConcreteDecorator角色。這些裝飾器同樣實現了run的行爲,一方面會調用被包裝對象的run方法,一方面會進行某些擴展操作(比如自動駕駛、飛行):

public class AutoCarDecorator extends CarDecorator {

    public AutoCarDecorator(Car decoratedCar){
        super(decoratedCar);
    }

    @Override
    public void run(){
        decoratedCar.run();
        autoRun();
    }

    private void autoRun(){
        System.out.println("開啓自動駕駛");
    }}

public class FlyCarDecorator extends CarDecorator {

    public FlyCarDecorator(Car decoratedCar){
        super(decoratedCar);
    }

    @Override
    public void run(){
        decoratedCar.run();
        fly();
    }

    private void fly(){
        System.out.println("開啓飛行汽車模式");
    }

}

最後,是我們的客戶端類。客戶端類負責創建被包裝對象和裝飾者,並決定如何進行包裝和執行:

public class Client {

    public static void main(String[] args) {
        Car benzCar = new BenzCar();
        Car bmwCar = new BmwCar();
        Car teslaCar = new TeslaCar();
        //創建自動駕駛的奔馳汽車
        CarDecorator autoBenzCar = new AutoCarDecorator(benzCar);
        //創建飛行的、自動駕駛的寶馬汽車
        CarDecorator flyAutoBmwCar = new FlyCarDecorator(new AutoCarDecorator(bmwCar));

        benzCar.run();
        bmwCar.run();
        teslaCar.run();
        autoBenzCar.run();
        flyAutoBmwCar.run();
    }
}

以輸入流爲例,爲了滿足不同輸入場景,JDK設計了多種多樣的輸入流,包括ByteArrayInputStream、FileInputStream等等。

這些輸入流都繼承自共同的抽象類:InputStream。

與此同時,爲了給這些輸入流帶來功能上的擴展,JDK設計了一個裝飾器類,FilterInputStream。該類繼承自InputStream,並且“組合”了InputStream成員對象。

從FilterInputStream類派生出了許多裝飾器子類,包括BufferedInputStream,DataInputStream等等,分別提供了輸入流緩衝,以及從輸入流讀取Java基本數據類型等額外功能。

—————END—————

喜歡本文的朋友,歡迎關注公衆號 程序員小灰,收看更多精彩內容

點個[在看],是對小灰最大的支持!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章