設計模式之-裝飾模式

定義:

裝飾模式(Decorator Pattern) :動態地給一個對象增長一些額外的職責(Responsibility),就增長對象功能來講,裝飾模式比生成子類實現更爲靈活。其別名也能夠稱爲包裝器(Wrapper),與適配器模式的別名相同,但它們適用於不一樣的場合。根據翻譯的不一樣,裝飾模式也有人稱之爲「油漆工模式」,它是一種對象結構型模式。git

裝飾模式參與者

  • Component:抽象的組件對象。
  • ConcreteComponent:一個具體組件對象,也能夠給這個對象添加一些職責。
  • Decorator:裝飾抽象類,繼承了Component,從外類來擴展Component功能,但對Component來講,是無需知道Decorator的存在的。
  • ConcreteDecorator:具體裝飾類

裝飾模式基本代碼

Component類:github

namespace DecoratorPattern.BasicStructure
{
    /// <summary>
    /// 抽象組件類
    /// </summary>
    abstract class Component
    {
        public abstract void Operation();
    }
}

ConcreteComponent類:編程

namespace DecoratorPattern.BasicStructure
{
    /// <summary>
    /// 具體組件類
    /// </summary>
    class ConcreteComponent : Component
    {
        public override void Operation()
        {
            Console.WriteLine("具體對象的操做");
        }
    }
}

Decorator類:app

namespace DecoratorPattern.BasicStructure
{
    /// <summary>
    /// 裝飾抽象類
    /// </summary>
    abstract class Decorator : Component
    {
        protected Component Component { get; set; }

        public void SetComponent(Component component)
        {
            this.Component = component;
        }
        public override void Operation()
        {
            if (Component != null)
            {
                Component.Operation();
            }
        }
    }
}

ConcreteDecoratorA類:ide

namespace DecoratorPattern.BasicStructure
{
    /// <summary>
    /// 具體裝飾類 A
    /// </summary>
    class ConcreteDecoratorA : Decorator
    {
        private string _addedState;

        public override void Operation()
        {
            base.Operation();
            _addedState = "new state";
            Console.WriteLine("具體裝飾對象A的操做");
        }
    }
}

ConcreteDecoratorB類:學習

namespace DecoratorPattern.BasicStructure
{
    /// <summary>
    /// 具體裝飾類 B
    /// </summary>
    class ConcreteDecoratorB : Decorator
    {
        public override void Operation()
        {
            base.Operation();
            AddedBehavior();
            Console.WriteLine("具體裝飾對象B的操做");
        }
        private void AddedBehavior() { }
    }
}

