裝飾器模式

1. 小菜扮靚初版

要求你寫一個能夠給人搭配不一樣的服飾系統.ide

結構圖:
結構圖1學習

A: 增長超人的裝扮你如何作?
B: 改Person類就好了,不對,這就違背了開放-封閉原則了,應該把服飾都寫成子類就行了.ui

2. 小菜扮靚第二版

代碼結構圖:
圖2this

仔細看下下面的代碼:spa

dtx.Show();
kk.Show();
pqx.Show();
xc.Show();

A: 這樣子意味着什麼?
B: 把dtx,kk,pqx,和xc的小菜一個一個的顯示出來?
A: 難道你當着別人的面穿衣服?
B: 應該在內部組裝完畢,而後在顯示出來?這好像是建造者模式.
A: 不是.建造者模式建造過程必須是穩定的,而如今咱們這個例子,建造過程是不穩定的.換句話說,經過服飾組合出一個有個性的人徹底能夠有無數種方案,並不是是固定.
B: 咱們須要把所須要的功能按正確的順序串聯起來進行控制,這好像很難辦?code

3. 裝飾器模式

動態地給一個對象添加一些額外的職責,就增長功能來講,裝飾模式比生成子類更爲靈活.

圖3
Component是定義一個對象接口,能夠給這些對象動態地添加職責.ConcreteComponent是定義了一個具體的對象,也能夠給這個對象添加一些職責.Decorator,裝飾器抽象類,繼承了Component,從外類來擴展Component類的功能,可是對於Component來講,是無需知道Decorator的存在的.至於,ConcreteDecorator就是具體的裝飾對象,起到給Component添加職責的功能.component

Component類對象

abstract class Component
{
    public abstract void Operation();
}

class ConcreteComponent : Component
{
    public override void Operation()
    {
        Console.WriteLine("具體對象的操做");
    }
}

Decorator類繼承

abstract class Decorator : Component
{
    protected Component component;

    public void SetComponent(Component component)
    {
        this.component = component;
    }

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

ConcreteDecoratorA類接口

class ConcreteDecoratorA : Decorator
{
    private string addedState;

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

ConcreteDecoratorB類

class ConcreteDecoratorB : Decorator
{

    public override void Operation()
    {
        base.Operation();
        AddedBehavior();
        Console.WriteLine("具體裝飾對象B的操做");
    }

    private void AddedBehavior()
    {

    }
}

客服端:

class Program
{
    static void Main(string[] args)
    {
        ConcreteComponent c = new ConcreteComponent();
        ConcreteDecoratorA d1 = new ConcreteDecoratorA();
        ConcreteDecoratorB d2 = new ConcreteDecoratorB();

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

        d2.Operation();

        Console.Read();
    }
}

B: 我明白了,原來裝飾器是利用SetComponent來對對象進行包裝.這樣每一個裝飾對象的實現就和如何使用這個對象分離開了,每一個裝飾器只關心本身的功能,不須要關心如何被添加到對象鏈當中.
B: 剛纔我寫的那個例子中的person類是Compoent仍是ConcreteComponent類呢?
A: 學習模式要善於變通,若是隻有一個ConcreteComponent類而沒有抽象的Component類,那麼Decorate類能夠是ConcreteComponent的一個子類.一樣的道理,若是隻有一個ConcreteDecorator類,那麼就沒有必要創建一個單獨的Decorator類,而能夠把Decorator和ConcreteDecorator的合併成一個類.
B: 也就是,這裏沒有必要有Component類了,直接讓服飾類Decorator繼承人類ConcreteComponent就可.

4. 第三版

代碼結構圖:
此處輸入圖片的描述

Person類(ConcreteComponent)

class Person
{
    public Person()
    { }

    private string name;
    public Person(string name)
    {
        this.name = name;
    }

    public virtual void Show()
    {
        Console.WriteLine("裝扮的{0}", name);
    }
}

服飾類(Decorator)

class Finery : Person
{
    protected Person component;

    //打扮
    public void Decorate(Person component)
    {
        this.component = component;
    }

    public override void Show()
    {
        if (component != null)
        {
            component.Show();
        }
    }
}

具體服飾類(ConcreteDecorator)

class TShirts : Finery
{
    public override void Show()
    {
        Console.Write("大T恤 ");
        base.Show();
    }
}

class BigTrouser : Finery
{
    public override void Show()
    {
        Console.Write("垮褲 ");
        base.Show();
    }
}

class Sneakers : Finery
{
    public override void Show()
    {
        Console.Write("破球鞋 ");
        base.Show();
    }
}

class Suit : Finery
{
    public override void Show()
    {
        Console.Write("西裝 ");
        base.Show();
    }
}

class Tie : Finery
{
    public override void Show()
    {
        Console.Write("領帶 ");
        base.Show();
    }
}

class LeatherShoes : Finery
{
    public override void Show()
    {
        Console.Write("皮鞋 ");
        base.Show();
    }
}

客服端

class Program
{
    static void Main(string[] args)
    {
        Person xc = new Person("小菜");

        Console.WriteLine("\n第一種裝扮:");

        Sneakers pqx = new Sneakers();
        BigTrouser kk = new BigTrouser();
        TShirts dtx = new TShirts();

        pqx.Decorate(xc);
        kk.Decorate(pqx);
        dtx.Decorate(kk);
        dtx.Show();

        Console.WriteLine("\n第二種裝扮:");

        LeatherShoes px = new LeatherShoes();
        Tie ld = new Tie();
        Suit xz = new Suit();

        px.Decorate(xc);
        ld.Decorate(px);
        xz.Decorate(ld);
        xz.Show();

        Console.WriteLine("\n第三種裝扮:");
        Sneakers pqx2 = new Sneakers();
        LeatherShoes px2 = new LeatherShoes();
        BigTrouser kk2 = new BigTrouser();
        Tie ld2 = new Tie();

        pqx2.Decorate(xc);
        px2.Decorate(pqx);
        kk2.Decorate(px2);
        ld2.Decorate(kk2);

        ld2.Show();

        Console.Read();
    }
}

5. 裝飾模式總結

B: 裝飾模式是爲已有功能動態地添加更多功能的一種方式.何時用?
A: 當系統須要新功能的時候,是向舊的類中添加新的代碼.這些新加的代碼一般裝飾了原有類的核心職責或主要行爲.在起初的作法,問題在於,它們在主類中加入新的字段,新的方法和新的邏輯,從而增長了主類的複雜度,就像你起初的那個'人'類,而這些新加入的東西僅僅是爲了知足一些只在特定狀況下才會執行的特殊任務的須要.
A: 而裝飾模式卻提供了一個很是好的解決方案,它把每一個要裝飾的功能放在單獨的類中,並讓這個類包裝它所要裝飾的對象,所以,當須要執行特殊行爲時,客戶代碼就能夠在運行時根據須要有選擇地,按順序地使用裝飾功能包裝對象了.B: 優勢,把類中的裝飾功能從類中搬移去除,這樣能夠簡化原有的類.A: 有效地把類的核心職責和裝飾功能區分開來.並且能夠去除相關類中重複的裝飾邏輯.A: 裝飾模式的裝飾順序很重要,最理想的狀況,是保證裝飾類之間彼此獨立,這樣它們就能夠以任意的順序進行組合.

相關文章
相關標籤/搜索