定義:在不改變原類文件以及不使用繼承的情況下理卑,動態(tài)地將責任附加到對象上铅歼,從而實現(xiàn)動態(tài)拓展一個對象的功能。它是通過創(chuàng)建一個包裝對象堤舒,也就是裝飾來包裹真實的對象。
裝飾者模式解決的問題
1.當我們需要為某個現(xiàn)有的對象哺呜,動態(tài)的增加一個新的功能或職責時舌缤,可以考慮使用裝飾模式。
2.當某個對象的職責經(jīng)常發(fā)生變化或者經(jīng)常需要動態(tài)的增加職責,避免為了適應(yīng)這樣的變化国撵,而增加繼承子類擴展的方式陵吸,因為這種方式會造成子類膨脹的速度過快,難以控制介牙。
裝飾者模式的優(yōu)點和缺點
優(yōu)點:1)裝飾類和被裝飾類可以獨立發(fā)展壮虫,而不會相互耦合,Component類無須知道Decorator類环础,Decorator類是從外部來擴展Component類的功能囚似,而Decorator也不用知道具體的構(gòu)件;2)裝飾模式是繼承關(guān)系的一個替代方案线得;3)我們看裝飾類Decorator饶唤,不管裝飾多少層,他始終是一個Component贯钩,實現(xiàn)的還是is-a的關(guān)系,所以他是繼承的一種良好替代方案募狂;4)如果設(shè)計得當,裝飾器類的嵌套順序可以任意,比如一定要注意前提,那就是你的裝飾不依賴順序
缺點:1)裝飾器模式雖然從數(shù)量級上減少了類的數(shù)量,但是為了要裝飾,仍舊會增加很多的小類這些具體的裝飾類的邏輯將不會非常的清晰,不夠直觀,容易令人迷惑;2)裝飾器模式雖然減少了類的爆炸,但是在使用的時候,你就可能需要更多的對象來表示繼承關(guān)系中的一個對象魏保;3)多層的裝飾是比較復(fù)雜,比如查找問題時,被層層嵌套,不容易發(fā)現(xiàn)問題所在
裝飾者模式的設(shè)計要點
- 多用組合熬尺,少用繼承
- 開閉原則:類應(yīng)該對拓展開放,對修改關(guān)閉
裝飾者模式的UML圖
- Component(抽象構(gòu)件)通常是一個抽象類或者一個接口谓罗,定義了屬性或者方法粱哼,方法的實現(xiàn)可以自己實現(xiàn),也可以由子類實現(xiàn)檩咱。通常不會直接使用Component揭措,而是通過繼承Component來實現(xiàn)特定的功能,它約束了整個繼承樹的行為刻蚯。比如說绊含,如果Component代表人,即使通過裝飾也不會使人變成別的動物炊汹。
- ConcreteComponent(具體構(gòu)件)是Component的子類躬充,實現(xiàn)了相應(yīng)的方法,它充當了“被裝飾者”的角色讨便。
- Decorator(抽象裝飾類)也是Component的子類充甚,它是裝飾者共同實現(xiàn)的抽象類(也可以是接口)。比如說霸褒,Decorator代表衣服這一類裝飾者伴找,那么它的子類可以是T恤、裙子之類的裝飾者废菱。
- ConcreteDecorator(具體裝飾類)是Decorator的子類技矮,是具體的裝飾者抖誉,由于它也是Component的子類,因此它能方便地拓展Component的狀態(tài)(比如添加新的方法)衰倦。每個裝飾者都應(yīng)該有一個實例變量用以保存某個Component的引用袒炉,這也是利用了組合的特性。在持有Component的引用后耿币,由于其自身也是Component的子類梳杏,那么,相當于ConcreteDecorator包裹了Component淹接,不但有Component的特性,同時自身也可以有別的特性叛溢,最終實現(xiàn)“裝飾”的效果塑悼。
裝飾者模式實例
抽象構(gòu)件
public abstract class Person {
String description = "I'm a person.";
public String getDescription() {
return description;
}
public abstract double cost();
}
具體構(gòu)件
public class Teenager extends Person {
public Teenager() {
description = "I'm a Teenager.";
}
@Override
public double cost() {
return 0;
}
}
抽象裝飾類
public abstract class ClothingDecorator extends Person {
@Override
public abstract String getDescription();
}
public abstract class HatDecorator extends Person {
@Override
public abstract String getDescription();
}
具體裝飾類
public class Shirt extends ClothingDecorator {
private Person person;
public Shirt(Person person) {
this.person = person;
}
@Override
public double cost() {
return person.cost() + 100;
}
@Override
public String getDescription() {
return person.getDescription() + " buy a shirt";
}
}
public class Casquette extends HatDecorator {
private Person person;
public Casquette(Person person) {
this.person = person;
}
@Override
public String getDescription() {
return person.getDescription() + " buy a casquette";
}
@Override
public double cost() {
return person.cost() + 20;
}
}
測試
public class TeenagerTest {
public static void main(String[] args) {
Person person = new Teenager();
person = new Shirt(person);
person = new Casquette(person);
System.out.println(person.getDescription());
System.out.println(person.cost());
}
}
I'm a Teenager. buy a shirt buy a casquette
120.0
時序圖
裝飾者模式與代理模式
裝飾者模式 | 代理模式 | |
---|---|---|
職能 | 增強對象,擴展對象功能 | 控制對象訪問楷掉,隱藏了控制對象的實現(xiàn)信息 |
實現(xiàn)接口 | 裝飾類和被裝飾類實現(xiàn)相同接口 | 代理類和委托類實現(xiàn)相同接口 |
使用/實現(xiàn)方式 | 通常做法是將原始對象作為參數(shù)傳入裝飾者的構(gòu)造器 | 通常在一個代理類中創(chuàng)建委托類的實例 |
確認時機 | 在運行時通過參數(shù)傳遞 | 編譯時確認依賴關(guān)系 |
無用的裝飾者模式厢蒜?
見參考文獻。
參考文獻
學(xué)習(xí)烹植、探究Java設(shè)計模式——裝飾者模式
設(shè)計模式 | 裝飾者模式及典型應(yīng)用
Java I/O系統(tǒng)----------- 類圖框架
無用的設(shè)計模式之裝飾者模式