一判导、 定義
裝飾者模式,動(dòng)態(tài)地將責(zé)任附加到對象上沛硅。若要擴(kuò)展功能眼刃,裝飾者提供了比繼承更加有彈性的替代方案。
二摇肌、組合和繼承的區(qū)別
繼承擂红。繼承是給一個(gè)類添加行為的比較有效的途徑。通過使用繼承围小,可以使得子類在擁有自身方法的同時(shí)昵骤,還可以擁有父類的方法。但是使用繼承是靜態(tài)的肯适,在編譯的時(shí)候就已經(jīng)決定了子類的行為变秦,我們不便于控制增加行為的方式和時(shí)機(jī)。
組合框舔。組合即將一個(gè)對象嵌入到另一個(gè)對象中蹦玫,由另一個(gè)對象來決定是否引用該對象來擴(kuò)展自己的行為。這是一種動(dòng)態(tài)的方式刘绣,我們可以在應(yīng)用程序中動(dòng)態(tài)的控制樱溉。
與繼承相比,組合關(guān)系的優(yōu)勢就在于不會破壞類的封裝性纬凤,且具有較好的松耦合性福贞,可以使系統(tǒng)更加容易維護(hù)。但是它的缺點(diǎn)就在于要?jiǎng)?chuàng)建比繼承更多的對象移斩。
三肚医、裝飾者模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
1、裝飾者模式可以提供比繼承更多的靈活性
2向瓷、可以通過一種動(dòng)態(tài)的方式來擴(kuò)展一個(gè)對象的功能肠套,在運(yùn)行時(shí)選擇不同的裝飾器,從而實(shí)現(xiàn)不同的行為猖任。
3你稚、通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創(chuàng)造出很多不同行為的組合〉罄担可以使用多個(gè)具體裝飾類來裝飾同一對象搁痛,得到功能更為強(qiáng)大的對象。
4宇弛、具體構(gòu)件類與具體裝飾類可以獨(dú)立變化鸡典,用戶可以根據(jù)需要增加新的具體構(gòu)件類和具體裝飾類,在使用時(shí)再對其進(jìn)行組合枪芒,原有代碼無須改變彻况,符合“開閉原則”。
缺點(diǎn)
1舅踪、會產(chǎn)生很多的小對象纽甘,增加了系統(tǒng)的復(fù)雜性
2、這種比繼承更加靈活機(jī)動(dòng)的特性抽碌,也同時(shí)意味著裝飾模式比繼承更加易于出錯(cuò)悍赢,排錯(cuò)也很困難,對于多次裝飾的對象货徙,調(diào)試時(shí)尋找錯(cuò)誤可能需要逐級排查左权,較為煩瑣。
四痴颊、裝飾者的使用場景
1涮总、在不影響其他對象的情況下,以動(dòng)態(tài)祷舀、透明的方式給單個(gè)對象添加職責(zé)瀑梗。
2、需要?jiǎng)討B(tài)地給一個(gè)對象增加功能裳扯,這些功能也可以動(dòng)態(tài)地被撤銷抛丽。 當(dāng)不能采用繼承的方式對系統(tǒng)進(jìn)行擴(kuò)充或者采用繼承不利于系統(tǒng)擴(kuò)展和維護(hù)時(shí)。
五饰豺、UML圖
六亿鲜、代碼示例
裝飾者基類
/**
* 食物基類
*
*/
public abstract class Food {
protected String desc;
public abstract String getDesc();
}
雞肉
/**
* 雞肉
*
*/
public class Chicken extends Food {
public Chicken(){
desc = "雞肉";
}
@Override
public String getDesc() {
return desc;
}
}
鴨肉
package com.xinye.test.decoration;
/**
* 鴨肉
* @author xinye
*
*/
public class Duck extends Food {
public Duck(){
desc = "鴨肉";
}
@Override
public String getDesc() {
return desc;
}
}
裝飾者基類
package com.xinye.test.decoration;
/**
*
* @author xinye
*
*/
public abstract class FoodDecoration extends Food {
@Override
public abstract String getDesc();
}
蒸-裝飾者
package com.xinye.test.decoration;
/**
* 蒸食物
* @author xinye
*
*/
public class SteamedFood extends FoodDecoration {
private Food food;
public SteamedFood(Food f){
this.food = f;
}
@Override
public String getDesc() {
return getDecoration() + food.getDesc();
}
private String getDecoration(){
return "蒸";
}
}
烤-裝飾者
package com.xinye.test.decoration;
/**
* 烤食物
* @author xinye
*
*/
public class RoastFood extends FoodDecoration {
private Food food;
public RoastFood(Food f){
this.food = f;
}
@Override
public String getDesc() {
return getDecoration() + food.getDesc();
}
private String getDecoration(){
return "烤";
}
}
客戶端
package com.xinye.test.decoration;
/**
* 客戶端
* @author xinye
*
*/
public class Client {
public static void main(String[] args) {
// 測試單純的食物
Food f1 = new Chicken();
System.out.println(f1.getDesc());
System.out.println("----------------------");
// 測試單重修飾的食物
RoastFood rf = new RoastFood(f1);
System.out.println(rf.getDesc());
System.out.println("----------------------");
// 測試多重修飾的食物
SteamedFood sf = new SteamedFood(rf);
System.out.println(sf.getDesc());
}
}
執(zhí)行結(jié)果:
雞肉
----------------------
烤雞肉
----------------------
蒸烤雞肉