源代碼:https://gitee.com/AgentXiao/DecroatorPattern
要點:
1监透、裝飾模式解決的問題
2、裝飾模式的各個模塊實現(xiàn)
3航唆、裝飾模式的優(yōu)缺點
4胀蛮、裝飾模式和橋接模式的區(qū)別
一、場景引入
如上圖所示糯钙,有一個狗(Dog)類粪狼,下面有三個子類,分別是會飛的狗(FlyDog)任岸、會游泳的狗(SwimDog)再榄、會跑的狗(RunDog)。假設(shè)此時三個子類都是單一功能的享潜,也就說FlyDog只會飛困鸥,游泳和跑步都不會。
如果此時需要一個既會飛也會跑的狗剑按,我們可以通過繼承的方式實現(xiàn)疾就,一次類推澜术,可以得到:
這顯然不是最好的方法!當(dāng)功能非常多時猬腰,需要繼承父類的子類數(shù)量將會大大增加瘪板!而裝飾模式就是解決這個問題的一種設(shè)計模式。
二漆诽、裝飾模式
裝飾模式是一種用于代替繼承的技術(shù),無需通過繼承增加子類就能夠擴展對象的新功能锣枝。使用對象的組合關(guān)系(區(qū)分于“組合設(shè)計模式”)代替繼承關(guān)系厢拭,避免類型體系的快速膨脹。
簡單地說撇叁,裝飾模式用于動態(tài)增加一個對象的新功能供鸠,或成為功能增強。
裝飾模式實現(xiàn)細節(jié):
(1)抽象構(gòu)建角色Component陨闹。這是真實對象和裝飾對象都需要實現(xiàn)的接口楞捂,便于客戶端可以使用相同的方式交互裝飾對象和真實對象,指上文的Dog趋厉。
(2)真實對象ConcreteComponent寨闹。具體需要裝飾的對象,定義為MyDog君账。
(3)裝飾對象Decorator繁堡。持有一個抽象構(gòu)件的引用(核心)。裝飾對象接受所有客戶端的請求乡数,并把這些請求通過引用轉(zhuǎn)發(fā)給真實對象椭蹄。這樣,就能在真實對象調(diào)用前后增加新的功能净赴,定義為SuperDog绳矩。
(4)具體裝飾對象ConcreteDecorator:指上文的Fly、Swim玖翅、Run翼馆。
三、裝飾模式的實現(xiàn)
1烧栋、抽象角色
/**
* @InterfaceName Dog
* @Description 抽象構(gòu)建角色
* @Author xwd
* @Date 2018/10/25 9:52
*/
public interface Dog {
/**
* @MethodName showPower
* @Descrition 展示能力
* @Param []
* @return void
*/
void showPower();
}
2写妥、具體角色
/**
* @ClassName MyDog
* @Description 具體對象
* @Author xwd
* @Date 2018/10/25 9:53
*/
public class MyDog implements Dog{
@Override
public void showPower() {
System.out.println("我還沒有什么能力!");
}
}
3审姓、裝飾角色(核心)
/**
* @ClassName SuperDog
* @Description 裝飾對象
* @Author xwd
* @Date 2018/10/25 9:54
*/
public class SuperDog implements Dog{
protected Dog dog;//持有抽象構(gòu)建角色的引用
public SuperDog(Dog dog) {
this.dog = dog;
}
@Override
public void showPower() {
dog.showPower();
}
}
4珍特、具體的裝飾角色
/**
* @ClassName Fly
* @Description 飛行能力
* @Author xwd
* @Date 2018/10/25 9:57
*/
public class Fly extends SuperDog{
public Fly(Dog dog) {
super(dog);
}
@Override
public void showPower() {
super.showPower();
System.out.println("我具備飛行功能!");
}
}
/**
* @ClassName Run
* @Description 奔跑能力
* @Author xwd
* @Date 2018/10/25 9:57
*/
public class Run extends SuperDog{
public Run(Dog dog) {
super(dog);
}
@Override
public void showPower() {
super.showPower();
System.out.println("我具備奔跑功能魔吐!");
}
}
/**
* @ClassName Swim
* @Description 游泳能力
* @Author xwd
* @Date 2018/10/25 9:57
*/
public class Swim extends SuperDog{
public Swim(Dog dog) {
super(dog);
}
@Override
public void showPower() {
super.showPower();
System.out.println("我具備游泳功能扎筒!");
}
}
5莱找、測試
/**
* @ClassName Client
* @Description 測試裝飾模式
* @Author xwd
* @Date 2018/10/25 9:59
*/
public class Client {
public static void main(String[] args) {
//原生態(tài)的狗,還沒有什么能力
Dog dog = new MyDog();
dog.showPower();
System.out.println("*********************");
//添加了裝飾模式的狗嗜桌,但是還沒有添加具體功能
SuperDog superDog = new SuperDog(dog);
superDog.showPower();
System.out.println("*********************");
//添加了飛行能力的狗
SuperDog flyDog = new Fly(dog);
flyDog.showPower();
System.out.println("*********************");
//添加了游泳能力的狗
SuperDog swimDog = new Swim(dog);
swimDog.showPower();
System.out.println("*********************");
//既添加了飛行能力又添加了奔跑能力的狗
SuperDog runDog = new Run(dog);
SuperDog fsDog = new Fly(runDog);
fsDog.showPower();
System.out.println("*********************");
}
}
6奥溺、測試結(jié)果
由此可見,需要為一個對象添加新功能時骨宠,只需要建立這個功能浮定,將具體對象傳入。如果傳入的對象是已經(jīng)具備某些功能的层亿,就相當(dāng)遠在那個基礎(chǔ)上添加新的功能桦卒。
四、開發(fā)中使用的場景
- IO中輸入流和輸出流的設(shè)計匿又。
- Swing包中圖形界面構(gòu)件功能方灾。
- Servlet API 中提供了一個request對象的Decorator設(shè)計模式的默認實現(xiàn)類HttpServletRequestWrapper,HttpServletRequestWrapper類碌更,增強了request對象的功能裕偿。
- Struts2中,request痛单,response,session對象的處理嘿棘。
在這里只解釋其中一種:
在IO流中,抽象構(gòu)建對象是InputStream桦他、OutputStream蔫巩、Reader、Writer快压。
真實對象是FileInputStream圆仔、FileOutputStream。
裝飾對象是FilterInputStream蔫劣、FilterOutputStream坪郭。
具體的裝飾對象:BufferedOutputStream、BufferedInputStream等脉幢。
五歪沃、總結(jié)
1、功能
裝飾模式(Decorator)也叫包裝器模式(Wrapper)嫌松。
裝飾模式降低系統(tǒng)的耦合度沪曙,可以動態(tài)的增加或刪除對象的職責(zé),并使得需要裝飾的具體構(gòu)建類和具體裝飾類可以獨立變化萎羔,以便增加新的具體構(gòu)建類和具體裝飾類液走。
2、優(yōu)點
- 擴展對象功能,比繼承靈活缘眶,不會導(dǎo)致類個數(shù)急劇增加嘱根。
- 可以對一個對象進行多次裝飾,創(chuàng)造出不同行為的組合巷懈,得到功能更加強大的對象该抒。
- 具體構(gòu)建類和具體裝飾類可以獨立變化,用戶可以根據(jù)需要自己增加新的具體構(gòu)件子類和具體裝飾子類顶燕。
3凑保、缺點
- 產(chǎn)生很多小對象。大量小對象占據(jù)內(nèi)存涌攻,一定程度上影響性能愉适。
- 裝飾模式易于出錯,調(diào)試排查比較麻煩癣漆。
4、裝飾模式和橋接模式的區(qū)別
兩個模式都是為了解決過多子類對象問題剂买。但他們的誘因不一樣惠爽。
- 橋接模式是對象自身現(xiàn)有機制沿著多個維度變化。
- 裝飾模式是為了增加新的功能瞬哼。