設計模式——裝飾者模式 Java原始碼
裝飾者模式,可以動態地把職責附加到已有的物件上面去。又稱 Wrapper Pattern,在程式碼實現的時候,確實有“包裝”的意思。
類圖
圖:來自《Head First Design Patterns》
可以看出,裝飾者模式裡面,有4個角色:Component抽象類,ConcreteComponent具體類,Decorator抽象類,ConcreteDecorator具體類
圖:我的Java原始碼的類圖
總共10個類
一個Component抽象類
兩個ConcreteComponent具體類
一個Decorator抽象類
五個ConcreteDecorator具體類
一個Main測試類
ConcreteDecorator 繼承了Decorator抽象類, 組合了Component抽象類。Decorator抽象類繼承了Component抽象類,這個繼承的目的是:it’s vital that the decorators have the same type as the object they are going to decorate。簡而言之,就是為了獲得相同的型別,並不是為了獲得行為。組合是為了讓所有的concreteDecorator可以“互相包裝、裝飾”
talk is cheap, show me the code
去食堂打菜,經濟套餐,假設總共只有5種食物可供選擇分別是:手撕包菜,茄子豆角,麻婆豆腐,青椒肉絲,紅燒裡脊。
一個Component抽象類
package decorator;
public abstract class Meal
{
String description = "Unknown Meal";
public String getDescription()
{
return description;
}
public abstract double cost();
}
兩個ConcreteComponent具體類
package decorator;
public class ChineseMeal extends Meal
{
public ChineseMeal()
{
description = "Chinese Meal";
}
@Override
public double cost()
{
return 1.0; // 一次性餐具費用
}
}
package decorator;
public class WesternMeal extends Meal
{
public WesternMeal()
{
description = "Western meal";
}
@Override
public double cost()
{
return 5.0; // 不鏽鋼刀、叉費用
}
}
一個Decorator抽象類
package decorator;
public abstract class Decorator extends Meal
{
public abstract String getDescription();
}
五個ConcreteDecorator具體類
package decorator;
// 茄子豆角
public class EggplantBean extends Decorator
{
Meal meal;
public EggplantBean(Meal meal)
{
this.meal = meal;
}
@Override
public String getDescription()
{
return meal.getDescription() + ", 茄子豆角";
}
@Override
public double cost()
{
return 2 + meal.cost();
}
}
package decorator;
// 青椒炒肉
public class GreenPepperPork extends Decorator
{
Meal meal;
public GreenPepperPork(Meal meal)
{
this.meal = meal;
}
@Override
public String getDescription()
{
return meal.getDescription() + ", 青椒炒肉";
}
@Override
public double cost()
{
return 3 + meal.cost();
}
}
package decorator;
// 手撕包菜
public class HandCabbage extends Decorator
{
Meal meal;
public HandCabbage(Meal meal)
{
this.meal = meal;
}
@Override
public String getDescription()
{
return meal.getDescription() + ", 手撕包菜";
}
@Override
public double cost()
{
return 2 + meal.cost();
}
}
package decorator;
// 麻婆豆腐
public class MapoTofu extends Decorator
{
Meal meal;
public MapoTofu(Meal meal)
{
this.meal = meal;
}
@Override
public String getDescription()
{
return meal.getDescription() + ", 麻婆豆腐";
}
@Override
public double cost()
{
return 4 + meal.cost();
}
}
package decorator;
// 紅燒裡脊
public class BraiseTenderloin extends Decorator
{
Meal meal;
public BraiseTenderloin(Meal meal)
{
this.meal = meal;
}
@Override
public String getDescription()
{
return meal.getDescription() + ", 紅燒裡脊";
}
@Override
public double cost()
{
return 5 + meal.cost();
}
}
一個Main測試類
package decorator;
public class Main
{
public static void main(String[] args)
{
Meal meal = new ChineseMeal();
meal = new GreenPepperPork(meal);
meal = new HandCabbage(meal);
meal = new BraiseTenderloin(meal);
System.out.println(meal.getDescription() + " ¥" + meal.cost());
Meal meal2 = new ChineseMeal();
meal2 = new EggplantBean(new MapoTofu(new BraiseTenderloin(meal2)));
System.out.println(meal2.getDescription() + " ¥" + meal2.cost());
}
}
執行結果
直接從eclipse複製過來
Chinese Meal, 青椒炒肉, 手撕包菜, 紅燒裡脊 ¥11.0
Chinese Meal, 紅燒裡脊, 麻婆豆腐, 茄子豆角 ¥12.0
分析討論
去食堂打菜,經濟套餐,假設總共只有5種食物可供選擇分別是:手撕包菜,茄子豆角,麻婆豆腐,青椒肉絲,紅燒裡脊。如果可以隨意打菜,就可以有
裝飾者模式就可以解決上述這種“類的爆炸式增長”問題,各種各樣的排列組合太多,不能在程式碼中一個類一個。
裝飾者模式的特點是“繼承(inheritance) + 組合(Composition)”:繼承是為了讓component和decorator擁有相同的型別,組合是為了讓所有的concreteDecorator可以“互相包裝、裝飾”。裝飾者又名Wrapper大概就是這樣來的。
Java. IO
Java.IO 中應用了裝飾者模式
FileInputStream fiStream = null;
InputStreamReader iStreamReader = null;
BufferedReader bReader = null;
fiStream = new FileInputStream("C:\\xxxx");
// InputStreamReader 是位元組流通向字元流的橋樑、
iStreamReader = new InputStreamReader(fiStream);
// 從字元輸入流中讀取檔案中的內容,裝飾了一個InputStreamReader的物件
bReader = new BufferedReader(iStreamReader("C:\\xxxx"));
一句程式碼版本,把3個new放到一起
BufferedReader bReader = new BufferedReader(new InputStreamReader(new FileInputStream("C:\\xxxx"));