裝飾者模式.

一、概念

  • 繼承的缺點:類數量爆炸、設計死板以及基類加入的新功能可能並不適用於所有的子類。
  • 裝飾者模式:動態地將責任附加到對象上,若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案。一言以蔽之 —— 動態擴展類的行爲。
  • 角色:   1、抽象組件(Component):給出一個抽象類或接口,以規範準備接收附加責任的行爲。   2、具體組件(ConcreteComponent):繼承或實現抽象組件,定義一個將要接收附加責任的類。   3、抽象裝飾者(Decorator):持有一個組件(Component)對象的實例,一般從抽象組件擴展,類型是抽象類或者接口,目的是達到"類型匹配"。   4、具體裝飾者(ConcreteDecorator):繼承或實現抽象裝飾者,負責給組件對象"貼上"附加的責任。

二、Demo 實現

TOPIC:我們要定義一些飲品,並能夠向飲品中添加一些調料,比如摩卡、糖之類的,然後能夠根據添加的調料種類動態的修改飲品的價格。

1、抽象組件

public abstract class Beverage {

    String description = "Unknown Beverage";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

這是一個抽象組件角色 —— 飲品抽象類,抽象方法 cost() 用來規範接收附加責任的行爲。

2、具體組件

public class Espresso extends Beverage {

    public Espresso() {
        description = "Espresso";
    }

    @Override
    public double cost() {
        return 1.99;
    }
}
public class HouseBlend extends Beverage {

    public HouseBlend() {
        description = "HouseBlend";
    }

    @Override
    public double cost() {
        return 0.89;
    }
}

這是兩個具體組件角色 —— 濃縮咖啡類和混合飲料類,用來接受附加責任,也就是裝飾者具體要裝飾的類!

3、抽象裝飾者

public abstract class CondimentDecorator extends Beverage {

    protected Beverage beverage;

    @Override
    public abstract String getDescription();
}

這是一個抽象裝飾者角色,主要的目的是爲了"類型匹配",什麼是"類型匹配"呢?不多說,看看下面的測試類就一目瞭然了!

4、具體裝飾者

現在我們想往飲品中添加摩卡,然後在飲品的價格上添加上摩卡的價格,也就是在不改變飲品類內部代碼的情況下擴展飲品類的行爲 —— 用摩卡類修飾飲品類!

public class Mocha extends CondimentDecorator {

    public Mocha(Beverage b) {
        beverage = b;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + "+Mocha";
    }

    @Override
    public double cost() {
        return beverage.cost() + 0.20;
    }
}

5、測試

測試類能幫你對裝飾者模式有更清晰的認識!

public static void main(String[] args) {
    Beverage beverage = new Espresso();
    System.out.println("濃縮咖啡:" + beverage.getDescription() + "," + beverage.cost());
    
    Beverage beverage1 = new HouseBlend();
    // 抽象裝飾者的 "類型匹配" 如下 —— 可以用同一個實例對象接收裝飾對象,以達到類行爲擴展的目的。
    beverage1 = new Mocha(beverage1);
    beverage1 = new Mocha(beverage1);
    System.out.println("混合飲料+2份摩卡:" + beverage1.getDescription() + "," + beverage1.cost());
}

演示源代碼:https://github.com/JMCuixy/design-patterns

三、總結

  • 設計原則:類應該對擴展開放,對修改關閉。
  • 特點:   1、裝飾者和被裝飾者對象有相同的超類型。   2、你可以用一個或多個裝飾者包裝一個對象。   3、裝飾者可以在所委託的被裝飾者行爲之前或之後,加上自己的行爲,以達到特定的目的。   4、對象可以在任何時候被裝飾,所以你可以在運行時動態地、不限量的用你喜歡的裝飾者來裝飾對象。
  • 優點:裝飾者模式的設計具有彈性,可以應對改變,可以接受新的功能來應對改變的需求。
  • 缺點:如果每個地方都採用開放-封閉原則是一種浪費,也沒必要,還會導致代碼變得複雜且難以理解。比如會產生很多的小類。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章