14 分鐘閱讀

裝飾器模式

雙11大拍賣
電腦顯示卡需要特價促銷

如果使用繼承來設計類別

繼承

public abstract class Goods {
    public String descript;
    public abstract int cost();
}

class Rtx3060 extends Goods{
    @Override
    public int cost() {
        return 9500;
    }
}
class Rtx4060 extends Goods{
    @Override
    public int cost() {
        return 10500;
    }
}

class Rtx3060_11_off extends Rtx3060{
    @Override
    public int cost() {
        return (int) (super.cost() * 0.85);
    }
}

考慮到有很多商品加上有各種的促銷,會有非常多的類別需要維護

修改基礎類別做調整

使用基礎類別來控制各種計算流程,配合繼承使子類別做出額外的計算與紀錄

public abstract class Goods {
    public String descript;
    protected int i_cost;
    public  double cost(){
        double base = 1;
        if (b11_off){
            base *= 0.88;
        }
        if(b3c_off){
            base *= 0.95;
        }
        return base;
    }
    protected boolean b11_off;
    protected boolean b3c_off;
    public boolean Is11_off(){ return b11_off;}
    public void set_11_off(){};
}

class Rtx3060 extends Goods{
    public Rtx3060(){
        b11_off = true;
    }
    @Override
    public double cost() {
        return Math.round(super.cost() * 9500);
    }
}


這樣可以正確計算,也可以減少類別數量

不過有幾個缺點

  1. 折扣改變必須修改程式
  2. 有新的促銷活動也必須加入新的折扣
  3. 賣化妝品的時候,化妝品並不需要3c折扣的方法

延伸解釋3的問題

使用繼承可以重複使用程式碼,重複利用的同時
也必須為每個繼承基礎類別的程式維護
全部的子類別不一定需要基礎類別的所有行為

使用裝飾器模式

  1. 一個商品RTX4060
  2. 雙11拍賣包裝RTX4060
  3. 3C拍賣包裝雙11

透過一層包裝一層,可以達到動態執行
呼叫的順序為 3->2->1

分為兩個種類

  1. 裝飾器類別
  2. 被裝飾類別
  • 裝飾器與被裝飾類別的基礎型別都是一樣的
  • 可以使用一個以上的裝飾器來裝飾
  • 裝飾器可以幫被被裝飾類別加入自己的行為

裝飾器的類別圖

定義;可以動態幫物件附加行為

裝飾者類別圖

裝飾器繼承Component不是為了取得基礎類別的行為
是為了取得與基礎類別一樣的型態

然後就可以不用透過繼承獲得行為
透過一樣的型態的組件互相組合
能獲得不同於繼承的高度彈性(執行時可以改變)

程式碼範例

public abstract class GoodsComponent {
    public abstract double cost();
}
class Rtx3060 extends GoodsComponent{
    @Override
    public double cost() {
        return 9500;
    }
}

abstract class GoodsDecorator extends GoodsComponent{
    protected GoodsComponent goods;

}

class C11_off extends GoodsDecorator{
    public C11_off(GoodsComponent goods){
        this.goods = goods;
    }
    @Override
    public double cost() {
        return goods.cost() * 0.95;
    }
}
class C3c_off extends GoodsDecorator{
    public C3c_off(GoodsComponent goods){
        this.goods = goods;
    }
    @Override
    public double cost() {
        return goods.cost() * 0.88;
    }
}

使用方法

GoodsComponent rtx3060 = new Rtx3060();
rtx3060 = new C11_off(rtx3060);
rtx3060 = new C3c_off(rtx3060);
System.out.println(rtx3060.cost());