客戶端調用代碼:this

    static void Main(string[] args)
    {
        try
        {
            {//BasicStructure
                ConcreteComponent c = new ConcreteComponent();
                ConcreteDecoratorA d1 = new ConcreteDecoratorA();
                ConcreteDecoratorB d2 = new ConcreteDecoratorB();

                d1.SetComponent(c);
                d2.SetComponent(d1);

                d2.Operation();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        Console.ReadKey();
    }

結果以下:spa

用裝飾模式實現給蘋果手機貼膜和帶手機套

場景模擬:某人最近新買了一部蘋果XS,因而準備給手機貼膜和買個手機套帶。翻譯

Handset(手機抽象)類——Component類設計

namespace DecoratorPattern.SituationSimulation
{
    /// <summary>
    /// 手機抽象類,即裝飾者模式中的抽象組件類
    /// </summary>
    abstract class Handset
    {
        public abstract void Operation();
    }
}

AppleHandset(蘋果手機)類——ConcreteComponent類

namespace DecoratorPattern.SituationSimulation
{
    /// <summary>
    /// 蘋果手機手機類,即裝飾着模式中的具體組件類
    /// </summary>
    class AppleHandset : Handset
    {
        public override void Operation()
        {
            Console.WriteLine("操做蘋果手機");
        }
    }
}

HandsetDecorator(手機裝飾)類——Decorator類

namespace DecoratorPattern.SituationSimulation
{
    abstract class HandsetDecorator : Handset
    {
        protected Handset Handset { get; set; }

        public HandsetDecorator(Handset handset)
        {
            this.Handset = handset;
        }
        public override void Operation()
        {
            if (Handset != null)
            {
                Handset.Operation();
            }
        }
    }
}

HandsetSticker(手機貼膜)類——ConcreteDecorator類

namespace DecoratorPattern.SituationSimulation
{
    /// <summary>
    /// 貼紙
    /// </summary>
    class HandsetSticker : HandsetDecorator
    {
        public HandsetSticker(Handset handset)
            : base(handset)
        {

        }
        public override void Operation()
        {
            base.Operation();
            AddSticker();
        }
        public void AddSticker()
        {
            Console.WriteLine("給手機貼膜");
        }
    }
}

HandsetCasing(手機保護套)類——ConcreteDecorator類

namespace DecoratorPattern.SituationSimulation
{
    /// <summary>
    /// 手機保護套
    /// </summary>
    class HandsetCasing : HandsetDecorator
    {
        public HandsetCasing(Handset handset)
            : base(handset)
        {

        }
        public override void Operation()
        {
            base.Operation();
            AddCasing();
        }
        public void AddCasing()
        {
            Console.WriteLine("給手機戴保護套");
        }
    }
}

客戶端調用代碼:

    static void Main(string[] args)
    {
        try
        {
            {//SituationSimulation
                //第一種寫法
                Console.WriteLine("***************第一種寫法:***************");
                AppleHandset handset = new AppleHandset();
                HandsetSticker handsetSticker = new HandsetSticker(handset);
                HandsetCasing handsetCasing = new HandsetCasing(handsetSticker);
                handsetCasing.Operation();

                //第二種寫法
                Console.WriteLine("***************第二種寫法:***************");
                Handset appleHandset = new AppleHandset();
                appleHandset = new HandsetSticker(appleHandset);
                appleHandset = new HandsetCasing(appleHandset);

                appleHandset.Operation();
                //第二種寫法的簡化
                Console.WriteLine("***************第二種寫法的簡化:***************");
                new HandsetCasing(new HandsetSticker(new AppleHandset())).Operation();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        Console.ReadKey();
    }

結果以下:

優勢:

  • 裝飾模式與繼承關係的目的都是要擴展對象的功能,可是裝飾模式能夠提供比繼承更多的靈活性。
  • 能夠經過一種動態的方式來擴展一個對象的功能,經過配置文件能夠在運行時選擇不一樣的裝飾器,從而實現不一樣的行爲。
  • 經過使用不一樣的具體裝飾類以及這些裝飾類的排列組合,能夠創造出不少不一樣行爲的組合。可使用多個具體裝飾類來裝飾同一對象,獲得功能更爲強大的對象。
  • 具體構件類與具體裝飾類能夠獨立變化,用戶能夠根據須要增長新的具體構件類和具體裝飾類,在使用時再對其進行組合,原有代碼無須改變,符合「開閉原則」

缺點:

  • 使用裝飾模式進行系統設計時將產生不少小對象,這些對象的區別在於它們之間相互鏈接的方式有所不一樣,而不是它們的類或者屬性值有所不一樣,同時還將產生不少具體裝飾類。這些裝飾類和小對象的產生將增長系統的複雜度,加大學習與理解的難度。
  • 這種比繼承更加靈活機動的特性,也同時意味着裝飾模式比繼承更加易於出錯,排錯也很困難,對於屢次裝飾的對象,調試時尋找錯誤可能須要逐級排查,較爲煩瑣。

適用環境:

在如下狀況下可使用裝飾模式:

  • 在不影響其餘對象的狀況下,以動態、透明的方式給單個對象添加職責。
  • 須要動態地給一個對象增長功能,這些功能也能夠動態地被撤銷。
  • 當不能採用繼承的方式對系統進行擴充或者採用繼承不利於系統擴展和維護時。不能採用繼承的狀況主要有兩類:第一類是系統中存在大量獨立的擴展,爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增加;第二類是由於類定義不能繼承(如final類).

總結:

  • 裝飾模式用於動態地給一個對象增長一些額外的職責,就增長對象功 能來講,裝飾模式比生成子類實現更爲靈活。它是一種對象結構型模 式。
  • 裝飾模式包含四個角色:抽象構件定義了對象的接口,能夠給這些對 象動態增長職責(方法);具體構件定義了具體的構件對象,實現了 在抽象構件中聲明的方法,裝飾器能夠給它增長額外的職責(方法); 抽象裝飾類是抽象構件類的子類,用於給具體構件增長職責,可是具 體職責在其子類中實現;具體裝飾類是抽象裝飾類的子類,負責向構 件添加新的職責。
  • 使用裝飾模式來實現擴展比繼承更加靈活,它以對客戶透明的方式動 態地給一個對象附加更多的責任。裝飾模式能夠在不須要創造更多子 類的狀況下,將對象的功能加以擴展。
  • 裝飾模式的主要優勢在於能夠提供比繼承更多的靈活性,能夠經過一種動態的 方式來擴展一個對象的功能,並經過使用不一樣的具體裝飾類以及這些裝飾類的 排列組合,能夠創造出不少不一樣行爲的組合,並且具體構件類與具體裝飾類可 以獨立變化,用戶能夠根據須要增長新的具體構件類和具體裝飾類;其主要缺 點在於使用裝飾模式進行系統設計時將產生不少小對象,並且裝飾模式比繼承 更加易於出錯,排錯也很困難,對於屢次裝飾的對象,調試時尋找錯誤可能需 要逐級排查,較爲煩瑣。
  • 裝飾模式適用狀況包括:在不影響其餘對象的狀況下,以動態、透明的方式給 單個對象添加職責;須要動態地給一個對象增長功能,這些功能也能夠動態地 被撤銷;當不能採用繼承的方式對系統進行擴充或者採用繼承不利於系統擴展 和維護時。
  • 裝飾模式可分爲透明裝飾模式和半透明裝飾模式:在透明裝飾模式中,要求客 戶端徹底針對抽象編程,裝飾模式的透明性要求客戶端程序不該該聲明具體構 件類型和具體裝飾類型,而應該所有聲明爲抽象構件類型;半透明裝飾模式允 許用戶在客戶端聲明具體裝飾者類型的對象,調用在具體裝飾者中新增的方法。

 

源代碼地址:https://github.com/houzhenhuang/DesignPattern

相關文章
相關標籤/搜索