設計模式——裝飾者模式

Jacob發表於2019-01-19

1. 簡介

  裝飾者模式是一種結構型模式,它可以動態的將責任附加到物件上,在擴充套件功能方面,它比繼承更有彈性。裝飾者模式遵循了開閉原則,對擴充套件開放,對修改關閉。
  雖然在裝飾者模式中也使用了繼承,但是繼承只是為了與被裝飾者擁有共同的父類,達到型別匹配的目的,而不是為了獲得父類的行為。因為裝飾者與被裝飾者擁有共同的父類,所以在任何需要原始物件的場合,都可以用裝飾過的物件替代它。但是在使用裝飾者模式的同時可能會引入大量小類,而且使用裝飾者模式除了例項化元件外,還要把元件包裝進裝飾者,會使程式碼顯得不易理解。


2. UML類圖

圖片描述

  ConcreteComponent是具體元件,也就是被裝飾者。Decorator是抽象裝飾者,與ConcreteComponent擁有共同的超類Component————它是一個抽象元件,在具體裝飾者ConcreteDecoratorA和ConcreteDecoratorB中有一個例項變數,可以記錄被裝飾的事物。


3. 例項

  去食堂吃飯,假如你想吃麵條,食堂有牛肉麵和熱乾麵,還可以加青菜、煎蛋、香腸等配料,以後還可能增加更多的配料,在計算價格時需要根據不同的配料來計算,這裡就可以用到裝飾者模式。
抽象元件:

public abstract class Noodles {
    
    protected String desc;

    public String getDesc() {
        return desc;
    }
    
    public abstract double cost();
}

具體元件:

public class BeefNoodles extends Noodles {
    
    public BeefNoodles() {
        desc = "Beef Noodles.";
    }
    
    public double cost() {
        return 10.0;
    }    
}

public class HotDryNoodles extends Noodles {

    public HotDryNoodles() {
        desc = "Hot Dry Noodles.";
    }
    
    public double cost() {
        return 8.0;
    }
}

抽象裝飾者:

//繼承自Noodles,使裝飾者與元件擁有共同的超類
public abstract class Condiment extends Noodles {
    
    public abstract String getDesc();

}

具體裝飾者:

public class Vegetable extends Condiment {
    
    private Noodles noodles;
    
    public Vegetable(Noodles noodles) {
        this.noodles = noodles;
    }
    
    public String getDesc() {
        return noodles.getDesc() + ", vegetable";
    }
    
    public double cost() {
        return noodles.cost() + 2.0;
    }
}

public class Egg extends Condiment {
    
    private Noodles noodles;
    
    public Egg(Noodles noodles) {
        this.noodles = noodles;
    }
    
    public String getDesc() {
        return noodles.getDesc() + ", egg";
    }
    
    public double cost() {
        return noodles.cost() + 3.0;
    }
}

public class Sausage extends Condiment {
    
    private Noodles noodles;
    
    public Sausage(Noodles noodles) {
        this.noodles = noodles;
    }
     
    public String getDesc() {
        return noodles.getDesc() + ", Sausage";
    }
    
    public double cost() {
        return noodles.cost() + 4.0;
    }   
}

測試:

public class Test {
    
    public static void main(String[] args) {
        Noodles noodles = new BeefNoodles();
        System.out.println(noodles.getDesc() + ", " + noodles.cost());
        
        noodles = new Vegetable(noodles);
        noodles = new Egg(noodles);
        noodles = new Sausage(noodles);
        System.out.println(noodles.getDesc() + ", " + noodles.cost());
    }
}

相關文章