【23種設計模式】裝飾模式(九)

来源:https://www.cnblogs.com/wml-it/archive/2023/09/12/17693849.html
-Advertisement-
Play Games

前言 裝飾模式,英文名稱:Decorator Pattern。我第一次看到這個名稱想到的是另外一個詞語“裝修”,我就說說我對“裝修”的理解吧,大家一定要看清楚,是“裝修”,不是“裝飾”。在房子裝修的過程中,各種功能可以相互組合,來增加房子的功用。類似的,如果我們在軟體系統中,要給某個類型或者對象增加 ...


前言

裝飾模式,英文名稱:Decorator Pattern。我第一次看到這個名稱想到的是另外一個詞語“裝修”,我就說說我對“裝修”的理解吧,大家一定要看清楚,是“裝修”,不是“裝飾”。在房子裝修的過程中,各種功能可以相互組合,來增加房子的功用。類似的,如果我們在軟體系統中,要給某個類型或者對象增加功能,如果使用“繼承”的方案來寫代碼,就會出現子類暴漲的情況。比如:IMarbleStyle是大理石風格的一個功能,IKeepWarm是保溫的一個介面定義,IHouseSecurity是房子安全的一個介面,就三個介面來說,House是我們房子,我們的房子要什麼功能就實現什麼介面,如果房子要的是複合功能,介面不同的組合就有不同的結果,這樣就導致我們子類膨脹嚴重,如果需要在增加功能,子類會成指數增長。

裝飾模式的定義

上述的問題的根源在於我們“過度地使用了繼承來擴展對象的功能”,由於繼承為類型引入的靜態特質,所謂靜態特質,就是說如果想要某種功能,我們必須在編譯的時候就要定義這個類,這也是強類型語言的特點。靜態,就是指在編譯的時候要確定的東西;動態,是指運行時確定的東西。使得這種擴展方式缺乏靈活性;並且隨著子類的增多(擴展功能的增多),各種子類的組合(擴展功能的組合)會導致更多子類的膨脹(多繼承)。如何使“對象功能的擴展”能夠根據需要來動態(即運行時)地實現?同時避免“擴展功能的增多”帶來的子類膨脹問題?從而使得任何“功能擴展變化”所導致的影響降為最低?裝飾者模式解決此問題應運而生,動態地給一個對象增加一些額外的職責。

裝飾模式的組成

  • 抽象構件角色(Component):給出一個抽象介面,以規範準備接收附加責任的對象。

  • 具體構件角色(Concrete Component):定義一個將要接收附加責任的類。

  • 裝飾角色(Decorator):持有一個構件(Component)對象的實例,並實現一個與抽象構件介面一致的介面。

  • 具體裝飾角色(Concrete Decorator):負責給構件對象添加上附加的責任。
    image

裝飾模式的實現

以裝修房子為例,完成裝飾著模式的代碼實現

房子定義
    /// <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();
        }

image

裝飾模式的優缺點

優點
  • 把抽象介面與其實現解耦。

  • 抽象和實現可以獨立擴展,不會影響到對方。

  • 實現細節對客戶透明,對用戶隱藏了具體實現細節。

缺點
  • 增加了系統的複雜度

本文來自博客園,作者:碼農阿亮,轉載請註明原文鏈接: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

建群聲明: 本著技術在於分享,方便大家交流學習的初心,特此建立【編程內功修煉交流群】,為大家答疑解惑。熱烈歡迎各位愛交流學習的程式員進群,也希望進群的大佬能不吝分享自己遇到的技術問題和學習心得!進群方式:掃碼關註公眾號,後臺回覆【進群】。



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 二叉樹(binary tree) 二叉樹(Binary Tree)是一種常見的樹狀數據結構,它由一組節點組成,每個節點最多有兩個子節點,分別稱為左子節點和右子節點。二叉樹具有以下特點: 每個節點最多有兩個子節點,分別稱為左子節點和右子節點。 左子樹和右子樹也是二叉樹,它們的結構與父節點類似。 二叉樹 ...
  • 來源:https://www.cnblogs.com/zisefeizhu/p/13692782.html 前言 我司的集群時刻處於崩潰的邊緣,通過近三個月的掌握,發現我司的集群不穩定的原因有以下幾點: 1、發版流程不穩定 2、缺少監控平臺【最重要的原因】 3、缺少日誌系統 4、極度缺少有關操作文檔 ...
  • 面試題:@Transactional聲明式事務註解什麼時候會失效 前言 今天來分享一道比較有意思的面試題,“@Transactional聲明式事務註解什麼時候會失效?”。 對於這個問題,我們一起看看考察點和比較好的回答吧! 考察點 這個問題就是面試官想考察我們對@Transactional註解有沒有 ...
  • 歡迎訪問我的GitHub 這裡分類和彙總了欣宸的全部原創(含配套源碼):https://github.com/zq2599/blog_demos 關於LeetCode98 做這道題之前,我反覆審題,最後確認:沒錯,不存在什麼坑,這道題確實非常非常簡單,然而卻被官方定義為中等難度 這一定是送分,白撿一 ...
  • 上一篇《如何正確實現一個自定義 Exception》發佈後獲得不少 star。有同學表示很擔憂,原來自己這麼多年一直寫錯了。其實大家不用過分糾結,如果寫的是 .NET CORE 1.0+ 的程式,那麼大概率是沒有問題的。 有大佬已經在評論區指出這些信息是過時的了。確實在.NET CORE 發佈之後, ...
  • C#常用的五種定時器分別是: System.Timers.Timer System.Threading.Timer System.Windows.Threading.DispatcherTimer : WPF應用程式 System.Windows.Forms.Timer :WinForm應用程式 S ...
  • .Net Framework使用Autofac實現依賴註入 前言 最近也是找了快2周的工作了,收到的面試邀請也就幾個,然後有個面試題目是用asp.net mvc + Entityframework 做一個學生信息增刪改查系統。因為題目要求了用Entityframework 也就是EF 那也就不上co ...
  • Unity 性能優化之Shader分析處理函數ShaderUtil.HasProceduralInstancing: 深入解析與實用案例 點擊封面跳轉到Unity國際版下載頁面 簡介 在Unity中,性能優化是游戲開發過程中非常重要的一環。其中,Shader的優化對於游戲的性能提升起著至關重要的作用 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...