裝飾器模式
裝飾器模式(Decorator Pattern)允許向一個(gè)現(xiàn)有的對(duì)象添加新的功能,同時(shí)又不改變其結(jié)構(gòu)。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它是作為現(xiàn)有的類的一個(gè)包裝。
這種模式創(chuàng)建了一個(gè)裝飾類,用來(lái)包裝原有的類,并在保持類方法簽名完整性的前提下,提供了額外的功能。
介紹
意圖: 動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來(lái)說(shuō),裝飾器模式相比生成子類更為靈活。
主要解決: 一般的,我們?yōu)榱藬U(kuò)展一個(gè)類經(jīng)常使用繼承方式實(shí)現(xiàn),由于繼承為類引入靜態(tài)特征,并且隨著擴(kuò)展功能的增多,子類會(huì)很膨脹。
何時(shí)使用:在不想增加很多子類的情況下擴(kuò)展類。
如何解決: 將具體功能職責(zé)劃分,同時(shí)繼承裝飾者模式。
關(guān)鍵代碼:
- Component 類充當(dāng)抽象角色,不應(yīng)該具體實(shí)現(xiàn)。
- 修飾類引用和繼承 Component 類,具體擴(kuò)展類重寫父類方法。
優(yōu)點(diǎn): 裝飾類和被裝飾類可以獨(dú)立發(fā)展,不會(huì)相互耦合,裝飾模式是繼承的一個(gè)替代模式,裝飾模式可以動(dòng)態(tài)擴(kuò)展一個(gè)實(shí)現(xiàn)類的功能。
缺點(diǎn): 多層裝飾比較復(fù)雜。(無(wú)法直觀的了解一個(gè)被裝飾類的全貌)
使用場(chǎng)景:
- 擴(kuò)展一個(gè)類的功能。
- 動(dòng)態(tài)增加功能,動(dòng)態(tài)撤銷。
裝飾模式和橋接模式的區(qū)別: 兩個(gè)模式都是為了解決過(guò)多子類對(duì)象問(wèn)題。但他們的誘因不一樣。橋接模式是對(duì)象自身現(xiàn)有機(jī)制沿著多個(gè)維度變化,是既有部分不穩(wěn)定。裝飾模式是為了增加新的功能。
注意事項(xiàng):可代替繼承。
實(shí)現(xiàn)
學(xué)習(xí)就是一種裝飾器模式(假設(shè)學(xué)到的知識(shí)不會(huì)忘記),我們不斷的學(xué)習(xí)就是不斷的給被裝飾類加上新的裝飾器。
步驟一:
創(chuàng)建學(xué)習(xí)接口(Learn):
/**
* @see 具體學(xué)習(xí)的技能(這里作用為輸出自己學(xué)到的技能)
* @author Thornhill
*
*/
public interface Learn {
public void learnSkills();
}
步驟二:
創(chuàng)建具體實(shí)現(xiàn)學(xué)習(xí)接口的學(xué)生(Student):
/**
* @see 實(shí)現(xiàn)了學(xué)習(xí)接口的學(xué)生,這里是被修飾者的角色
* @author Thornhill
*
*/
public class Student implements Learn {
private String name;
public Student(String name) {
this.name = name;
}
@Override
public void learnSkills() {
System.out.println(name + "學(xué)會(huì)了技能:");
}
}
步驟三:
創(chuàng)建裝飾角色(Skills):
/**
* @see 裝飾者的基類,持有一個(gè)學(xué)習(xí)者對(duì)象,被裝飾時(shí)共享一個(gè)學(xué)習(xí)對(duì)象
* @author Thornhill
*
*/
public class Skills implements Learn {
private Learn learner;
public Skills(Learn learner) {
this.learner = learner;
}
@Override
public void learnSkills() {
if (learner != null) {
learner.learnSkills();
}
}
}
步驟四:
創(chuàng)建實(shí)際修飾角色(CSkills):
/**
* @see 具體修飾者角色,最高層繼承于修飾者(Sills),為了給同一個(gè)方法靈活疊加新的方法,多層繼承于自己。
* @author Thornhill
*
*/
public class CSkills extends Skills {
private String skillName;
public CSkills(Learn learner, String skillName) {
super(learner);
this.skillName = skillName;
}
@Override
public void learnSkills() {
super.learnSkills();
System.out.println(" " + skillName);
}
}
步驟五:
測(cè)試功能:
public class DecoratorPatternDemo {
public static void main(String[] args) {
// 創(chuàng)建學(xué)生“小明”
Learn xiaoming = new Student("小明");
// 創(chuàng)建修飾者“skills”
Skills skills = new Skills(xiaoming);
// 多層修飾skill
// 即模擬小明多次學(xué)習(xí)新技能
skills = new CSkills(skills, "Java");
skills = new CSkills(skills, "Python");
skills = new CSkills(skills, "Hadoop");
// 輸出小明的技能
skills.learnSkills();
}
}
步驟六:
測(cè)試輸出:
小明學(xué)會(huì)了技能:
Java
Python
Hadoop
結(jié)語(yǔ):
個(gè)人認(rèn)為,裝飾模式即不適用繼承的方式,通過(guò)裝飾者和實(shí)際裝飾者的多次復(fù)合,達(dá)到多次重寫(修飾)需要修飾的方法的目的。