源碼地址 | https://github.com/DingMouRen/DesignPattern |
---|
- Component:抽象組件,可以是一個(gè)接口或者抽象類距糖,是被裝飾的原始對(duì)象缸剪。
- ConcreteComponent:組件具體實(shí)現(xiàn)類唬渗。該類是Component類的基本實(shí)現(xiàn),也是我們裝飾的具體對(duì)象撑蒜。
- Decorator:抽象裝飾者狸眼。它承擔(dān)的職責(zé)是為了裝飾組件對(duì)象,其內(nèi)部一定要有一個(gè)指向組件對(duì)象的引用微王。在多數(shù)情況下,該類為抽象類激才,需要根據(jù)不同的裝飾邏輯實(shí)現(xiàn)不同的具體子類东帅。如果裝飾邏輯單一靠闭,只有一個(gè)情況下我們可以省略該類直接作為具體的裝飾者。
- ConcreteDecoratorA:裝飾者具體實(shí)現(xiàn)類,只是對(duì)抽象裝飾者作出具體的實(shí)現(xiàn)蟀悦。
定義
裝飾者模式動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)孙乖。在增加功能方面鼓拧,裝飾者模式比生成子類更為靈活。
使用場(chǎng)景
- 在不影響其他對(duì)象的情況下,以動(dòng)態(tài)、透明的方式給單個(gè)對(duì)象添加功能
- 處理可以撤銷的職責(zé)
- 當(dāng)不能采用生成子類的方式進(jìn)行擴(kuò)展功能時(shí)都哭。1.為類擴(kuò)展功能造成產(chǎn)生大量子類,子類數(shù)目爆炸性增長(zhǎng)穆趴。2.不能生成子類的情況,比如被final修飾的類
協(xié)作
Decorator將請(qǐng)求轉(zhuǎn)發(fā)給它的Component對(duì)象,并有可能在轉(zhuǎn)發(fā)請(qǐng)求前后執(zhí)行一些附加的動(dòng)作化戳,也就是想要添加的新行為递鹉。
舉個(gè)栗子
不管男的女的都是要穿衣服的,我們抽象成一個(gè)抽象類Person却盘,行為就是穿衣服,定義一個(gè)穿衣服的抽象方法dressed(),定義兩個(gè)類Boy、Girl分別繼承Person類,它們只有一個(gè)行為。假設(shè)Boy Girl都通過調(diào)用自己實(shí)現(xiàn)的dressed()方法竹挡,已經(jīng)穿了一件衣服,可是人不能只穿一件衣服吧(o)/~,但是我們不想去修改Boy Gril的對(duì)象,同時(shí)讓創(chuàng)建出來的這兩個(gè)實(shí)例對(duì)象能穿更多的衣服,也就是說在不影響對(duì)象的情況下贤重,為對(duì)象添加功能滚停。好啦镰吵,可以開始使用裝飾者模式了。我們定義一個(gè)裝飾的抽象類PersonCloth勺馆,讓它繼承抽象組件Person類悲柱,同時(shí)我們讓PersonCloth類持有一個(gè)Person類的引用,通過構(gòu)造器傳入。因?yàn)槔^承了Person類派任,就要實(shí)現(xiàn)dressed()這個(gè)抽象方法颤诀,里面的具體實(shí)現(xiàn)自然是Person類的引用調(diào)用dressed()屈暗,這就是保存這個(gè)引用的主要原因,可以方便的調(diào)用具體被裝飾對(duì)象的dressed()方法(java運(yùn)行時(shí)類型判斷)『偌埽現(xiàn)在我們要定義裝飾者的具體實(shí)現(xiàn)對(duì)象,定義CheapCloth類繼承PersonCloth類,實(shí)現(xiàn)dressed()方法西乖,這里面有一個(gè)super.dressed()這就是被裝飾對(duì)象自己原來的實(shí)現(xiàn),我們想添加的行為怎么辦呢?只要在CheapCloth這個(gè)具體裝飾對(duì)象中定義新的行為矫膨,然后在super.dressed()前或者后調(diào)用就可以了谊娇,這樣就添加了功能攀例,調(diào)用的時(shí)候自然調(diào)用的是這個(gè)裝飾者對(duì)象CheapCloth的dressed()方法。就好像通過CheapCloth類包裹了Boy類一樣垛吗,我們沒有動(dòng)Boy這樣的具體組件對(duì)象,也沒有使用繼承可能會(huì)造成類爆炸的方式。
//抽象組件類:類Person定義一個(gè)穿衣的抽象方法
public abstract class Person {
public abstract void dressed();
}
//組件具體實(shí)現(xiàn)類:需要被裝飾的具體對(duì)象
public class Boy extends Person {
@Override
public void dressed() {
System.out.println(getClass().getSimpleName()+"穿牛仔褂");
}
}
//裝飾抽象類:表示人要穿的衣服
public abstract class PersonCloth extends Person{
/**
* 保持一個(gè)Person類的引用狼牺,方便調(diào)用具體被裝飾對(duì)象中的方法
* 這樣可以在不破壞原類層次結(jié)構(gòu)的情況下為類添加一些功能是钥,只需要在被裝飾對(duì)象的相應(yīng)方法
* 前或后增加相應(yīng)的邏輯功能就行。
* 如果裝飾物只有一個(gè)的話领铐,不必聲明一個(gè)抽象類作為裝飾者抽象的提取。只要定義一個(gè)普通的類表示裝飾者就行
*/
private Person person;
public PersonCloth(Person person) {
this.person = person;
}
@Override
public void dressed() {
person.dressed();//調(diào)用Person類型的dressed()方法
}
public Person getPerson() {
return person;
}
}
//具體裝飾者
public class CheapCloth extends PersonCloth {
public CheapCloth(Person person) {
super(person);
}
@Override
public void dressed() {
//原來具體組件實(shí)現(xiàn)
super.dressed();
//添加的新行為的具體實(shí)現(xiàn)
dressShorts();
}
private void dressShorts(){
System.out.println(getPerson().getClass().getSimpleName()+"穿短褲");
}
}
public static void main(String[] args) {
//創(chuàng)建被裝飾對(duì)象
Person person = new Boy();
//給他穿便宜衣服
PersonCloth clothCheap = new CheapCloth(person);
clothCheap.dressed();
//穿貴的衣服
PersonCloth clothExpensive = new ExpensiveCloth(person);
clothExpensive.dressed();
Person girl = new Girl();
PersonCloth clothCheapGirl = new CheapCloth(girl);
clothCheapGirl.dressed();
}
使用
public static void main(String[] args) {
//創(chuàng)建被裝飾對(duì)象
Person person = new Boy();
//給他穿便宜衣服
PersonCloth clothCheap = new CheapCloth(person);
clothCheap.dressed();
//穿貴的衣服
PersonCloth clothExpensive = new ExpensiveCloth(person);
clothExpensive.dressed();
Person girl = new Girl();
PersonCloth clothCheapGirl = new CheapCloth(girl);
clothCheapGirl.dressed();
}
總結(jié)
裝飾者模式為所裝飾的對(duì)象增加功能糠亩,而不使用繼承的方式,也不會(huì)影響被裝飾對(duì)象党远。有的時(shí)候會(huì)跟代理模式混淆削解,代理模式做的不是增加功能,而是對(duì)代理的對(duì)象進(jìn)行控制沟娱。