裝飾模式是一種設(shè)計(jì)模式,在不需要更改原有類(lèi)文件和使用繼承的情況下,能夠動(dòng)態(tài)地?cái)U(kuò)展一個(gè)對(duì)象的功能。這種模式通過(guò)創(chuàng)建一個(gè)包裝對(duì)象,即裝飾者,來(lái)封裝實(shí)際的對(duì)象。
定義
裝飾模式,又稱(chēng)Decorator Pattern,是23種設(shè)計(jì)模式之一。它允許在運(yùn)行時(shí)動(dòng)態(tài)地向一個(gè)對(duì)象添加新的行為,而不必修改原有的類(lèi)。裝飾模式通過(guò)創(chuàng)建一個(gè)包裝對(duì)象,即裝飾者,來(lái)封裝實(shí)際的對(duì)象。
特點(diǎn)
裝飾對(duì)象與真實(shí)對(duì)象具有相同的接口,這使得客戶(hù)端對(duì)象能夠以與真實(shí)對(duì)象相同的方式與裝飾對(duì)象交互。
裝飾對(duì)象包含一個(gè)指向真實(shí)對(duì)象的引用。
裝飾對(duì)象接收來(lái)自客戶(hù)端的所有請(qǐng)求,并將其轉(zhuǎn)發(fā)給真實(shí)對(duì)象。
在轉(zhuǎn)發(fā)請(qǐng)求之前或之后,裝飾對(duì)象可以添加額外的功能,從而無(wú)需修改給定對(duì)象的結(jié)構(gòu)即可在運(yùn)行時(shí)添加功能。在面向?qū)ο蟮脑O(shè)計(jì)中,通常通過(guò)繼承來(lái)實(shí)現(xiàn)對(duì)給定類(lèi)的功能擴(kuò)展。
適用性
裝飾模式適用于以下場(chǎng)景:
1. 需要擴(kuò)展一個(gè)類(lèi)的功能,或?yàn)槠涮砑痈郊勇氊?zé)。
2. 動(dòng)態(tài)地為一個(gè)對(duì)象添加功能,且這些功能可以隨時(shí)取消。
3. 增加由基本功能組成的大量功能,使繼承關(guān)系變得不切實(shí)際。
4. 當(dāng)無(wú)法通過(guò)子類(lèi)化來(lái)擴(kuò)展時(shí),如當(dāng)類(lèi)定義被隱藏,或類(lèi)定義不能用于生成子類(lèi)時(shí)。
優(yōu)點(diǎn)
裝飾模式提供了比繼承更靈活的方式來(lái)擴(kuò)展對(duì)象的功能。
通過(guò)使用不同的具體裝飾類(lèi)及其組合,設(shè)計(jì)師可以創(chuàng)造多種不同的行為組合。
缺點(diǎn)
裝飾模式的靈活性也帶來(lái)了更高的復(fù)雜度。
過(guò)度使用裝飾模式可能導(dǎo)致程序結(jié)構(gòu)變得復(fù)雜。
設(shè)計(jì)原則
應(yīng)優(yōu)先考慮組合而非繼承。
類(lèi)的設(shè)計(jì)應(yīng)該對(duì)擴(kuò)展開(kāi)放,對(duì)修改封閉。
模式簡(jiǎn)化
若只有一個(gè)具體的Component類(lèi),則讓Decorator繼承該類(lèi)。
若只有一個(gè)具體的Decorator類(lèi),則可以將Decorator和混凝土 Decorator合并。
相關(guān)區(qū)別
新職責(zé)方面,適配器模式也能在轉(zhuǎn)換時(shí)增加新職責(zé),但其主要目的是轉(zhuǎn)換接口,而裝飾模式的主要目的是為被裝飾者增加新職責(zé)。
接口方面,適配器模式使用新接口調(diào)用原接口,原接口對(duì)于新系統(tǒng)來(lái)說(shuō)是不可見(jiàn)的;而裝飾模式保持原接口不變,系統(tǒng)通過(guò)原接口使用裝飾對(duì)象。
包裹對(duì)象方面,適配器了解被適配者的細(xì)節(jié),而裝飾者只知其接口,具體類(lèi)型則在運(yùn)行時(shí)確定。
實(shí)際使用
Java IO流是裝飾模式的一個(gè)典型例子。
代碼示例
在裝飾模式中,涉及的角色包括:
抽象構(gòu)件(Component)角色:定義一個(gè)接口,規(guī)范準(zhǔn)備接收附加責(zé)任的對(duì)象。
具體構(gòu)件(混凝土 Component)角色:定義一個(gè)將要接收附加責(zé)任的類(lèi)。
裝飾(Decorator)角色:持有構(gòu)件(Component)對(duì)象的實(shí)例,并實(shí)現(xiàn)與抽象構(gòu)件接口一致的接口。
具體裝飾(Concrete Decorator)角色:負(fù)責(zé)為構(gòu)件對(duì)象添加附加的責(zé)任。
以下示例展示了如何使用裝飾模式來(lái)擴(kuò)展現(xiàn)有類(lèi)的功能。其中,ThirdParty.Java表示一個(gè)已有的或第三方的功能,由于某些原因無(wú)法直接修改,它提供了一個(gè)sayMsg()方法。現(xiàn)在我們要在sayMsg()方法中添加一些額外的信息,因此我們編寫(xiě)了一個(gè)Decorator.java類(lèi)。MailTest.java是客戶(hù)端測(cè)試程序。
```java
// IthirdParty.Java--抽象接口類(lèi)
package decorator.saystr;
public 接口 IThirdParty {
public String sayMsg();
}
// ThirdParty.Java--具體類(lèi)
public class ThirdParty implements IThirdParty {
public String sayMsg() {
return "hello";
}
}
// Decorator1.java 具體裝飾類(lèi)1
package decorator.saystr;
public class Decorator1 implements IThirdParty {
private IThirdParty thirdParty;
public Decorator1(IThirdParty thirdParty) {
this.thirdParty = thirdParty;
}
public String sayMsg() {
return "##1" + thirdParty.sayMsg() + "##1";
}
}
// Decorator2.java 具體裝飾類(lèi)2
package decorator.saystr;
public class Decorator2 implements IThirdParty {
private IThirdParty thirdParty;
public Decorator2(IThirdParty thirdParty) {
this.thirdParty = thirdParty;
}
public String sayMsg() {
return "##2" + thirdParty.sayMsg() + "##2";
}
}
// MailTest.java
package decorator.saystr;
public class MailTest {
public static void main(String[] args) {
IThirdParty thirdPartyOne = new ThirdParty();
IThirdParty decorator1 = new Decorator1(thirdPartyOne);
IThirdParty decorator2 = new Decorator2(decorator1);
System.out.println(decorator2.sayMsg());
}
}
```
執(zhí)行結(jié)果為:`##2##1hello##1##2`
參考資料 >
設(shè)計(jì)模式之裝飾模式(Decorator).博客園.2024-11-04
23種設(shè)計(jì)模式之裝飾者(Decorator)模式.掘金開(kāi)發(fā)者社區(qū).2024-11-04
3.裝飾模式.Graphic Design Patterns.2024-11-04