裝飾者模式:
動態地將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案。
特點:
1、裝飾者和被裝飾對象有相同的超類型。
2、你可以用一個或多個裝飾者包裝一個對象。
3、既然裝飾者和被裝飾對象有相同的超類型,所以在任何需要原始對象(被包裝的)的場合,可以用裝飾過的對象代替它。
4、裝飾者可以再所委託被裝飾者的行爲之前與/或之後,加上自己的行爲,以達到特定的目的。
5、對象可以在任何時候被裝飾所以可以在運行時動態地、不限量地用你先的裝飾者來裝飾對象。
實例:
購買咖啡是,可以要求在其中假如各種調料,例如:豆漿、摩卡、或者奶泡,根據所加入的調料收取不同的費用。
以裝飾者模式構造:
類圖:
話不多說,直接上代碼:
/**
* 飲料類
*
*/
public abstract class Beverage {
//描述
String description = "Unknown Beverage";
public String getDescription(){
return description;
}
//結算方法
public abstract double cost();
}
/**
* 調料抽象類,也就是裝飾者類
*
*/
//必須讓CondimentDecorator能夠取代Beverage,所以將CondimentDecorator擴展自Beverage
public abstract class CondimentDecorator extends Beverage{
//所有調料裝飾者必須重新實現此方法
public abstract String getDescription();
}
/**
* 濃縮咖啡
*
*/
public class Espresso extends Beverage{
public Espresso(){
//爲了設置飲料的描述,我們寫了一個構造器
description = "Espresso";
}
@Override
public double cost() {
//飲料的價錢
return 1.99;
}
}
/**
* 摩卡裝飾者
*
*/
public class Mocha extends CondimentDecorator{
//要讓mocha能夠引用一個Beverage,做法如下
//1、用一個實例變量記錄飲料,也就是被裝飾者
Beverage beverage;
//2、想辦法讓被裝飾者被記錄到實例變量中,這裏的做法是:把飲料當做構造器的參數,再由構造器將此飲料記錄在實例變量中
public Mocha(Beverage beverage){
this.beverage = beverage;
}
@Override
public String getDescription() {
// 我們希望描述不只是描述飲料,而是完整的連調料也描述出來,所以首先利用委託的做法,得到一個描述,然後在其後加上附加的敘述
return beverage.getDescription() + ",Mocha";
}
@Override
public double cost() {
//需要計算帶mocha飲料的價錢,首先把調用委託給被裝飾對象,以計算價格,然後再加上摩卡的價錢,得到最後結果
return 0.2 + beverage.cost();
}
}
public class CoffeeTest {
//測試類
public static void main(String[] args) {
//訂一杯濃縮咖啡,不需要飲料
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" +beverage.cost());
//訂一杯濃縮咖啡,需要mocha
Beverage beverage2 = new Espresso();
beverage2 = new Mocha(beverage2);
System.out.println(beverage2.getDescription() + " $" +beverage2.cost());
}
}