1. 程式人生 > >二十三種設計模式[9] - 裝飾模式(Decorator Pattern)

二十三種設計模式[9] - 裝飾模式(Decorator Pattern)

前言

       裝飾模式,屬於物件結構型模式。在《設計模式 - 可複用的面向物件軟體》一書中將之描述為“ 動態地給一個物件新增一些額外的職責。就增加功能來說,Decorator模式相比生成子類更為靈活”。

       我理解的裝飾模式就是對現有類的包裝,在不對現有類做出修改的前提下為其臨時擴充套件額外的功能。就像套娃一樣,在一個小娃娃外套上一個又一個更大的娃娃。

結構

Decorator_1

  • Component(公共介面):定義所有物件的公共行為,保證各個物件的一致性;
  • ConcreteComponent(產品):被裝飾者;
  • Decorator(裝飾者抽象):所有裝飾者的抽象,保留公共介面的引用;
  • ConcreteDecorator(實際裝飾者):實現具體裝飾的行為;

場景

       舉一個貼近生活的例子。我們每天出門前都要穿上衣服、褲子和鞋(如果你不是這樣,請迅速點選右上角關閉按鈕)。使用程式來描述這個行為時,設計如下。

Decorator_2

       如果這個人今天出門時想要戴上一塊手錶(並不是每天都戴),我們就需要增加一個手錶類並在Human類中增加對手錶類的引用,並不符合開閉原則。而且,當這個人今天沒有佩戴手錶時,對於Human類來說,手錶的引用就是無意義的。

       現在我們從裝飾模式來看看這個行為。首先,人是被裝飾者,衣服、褲子和鞋則是不同的裝飾。人本身是一個獨立的個體,而衣服、褲子和鞋的目的就是為了裝飾人類。人類通過被不同的衣物裝飾來適應不同的場合。比如我們在浴室可以不穿衣服,在家裡穿舒適的衣服,在公司穿得體的衣服。但需要注意的是,無論穿什麼樣的衣服,人依舊是人,只是被不同的衣物裝飾著。所以,人在穿衣服的過程,就是一個裝飾的過程。

示例

Decorator_3

public interface Component
{
    string ShowMyself();
}

public class Human : Component
{
    public string ShowMyself()
    {
        return "我叫程式設計師";
    }
}

public abstract class Decorator : Component
{
    protected Component _component = null;
    public Decorator(Component component)
    {
        this._component = component;
    }
    public virtual string ShowMyself()
    {
        return this._component.ShowMyself();
    }
}

public class Clothes : Decorator
{
    public Clothes(Component component) : base(component) { }

    public override string ShowMyself()
    {
        return base.ShowMyself() + Environment.NewLine + "我穿了一件紅色的格子襯衫";
    }
}

public class Trouser : Decorator
{
    public Trouser (Component component) : base(component) { }

    public override string ShowMyself()
    {
        return base.ShowMyself() + Environment.NewLine + "我穿了一件藍色的牛仔褲";
    }
}

public class Shoe : Decorator
{
    public Shoe(Component component) : base(component) { }

    public override string ShowMyself()
    {
        return base.ShowMyself() + Environment.NewLine + "我穿了一雙棕色的登山鞋";
    }
}

static void Main(string[] args)
{
    Component human = new Human();  //一個人
    human = new Clothes(human);     //穿衣服
    human = new Clothes(human);     //在穿一件衣服
    human = new Trouser(human);     //穿褲子
    human = new Shoe(human);        //穿鞋
    //Component human = new Shoe(new Trouser(new Clothes(new Human())));

    Console.WriteLine(human.ShowMyself());
    Console.ReadKey();
}

image

       示例中,通過Clothes、Trouser和Shoe三個類去裝飾Human類,就像穿衣服一樣,將它們“穿”到Human身上,之後通過遞迴一層層呼叫裝飾類的業務邏輯,達到動態擴充套件Human類的效果。當我們需要給這個人增加一塊手錶時,只需要增加一個手錶類,並將其裝飾到Human上即可,符合開閉原則。當Human類被不同的類裝飾時,可以滿足不同的場景。比如為這個人同時穿兩件外套…

總結

       裝飾模式使我們可以在不對現有類做出修改的前提下為其進行動態且透明的擴充套件,滿足開閉原則方便程式擴充套件。並且我們可以通過對現有類的不同裝飾以適應不同的業務場景,能夠有效減少類的數量。但由於遞迴的使用,使得我們需要花費更多的時間去理解它的層次關係,更不方便問題的排查。


       以上,就是我對裝飾模式的理解,希望對你有所幫助。

       示例原始碼:https://gitee.com/wxingChen/DesignPatternsPractice

       系列彙總:https://www.cnblogs.com/wxingchen/p/10031592.html

       本文著作權歸本人所有,如需轉載請標明本文連結(https://www.cnblogs.com/wxingchen/p/10078611.html)