《Head First 設(shè)計(jì)模式》 學(xué)習(xí)筆記鹦聪,碼云同步更新中
如有錯(cuò)誤或不足之處,請(qǐng)一定指出蒂秘,謝謝~
目錄
查看其它設(shè)計(jì)模式筆記泽本,點(diǎn)這里→設(shè)計(jì)模式筆記匯總
裝飾者模式
- 定義:
- 動(dòng)態(tài)地將責(zé)任附加到對(duì)象身上。若要擴(kuò)展功能姻僧,裝飾者提供了比繼承更有彈性的替代方案规丽。
- 特點(diǎn):
- 裝飾者和被裝飾著有共同的超類,裝飾過(guò)的對(duì)象可以替代原始對(duì)象使用
- 可以用一個(gè)或多個(gè)裝飾者包裝一個(gè)對(duì)象
- 裝飾者可以在所委托被裝飾者的行為之前撇贺、之后赌莺,加上自己的行為,來(lái)達(dá)到特定目的
- 注意:
- 這里用到繼承的目的不是“繼承行為”松嘶,而是“類型匹配”雄嚣。對(duì)象的行為來(lái)自于對(duì)象的組合。
這并不違反之前提到的設(shè)計(jì)原則。
- 這里用到繼承的目的不是“繼承行為”松嘶,而是“類型匹配”雄嚣。對(duì)象的行為來(lái)自于對(duì)象的組合。
- 優(yōu)點(diǎn):
- 可以很靈活地?cái)U(kuò)展對(duì)象功能缓升,擴(kuò)展時(shí)符合“開(kāi)閉原則”
- 缺點(diǎn):
- 會(huì)產(chǎn)生很多對(duì)象鼓鲁,增加系統(tǒng)復(fù)雜度,加大學(xué)習(xí)理解成本
- 使用時(shí)更容易出錯(cuò)港谊,錯(cuò)誤排查也更加困難(但結(jié)合工廠模式和生成器模式后會(huì)得到很大改善)
- 案例
- 咖啡價(jià)格計(jì)算程序的最初實(shí)現(xiàn):有一個(gè)咖啡的超類骇吭,所有品種的咖啡都會(huì)繼承他,并定義自己的描述和價(jià)格歧寺。
但帶來(lái)的問(wèn)題是:不僅咖啡種類很多燥狰,當(dāng)加入不同的配料(奶,焦糖斜筐,奶泡龙致,摩卡)時(shí),又會(huì)有不一樣的價(jià)格顷链。
如果這樣實(shí)現(xiàn)目代,會(huì)產(chǎn)生茫茫多的咖啡子類。 - 裝飾者模式改造:
- 一杯加香草嗤练、榛子的美式咖啡的計(jì)價(jià)過(guò)程:
- new一個(gè)美式咖啡對(duì)象
- 用香草對(duì)象裝飾它
- 用榛子對(duì)象裝飾它
- 調(diào)用cost()方法榛了,并依賴委托將配料的價(jià)格加上去
- 一杯加香草嗤练、榛子的美式咖啡的計(jì)價(jià)過(guò)程:
- 咖啡價(jià)格計(jì)算程序的最初實(shí)現(xiàn):有一個(gè)咖啡的超類骇吭,所有品種的咖啡都會(huì)繼承他,并定義自己的描述和價(jià)格歧寺。
- 代碼
/**
* 飲料抽象超類
**/
public abstract class Beverage {
String description = "未知飲料";
public String getDescription() {
return description;
}
// 金額應(yīng)該用BigDecimal
public abstract double cost();
}
/**
* 配料裝飾者超類
* 繼承飲料類
**/
public abstract class CondimentDecorator extends Beverage {
/**
* 這里重寫的目的是約束配料類重寫獲取描述方法,
* 最終拿到完整的描述鏈
* 例如:“美式煞抬,香草霜大,榛子”
*/
@Override
public abstract String getDescription();
}
/**
* 美式咖啡類
*/
public class Americano extends Beverage {
public Americano() {
description = "美式"; // 構(gòu)造方法,修改繼承自超類的description
}
@Override
public double cost() {
return 21; // 返回美式本身的價(jià)格
}
}
/**
* 香草配料
**/
public class Vanilla extends CondimentDecorator {
Beverage beverage; // 用來(lái)記錄被裝飾者
public Vanilla(Beverage beverage) { // 構(gòu)造函數(shù)革答,被裝飾者作為參數(shù)
this.beverage = beverage;
}
@Override
public String getDescription() { // 獲取完整的描述
return beverage.getDescription() + ", 香草";
}
@Override
public double cost() { // 用被裝飾者的價(jià)格加上香草自己的價(jià)格
return 3 + beverage.cost();
}
}
/**
* 榛子配料
**/
public class Hazelnut extends CondimentDecorator {
Beverage beverage;
public Hazelnut(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", 榛子";
}
@Override
public double cost() {
return 5 + beverage.cost();
}
}
/**
* 測(cè)試
*/
public class Test {
public static void main(String[] args) {
Beverage beverage = new Americano();
System.out.println(beverage.getDescription() + " ¥" + beverage.cost());
Beverage beverage2 = new Americano();
// 加香草
beverage2 = new Vanilla(beverage2);
// 加榛子
beverage2 = new Hazelnut(beverage2);
System.out.println(beverage2.getDescription() + " ¥" + beverage2.cost());
}
}
結(jié)果
美式 ¥21.0
美式, 香草, 榛子 ¥29.0
- Java中的裝飾者模式
- java.io 包中有茫茫多的類战坤,但仔細(xì)觀察就會(huì)發(fā)現(xiàn),其中很多類都是裝飾者残拐。
這也體現(xiàn)了裝飾者模式的缺點(diǎn):對(duì)于不明所以的人來(lái)說(shuō)途茫,大料API看起來(lái)會(huì)很困擾。 - 感性去的話可以自己編寫一個(gè)裝飾者來(lái)裝飾io蹦骑,比如把輸入流中的所有小寫字母轉(zhuǎn)為大寫慈省。
- java.io 包中有茫茫多的類战坤,但仔細(xì)觀察就會(huì)發(fā)現(xiàn),其中很多類都是裝飾者残拐。