問題:
在物件導向系統的設計和開發中,在某些特定的情境下,需要在運行時不改變對象類的前提下動態為已經定義好的對象添加新的職責(操作),使用繼承時將會建立出大量的子類,而且繼承的實現都是靜態,用戶端不能在運行期(runtime)根據環境需要靈活控制改變組合添加的多個功能。
定義:
動態給一個對象添加一些額外的職責。就增加功能來說,裝飾模式比產生子類更加靈活。
意圖:
提供一個Decorator角色,它維護了一個需要裝飾的Component具體對象的索引,Decorator收所有的來自用戶端的請求,轉寄這些請求給Component之前或以後增加一些附加功能來裝飾Component。這樣就確保了在運行時,不用修改給定對象的結構就可以在外部增加附加的功能。Decorator繼承了Component所具有的介面,所以我們可以使用一個或者多個Decorator對象來“裝飾”一個Component對象,且裝飾後的對象仍然是一個Component對象。
參與者:
•抽象組件(Component)角色:
一個抽象介面,是被裝飾類和裝飾類的父介面。裝飾者和被裝飾對象擁有共同一致的介面。
•具體組件(Concrete Component)角色:
具體需要被裝飾的類,他實現了抽象組件介面。
•抽象裝飾(Decorator)角色:
包含一個組件的引用,並定義了與抽象組件一致的介面。
•具體裝飾(Concrete Decorator)角色:
為抽象裝飾角色的實作類別。負責具體的裝飾。
UML:
執行個體說明:
諾基亞手機工廠
手機功能擴充不用修改或重新定義手機工廠,可以為手機裝飾多個功能。
uml圖如下:
代碼:
/// <summary>
/// 抽象組件介面,定義了裝飾者和被裝飾對象擁有共同一致的介面。
/// </summary>
public abstract class ComponentPhone
{
public abstract void ShowPhone();
}
/// <summary>
/// 具體裝飾對象
/// </summary>
public class ComponentN8 : ComponentPhone
{
public override void ShowPhone()
{
System.Console.Write("我是N8手機。");
}
}
/// <summary>
/// 抽象裝飾介面
/// </summary>
public class DecoratorPhone : ComponentPhone
{
ComponentPhone component;
public DecoratorPhone(ComponentPhone _component)
{
component = _component;
}
public override void ShowPhone()
{
if (component != null)
{
component.ShowPhone();
}
}
}
/// <summary>
/// 具體裝飾類
/// </summary>
public class PhoneGPS : DecoratorPhone
{
public PhoneGPS(ComponentPhone _component)
: base(_component)
{
}
public override void ShowPhone()
{
base.ShowPhone();
this.ShowGPS();
}
/// <summary>
/// addedbehavior(),需要裝飾到,被裝飾對象中的方法
/// </summary>
public void ShowGPS()
{
System.Console.Write("我有GPS導航功能!");
}
}
/// <summary>
/// 具體裝飾類
/// </summary>
public class PhoneHFR : DecoratorPhone
{
public PhoneHFR(ComponentPhone _component)
: base(_component)
{
}
public override void ShowPhone()
{
base.ShowPhone();
this.ShowHFR();
}
/// <summary>
/// addedbehavior(),需要裝飾到,被裝飾對象中的方法
/// </summary>
public void ShowHFR()
{
System.Console.Write("我有HFRFace Service功能!");
}
}
/// <summary>
/// 用戶端測試
/// </summary>
public void DecoratorTest()
{
ComponentN8 n8 = new ComponentN8();
DecoratorPhone gps = new PhoneGPS(n8);
DecoratorPhone hfr = new PhoneHFR(gps);
hfr.ShowPhone();
}
優點:
•比繼承更靈活
從為對象添加功能的角度來看,裝飾模式比繼承來得更靈活。繼承是靜態,而且一旦繼承是所有子類都有一樣的功能。而裝飾模式採用把功能分離到每個裝飾器當中,然後通過對象組合的方式,在運行時動態組合功能,每個被裝飾的對象,最終有哪些功能,是由運行期動態組合的功能來決定的。
•更容易複用功能
裝飾模式把一系列複雜的功能,分散到每個裝飾器當中,一般一個裝飾器只實現一個功能,這樣實現裝飾器變得簡單,更重要的是這樣有利於裝飾器功能的複用,可以給一個對象增加多個同樣的裝飾器,也可以把一個裝飾器用來裝飾不同的對象,從而複用裝飾器的功能。
•簡化高層定義
裝飾模式可以通過組合裝飾器的方式,給對象增添任意多的功能,因此在進行高層定義的時候,不用把所有的功能都定義出來,而是定義最基本的就可以了,可以在使用需要的時候,組合相應的裝飾器來完成需要的功能。
缺點:
•會產生很多細粒度對象
裝飾模式是把一系列複雜的功能,分散到每個裝飾器當中,一般一個裝飾器只實現一個功能,這樣會產生很多細粒度的對象,而且功能越複雜,需要的細粒度對象越多。
應用情景:
•在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責。
•如果不合適使用子類來進行擴充的時候