前言 裝飾模式,英文名稱:Decorator Pattern。我第一次看到這個名稱想到的是另外一個詞語“裝修”,我就說說我對“裝修”的理解吧,大家一定要看清楚,是“裝修”,不是“裝飾”。在房子裝修的過程中,各種功能可以相互組合,來增加房子的功用。類似的,如果我們在軟體系統中,要給某個類型或者對象增加 ...
前言
裝飾模式,英文名稱:Decorator Pattern
。我第一次看到這個名稱想到的是另外一個詞語“裝修”,我就說說我對“裝修”的理解吧,大家一定要看清楚,是“裝修”,不是“裝飾”。在房子裝修的過程中,各種功能可以相互組合,來增加房子的功用。類似的,如果我們在軟體系統中,要給某個類型或者對象增加功能,如果使用“繼承”的方案來寫代碼,就會出現子類暴漲的情況。比如:IMarbleStyle是大理石風格的一個功能,IKeepWarm是保溫的一個介面定義,IHouseSecurity是房子安全的一個介面,就三個介面來說,House是我們房子,我們的房子要什麼功能就實現什麼介面,如果房子要的是複合功能,介面不同的組合就有不同的結果,這樣就導致我們子類膨脹嚴重,如果需要在增加功能,子類會成指數增長。
裝飾模式的定義
上述的問題的根源在於我們“過度地使用了繼承來擴展對象的功能”,由於繼承為類型引入的靜態特質,所謂靜態特質,就是說如果想要某種功能,我們必須在編譯的時候就要定義這個類,這也是強類型語言的特點。靜態,就是指在編譯的時候要確定的東西;動態,是指運行時確定的東西。使得這種擴展方式缺乏靈活性;並且隨著子類的增多(擴展功能的增多),各種子類的組合(擴展功能的組合)會導致更多子類的膨脹(多繼承)。如何使“對象功能的擴展”能夠根據需要來動態(即運行時)地實現?同時避免“擴展功能的增多”帶來的子類膨脹問題?從而使得任何“功能擴展變化”所導致的影響降為最低?裝飾者模式解決此問題應運而生,動態地給一個對象增加一些額外的職責。
裝飾模式的組成
-
抽象構件角色(Component):給出一個抽象介面,以規範準備接收附加責任的對象。
-
具體構件角色(Concrete Component):定義一個將要接收附加責任的類。
-
裝飾角色(Decorator):持有一個構件(Component)對象的實例,並實現一個與抽象構件介面一致的介面。
-
具體裝飾角色(Concrete Decorator):負責給構件對象添加上附加的責任。
裝飾模式的實現
以裝修房子為例,完成裝飾著模式的代碼實現
房子定義
/// <summary>
/// 該抽象類就是房子抽象介面的定義,該類型就相當於是Component類型,是餃子餡,需要裝飾的,需要包裝的
/// </summary>
public abstract class House
{
/// <summary>
/// 房子的裝修方法--該操作相當於Component類型的Operation方法
/// </summary>
public abstract void Renovation();
}
/// <summary>
/// MyHouse的房子,我要按我的要求做房子,相當於ConcreteComponent類型
/// </summary>
public sealed class MyHouse : House
{
public override void Renovation()
{
Console.WriteLine("裝修我的房子");
}
}
裝飾類的定義
/// <summary>
/// 該抽象類就是裝飾介面的定義,該類型就相當於是Decorator類型,如果需要具體的功能,可以子類化該類型
/// </summary>
public abstract class DecorationStrategy : House //關鍵點之二,體現關係為Is-a,有了這個關係,裝飾的類也可以繼續裝飾了
{
//通過組合方式引用Decorator類型,該類型實施具體功能的增加
//這是關鍵點之一,包含關係,體現為Has-a
protected House _house;
//通過構造器註入,初始化平臺實現
protected DecorationStrategy(House house)
{
this._house = house;
}
//該方法就相當於Decorator類型的Operation方法
public override void Renovation()
{
if (this._house != null)
{
this._house.Renovation();
}
}
}
安全需求類裝飾定義
/// <summary>
/// 具有安全功能的設備,可以提供監視和報警功能,相當於ConcreteDecoratorA類型
/// </summary>
public sealed class HouseSecurityDecorator : DecorationStrategy
{
public HouseSecurityDecorator(House house) : base(house) { }
public override void Renovation()
{
base.Renovation();
Console.WriteLine("增加安全系統");
}
}
保暖需求類裝飾定義
/// <summary>
/// 具有保溫介面的材料,提供保溫功能,相當於ConcreteDecoratorB類型
/// </summary>
public sealed class KeepWarmDecorator : DecorationStrategy
{
public KeepWarmDecorator(House house) : base(house) { }
public override void Renovation()
{
base.Renovation();
Console.WriteLine("增加保溫的功能");
}
}
調用
public void RunTest()
{
//這就是我們需要裝飾的房子
House myselfHouse = new MyHouse();
DecorationStrategy securityHouse = new HouseSecurityDecorator(myselfHouse);
securityHouse.Renovation();
/*
* 此時房子就有了安全系統了.....
*/
//【1】如果我既要安全系統又要保暖呢,繼續裝飾就行
//DecorationStrategy securityAndWarmHouse = new KeepWarmDecorator(myselfHouse);
//securityAndWarmHouse.Renovation();
Console.WriteLine("\r\n*****************************\r\n");
//【2】如果我既要安全系統又要保暖呢,繼續裝飾就行【和上邊的進行運行比對】
//【對運行結果難理解的話,打斷點單步執行進行理解】
DecorationStrategy securityAndWarmHouse1 = new KeepWarmDecorator(securityHouse);
securityAndWarmHouse1.Renovation();
}
裝飾模式的優缺點
優點
-
把抽象介面與其實現解耦。
-
抽象和實現可以獨立擴展,不會影響到對方。
-
實現細節對客戶透明,對用戶隱藏了具體實現細節。
缺點
- 增加了系統的複雜度
本文來自博客園,作者:碼農阿亮,轉載請註明原文鏈接:https://www.cnblogs.com/wml-it/p/17693849.html
技術的發展日新月異,隨著時間推移,無法保證本博客所有內容的正確性。如有誤導,請大家見諒,歡迎評論區指正!
開源庫地址,歡迎點亮:
GitHub:https://github.com/ITMingliang
Gitee: https://gitee.com/mingliang_it
GitLab: https://gitlab.com/ITMingliang
建群聲明: 本著技術在於分享,方便大家交流學習的初心,特此建立【編程內功修煉交流群】,為大家答疑解惑。熱烈歡迎各位愛交流學習的程式員進群,也希望進群的大佬能不吝分享自己遇到的技術問題和學習心得!進群方式:掃碼關註公眾號,後臺回覆【進群】。