網站首頁 編程語言 正文
一、動機(Motivate)
在房子裝修的過程中,各種功能可以相互組合,來增加房子的功用。類似的,如果我們在軟件系統中,要給某個類型或者對象增加功能,如果使用“繼承”的方案來寫代碼,就會出現子類暴漲的情況。比如:IMarbleStyle是大理石風格的一個功能,IKeepWarm是保溫的一個接口定義,IHouseSecurity是房子安全的一個接口,就三個接口來說,House是我們房子,我們的房子要什么功能就實現什么接口,如果房子要的是復合功能,接口不同的組合就有不同的結果,這樣就導致我們子類膨脹嚴重,如果需要在增加功能,子類會成指數增長。這個問題的根源在于我們“過度地使用了繼承來擴展對象的功能”,由于繼承為類型引入的靜態特質(所謂靜態特質,就是說如果想要某種功能,我們必須在編譯的時候就要定義這個類,這也是強類型語言的特點。靜態,就是指在編譯的時候要確定的東西;動態,是指運行時確定的東西),使得這種擴展方式缺乏靈活性;并且隨著子類的增多(擴展功能的增多),各種子類的組合(擴展功能的組合)會導致更多子類的膨脹(多繼承)。如何使“對象功能的擴展”能夠根據需要來動態(即運行時)地實現?同時避免“擴展功能的增多”帶來的子類膨脹問題?從而使得任何“功能擴展變化”所導致的影響降為最低?
二、意圖(Intent)
動態地給一個對象增加一些額外的職責。就增加功能而言,Decorator模式比生成子類更為靈活。??????? ——? 《設計模式》GoF
三、結構圖(Structure)
四、模式的組成
在裝飾模式中的各個角色有:
(1)、抽象構件角色(Component):給出一個抽象接口,以規范準備接收附加責任的對象。
(2)、具體構件角色(Concrete Component):定義一個將要接收附加責任的類。
(3)、裝飾角色(Decorator):持有一個構件(Component)對象的實例,并實現一個與抽象構件接口一致的接口。
(4)、具體裝飾角色(Concrete Decorator):負責給構件對象添加上附加的責任。
五 、裝飾模式的具體代碼實現
繼續拿蓋房子來說事吧。
/// <summary>
/// 該抽象類就是房子抽象接口的定義,該類型就相當于是Component類型,是餃子餡,需要裝飾的,需要包裝的
/// </summary>
public abstract class House
{
public abstract void Renovation();//房子的裝修方法--該操作相當于Component類型的Operation方法
}
/// <summary>
/// 該抽象類就是裝飾接口的定義,該類型就相當于是Decorator類型,如果需要具體的功能,可以子類化該類型
/// </summary>
public abstract class DecorationStrategy : House //關鍵點之二,體現關系為Is-a,有這這個關系,裝飾的類也可以繼續裝飾了
{
//通過組合方式引用Decorator類型,該類型實施具體功能的增加這是關鍵點之一,包含關系,體現為Has-a
protected House _house;
protected DecorationStrategy(House house)//通過構造器注入,初始化平臺實現
{
this._house = house;
}
public override void Renovation() //該方法就相當于Decorator類型的Operation方法
{
if (this._house != null)
{
this._house.Renovation();
}
}
}
/// <summary>
/// PatrickLiu的房子,我要按我的要求做房子,相當于ConcreteComponent類型,這就是我們具體的餃子餡,我個人比較喜歡韭菜餡
/// </summary>
public sealed class MyHouse : House
{
public override void Renovation()
{
Console.WriteLine("裝修PatrickLiu的房子");
}
}
/// <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 class Program
{
static void Main()
{
House myselfHouse = new MyHouse();//這就是我們的餃子餡,需要裝飾的房子
DecorationStrategy securityHouse = new HouseSecurityDecorator(myselfHouse);
securityHouse.Renovation();
//房子就有了安全系統了
//如果我既要安全系統又要保暖呢,繼續裝飾就行
DecorationStrategy securityAndWarmHouse = new HouseSecurityDecorator(securityHouse);
securityAndWarmHouse.Renovation();
}
}
六、裝飾模式的實現要點:
- 通過采用組合、而非繼承的手法,Decorator模式實現了在運行時動態地擴展對象功能的能力,而且可以根據需要擴展多個功能。避免了單獨使用繼承帶來的“靈活性差”和“多子類衍生問題”。
- Component類在Decorator模式中充當抽象接口的角色,不應該去實現具體的行為。而且Decorator類對于Component類應該透明——換言之Component類無需知道Decorator類,Decorator類是從外部來擴展Component類的功能。
- Decorator類在接口上表現為is-a Component的繼承關系,即Decorator類繼承了Component類所具有的接口。但在實現上又表現為has-a Component的組合關系,即Decorator類又使用了另外一個Component類。我們可以使用一個或者多個Decorator對象來“裝飾”一個Component對象,且裝飾后的對象仍然是一個Component對象。
- Decorator模式并非解決“多子類衍生的多繼承”問題,Decorator模式應用的要點在于解決“主體類在多個方向上的擴展功能”——是為“裝飾”的含義。
1、裝飾模式的優點:
- 把抽象接口與其實現解耦。
- 抽象和實現可以獨立擴展,不會影響到對方。
- 實現細節對客戶透明,對用于隱藏了具體實現細節。
2、裝飾模式的缺點:
- 增加了系統的復雜度
3、在以下情況下應當使用橋接模式:
- 如果一個系統需要在構件的抽象化角色和具體化角色之間添加更多的靈活性,避免在兩個層次之間建立靜態的聯系。
- 設計要求實現化角色的任何改變不應當影響客戶端,或者實現化角色的改變對客戶端是完全透明的。
- 需要跨越多個平臺的圖形和窗口系統上。
- 一個類存在兩個獨立變化的維度,且兩個維度都需要進行擴展。
七、.NET 中裝飾模式的實現
在Net框架中,有一個類型很明顯的使用了“裝飾模式”,這個類型就是Stream。Stream類型是一個抽象接口,它在System.IO命名空間里面,它其實就是Component。FileStream、NetworkStream、MemoryStream都是實體類ConcreteComponent。右邊的BufferedStream、CryptoStream是裝飾對象,它們都是繼承了Stream接口的。
如圖:
Stream就相當于Component,定義裝飾的對象,FileStream就是要裝飾的對象,BufferedStream是裝飾對象。我們看看BufferedStream的定義,部分定義了。
public sealed class BufferedStream : Stream
{
private const int _DefaultBufferSize = 4096;
private Stream _stream;
}
原文鏈接:https://www.cnblogs.com/springsnow/p/11310438.html
相關推薦
- 2021-12-06 Flutter多項選擇彈窗實現詳解_Android
- 2023-03-20 C#中程序自刪除實現方法_C#教程
- 2022-08-16 C#獲取Description特性的擴展類詳解_C#教程
- 2023-01-07 Flutter?Widget開發之Focus組件圖文詳解_Android
- 2021-12-07 Linux下Hbase安裝配置教程_Linux
- 2022-12-16 python實例方法的使用注意及代碼實例_python
- 2023-02-01 Bat腳本-timeout?命令(延時執行)_DOS/BAT
- 2022-07-12 CSS樣式:樣式的沖突 樣式的繼承 偽元素 偽類
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支