設計模式-裝飾者模式

要解決的問題

考慮一個咖啡店收費的問題:如何實現靈活的咖啡的價格的計算。咖啡店主要賣咖啡,可是後來爲了知足不一樣客戶的不一樣口味,只是純咖啡,顯得太單調了,就考慮增長不一樣的搭配,搭配不一樣的配料後會組成另外一種飲品,這樣,品種豐富了,但隨之問題也來了,如何爲不一樣新的品種計算新的準確的價格。兩種方案:編程

第一種:能夠採用繼承的方式,將純咖啡做爲基類,然後須要什麼品種的話,能夠生成一個子類繼承基類,單獨做爲一個品種來計算價格的方法,而且還能夠爲這個品種添加其它功能。可是,繼承有一個很大的問題就是,這樣的方案實現是首先你是知道都有什麼品種的,纔會派生出各類子類,可是,若是後續想要在某個現有品種中去掉一些或者加上一些內容,甚至直接刪掉這個品種,就會很麻煩,由於老是要去修改對應的子類;並且還有個缺點,會產生不少種子類,若是品種不少,並且每一個品種的差異很小的時候,都分別單獨做爲一個類就會很麻煩。ide

第二種:就是採用裝飾者模式。先類比一下生活中的一個例子:一張紙質的照片,想要讓這個照片保存的久一點,能夠先給這張照片塑封;塑封后,以爲還不夠的話,可能還會給這張照片裝一個相框;加一個相框還以爲不能好好保護相片的話,再加個玻璃罩。在這個例子中,能夠理解照片自己就是要被裝飾的對象,塑封膠、相框、玻璃罩都是做爲裝飾者。每一層的裝飾着都不會修改最裏邊的被裝飾的對象。這裏能夠把具體的咖啡飲品看成被裝飾者,要加入的食物或飲料看成裝飾者,每一種咖啡飲品能夠被不一樣的裝飾者裝飾。測試

將上述爲不一樣咖啡飲品計算價格的問題用編程的概念來說就是如何透明的給一個對象增長功能。並實現功能的動態組合。這就是裝飾者模式的功能。ui


模式定義

裝飾者模式可以實現動態地爲對象添加功能,從一個對象外部透明的給對象增長功能。透明地給一個對象增長功能,就是說要給一個對象增長功能,可是不能讓這個對象知道,也就是不能去修改這個對象。this

每一個被裝飾者能夠被多個裝飾者裝飾。例如:黑咖啡(被裝飾者)能夠被牛奶(裝飾者)、水果(裝飾者)裝飾,並且,不一樣的裝飾者之間沒有前後順序的限制。3d


具體實現

裝飾者須要和被裝飾者的對象繼承於一樣的類或者實現一樣的接口,然後,在具體的裝飾者實現中,轉調被裝飾者對象(這就須要裝飾者對象持有一個被裝飾者對象)。code

下邊是具體實現的 UML 圖和不一樣類之間的調用層次圖。
對象

CoffeeComponent:咖啡基類(也能夠是接口)
BlackCoffee:具體的咖啡,就是被裝飾的對象
CondimentDecorator:配料的基類(裝飾者的基類),並且須要繼承於被裝飾着的基類 CoffeeComponent,同時還要持有一個 CoffeeComponent 類型的屬性。
MilkDecorator:牛奶裝飾者,具體的裝飾者對象。blog


實例

  • 抽象組件--CoffeeComponent
/**
 * 抽象組件
 */
public abstract class CoffeeComponent {
    protected String desc;
    
    public String getDesc(){
        return desc;
    }
    
    public abstract double cost();
}
  • 具體組件--BlackCoffee(被裝飾者)
/**
 * 具體組件--BlackCoffee
 * 被裝飾者
 */
public class BlackCoffee extends CoffeeComponent{
    
    public BlackCoffee(){
        desc = "Black Coffee";
    }
    
    @Override
    public double cost() {
        return 10.0;
    }
}
  • 抽象裝飾者--CondimentDecorator
/**
 * 抽象裝飾者--CondimentDecorator
 * 須要跟被裝飾者BlackCoffee同樣繼承抽象組件CoffeeComponent
 */
public abstract class CondimentDecorator extends CoffeeComponent{
    
    public abstract double cost();
}
  • 具體裝飾者--MilkDecorator
/**
 * 具體裝飾者--MilkDecorator
 * 持有抽象組件的成員變量
 */
public class MilkDecorator extends CondimentDecorator{
    private CoffeeComponent coffeeComponent;

    public MilkDecorator(CoffeeComponent coffeeComponent){
        this.coffeeComponent = coffeeComponent;
    }

    public String getDesc(){
        return coffeeComponent.getDesc() + ", milk";
    }
    
    @Override
    public double cost() {
        return coffeeComponent.cost() + 2.0;
    }
}
  • 具體裝飾者--FruitDecorator
/**
 * 具體裝飾者--FruitDecorator
 * 持有抽象組件的成員變量
 */
public class FruitDecorator extends CondimentDecorator{
    private CoffeeComponent coffeeComponent;

    public FruitDecorator(CoffeeComponent coffeeComponent){
        this.coffeeComponent = coffeeComponent;
    }

    public String getDesc(){
        return coffeeComponent.getDesc() + ", Fruit";
    }

    @Override
    public double cost() {
        return coffeeComponent.cost() + 3.0;
    }
}
  • 測試
public class Test {
    public static void main(String[] args) {
        CoffeeComponent coffeeComponent = new BlackCoffee();
        System.out.println(coffeeComponent.getDesc() + "," + coffeeComponent.cost());
        coffeeComponent = new MilkDecorator(coffeeComponent);
        coffeeComponent = new FruitDecorator(coffeeComponent);
        System.out.println(coffeeComponent.getDesc() + "," + coffeeComponent.cost());
    }
}
  • 輸出
Black Coffee,10.0
Black Coffee, milk, Fruit,15.0
相關文章
相關標籤/搜索