通俗易懂設計模式解析——裝飾模式

  • 2019 年 10 月 3 日
  • 筆記

前言

  今天介紹的是結構型設計模式中的——裝飾模式(Decorator Pattern),也是裝飾器模式。裝飾也就是裝點修飾。例如我們對手機進行裝飾,買了一個新的手機,先貼個鋼化膜。在帶一個殼。偶爾還在背面貼點貼紙。裝一些掛件。這些等等行為也就是裝飾。生活中的裝飾是如此,那麼編程中的裝飾模式又是如何呢?

裝飾模式介紹

一、來由

  在我們平常的軟件系統中,經常會面臨著向現有的對象添加一些新的功能或者新的職責,但是呢?又不能修改現有的類。以往常用的可能是繼承來解決次問題。但是採用繼承來說,隨着擴展功能的增加,子類會變化的很膨脹。那麼裝飾器模式呢就解決這麼一個問題,裝飾器模式允許向一個現有的對象添加新的功能職責,同時又不改變其結構。將其功能職責劃分。

二、意圖

  動態地給一個對象添加一些額外的職責。就增加功能來說,裝飾器模式相比生成子類更為靈活。

三、案例圖

 

 

 

四、裝飾模式代碼示例

看上述案例圖,裝飾模式包含以下部分組成:

抽象構件角色給出一個抽象接口,以規範準備接收新加的責任

具體構件角色繼承抽象構件角色,定義一個將要接收新加責任的類

裝飾角色繼承抽象構件角色,包含一個構件角色對象的實例,並且實現抽象構件角色的接口

具體裝飾角色繼承裝飾角色,負責新加責任。

 

我們繼續看手機的案例,今天新買了一個手機,需要新加鋼化膜,手機殼,然後才是一個我想要的手機。在這兒之後突然又想加一個掛件增加美感。我們看下如何使用裝飾模式來實現手機裝飾的問題吧:

 

namespace Decorator_Pattern  {      class DecoratorPattern      {      }      #region 抽象構件角色——抽象手機(抽象一個接口,準備接收新增的責任)=========      /// <summary>      /// 手機抽象類      /// </summary>      public abstract class Phone      {          public abstract void Write();      }      #endregion      #region 具體抽象構件角色——具體手機(實現抽象接口)===============================      public class HuaweiV9Phone : Phone      {          public override void Write()          {              Console.WriteLine("對榮耀V9手機開始裝飾");          }      }      #endregion      #region 裝飾抽象角色——繼承抽象構件角色,包含一個抽象構件角色對象的實例     /// <summary>     /// 裝飾角色     /// </summary>      public abstract class Decorator : Phone      {          public Phone _phone;          protected Decorator(Phone phone)          {              this._phone = phone;          }          public override void Write()          {              if (_phone!=null)              {                  _phone.Write();              }          }      }      #endregion      #region 具體裝飾角色——手機加上鋼化膜      /// <summary>      /// 具體裝飾角色      /// </summary>      public class Membrane : Decorator      {          public Membrane(Phone phone) : base(phone) { }          public override void Write()          {              base.Write();              AddMembrane();          }          public void AddMembrane()          {              Console.WriteLine("手機加上了鋼化膜!");          }      }      #endregion        #region 具體裝飾角色——手機加上殼      /// <summary>      /// 具體裝飾角色      /// </summary>      public class Shell : Decorator      {          public Shell(Phone phone) : base(phone) { }          public override void Write()          {              base.Write();              AddShell();          }          public void AddShell()          {              Console.WriteLine("手機加上了殼!");          }      }      #endregion        #region 具體裝飾角色——手機掛件      /// <summary>      /// 具體裝飾角色      /// </summary>      public class Pendant : Decorator      {          public Pendant(Phone phone) : base(phone) { }          public override void Write()          {              base.Write();              AddPendant();          }          public void AddPendant()          {              Console.WriteLine("手機加上了掛件!");          }      }      #endregion  }

 

    class Program      {          static void Main(string[] args)          {              //現在獲得了一個手機              Phone phone = new HuaweiV9Phone();                //裸機一個,先貼個膜              Decorator membrane = new Membrane(phone);              membrane.Write();              Console.WriteLine();                //還是覺得不順眼,再加個外殼看看              Decorator membraneShell = new Shell(membrane);              //現在我同時有鋼化膜和外殼了              membraneShell.Write();              Console.WriteLine( );                //這時候我覺得還是不要外殼了。我需要同時又鋼化膜和手機掛件              Decorator membranePendant = new Pendant(membrane);              membranePendant.Write();              Console.WriteLine();                  Console.ReadLine();          }      }

 

使用場景及優缺點

一、使用場景

1、需要擴展類的功能或者為類增加新增的責任

2、需要動態增加功能或者撤銷功能

二、優點

1、裝飾類與被裝飾類可以獨立發展,不會互相耦合, 極易擴展、符合開閉原則

2、裝飾模式與繼承關係的目的都是要擴展對象的功能,但是裝飾模式可以提供比繼承更多的靈活性。

三、缺點

1、增加系統複雜度,更加易於出錯,難於排查錯誤。增大了學習與理解的難度。

總結

  裝飾模式到這裡就短暫的介紹完了。在平常中,裝飾模式使用的情況較多。一般來說,我們擴展一個類經常選擇繼承的方式,但是由於繼承是為類引入靜態的特徵。並且隨着功能增加的越來越多,子類會越來越膨脹。裝飾模式是可以替代繼承方式的。前面結構型的設計模式也學習了適配器模式與橋接模式。再加上今天學習的裝飾模式。我們都需要細細分析其區別及使用場景,以便於後期使用時不至於混淆其用法。要用的恰到好處。

只有經歷過地獄般的折磨,才有征服天堂的力量。只有流過血的手指才能彈出世間的絕唱。

    C#設計模式系列目錄

歡迎大家掃描下方二維碼,和我一起踏上設計模式的闖關之路吧!