Decorator(裝飾者)模式
裝飾者模式適用於給一個對象添加額外功能的情況,傳統的類在進行功能添加時主要靠以下手段進行:
- 直接修改對象添加相應的功能
- 派生子類進行拓展
這樣做的缺點顯而易見,直接修改對象會造成該類隨着時間推移愈發臃腫;子類派生的話如果增加的功能很多的時候會有一條非常長的繼承線。
裝飾器的做法是採用一個功能一個類的方式去往實例類中動態添加功能(使用功能類去包裝需要此功能的對象),這樣做既不會直接修改類中屬性和方法,也不會有長的繼承線。客戶端可以根據實際需要,去加載它會使用到的功能。優點總結如下:
- 類的層次不會混亂
- 增加或減少功能不需要改變類中的數據結構
- 解耦,讓核心職責和功能分開
完全組件
- Component (被裝飾對象基類):定義對象的接口。
- ConcreteComponent(具體被裝飾類):繼承自Component,對象類。
- Decorator(修飾者基類):維護指向Component的引用,定義與其一樣的接口。
- ConcreteDecorator(具體裝飾者):具體的裝飾對象,給內部持有的具體被裝飾對象增加具體的職責;
適當刪減的意思是可以根據實際需求,刪除修飾者基類,這是在系統不是很大的情況下適用。類結構圖如下。
這裏有一個簡單樣例,通過火鍋對裝飾者模式進行講解。其中菜品屬於裝飾者,鍋底屬於被裝飾者。
被裝飾者基類
public interface GuoDi {
public float cost();//鍋底當然要有價錢啦
public String name();//名字也得有哦
}
被裝飾者實例類
public class YuanYang implements GuoDi {
@Override
public float cost() {
return 48.0f;
}
@Override
public String name() {
return "鴛鴦鍋底";
}
}
public class DaLongYan implements GuoDi{
@Override
public float cost() {
return 59.0f;
}
@Override
public String name() {
return "大龍燚火鍋原味鍋底";
}
}
裝飾者基類
public abstract class PeiCai implements GuoDi {
private GuoDi guodi;
public FoodDecorator(GuoDi guodi) {
super();
this.guodi = guodi;
}
@Override
public float cost() {
return guodi.cost();
}
@Override
public String name() {
return guodi.name();
}
}
裝飾者實例類
public class MaLaNiuRou extends PeiCai {
public MaLaNiuRou(GuoDi guodi) {
super(guodi);
}
@Override
public float cost() {
return super.cost()+46f;
}
@Override
public String name() {
return super.name()+"+麻辣牛肉";
}
}
public class MaoDu extends PeiCai {
public MaoDu(GuoDi guodi) {
super(guodi);
}
@Override
public float cost() {
return super.cost()+30f;
}
@Override
public String name() {
return super.name()+"+大刀毛肚";
}
}
調用方法
public class Test {
public static void main(String[] args) {
GuoDi guodi = new DaLongYan ();//點個大龍燚火鍋原味鍋底
MaLaNiuRou y = new MaLaNiuRou(guodi);//來個麻辣牛肉
MaoDu x = new MaoDu(y);//在麻辣牛肉的基礎上再來個大刀毛肚
System.out.println("一共點了"+x.name()+",共消費"+s.cost());
}
}
這樣做便把新菜品加入進去了。思考:使用傳統方法會是怎樣的情況,並且結合上面總結的優缺點。