1. 小菜扮靓第一版

要求你写一个可以给人搭配不同的服饰系统.

结构图:
结构图1

A: 增加超人的装扮你如何做?
B: 改Person类就行了,不对,这就违背了开放-封闭原则了,应该把服饰都写成子类就好了.

2. 小菜扮靓第二版

代码结构图:
图2

仔细看下下面的代码:

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

A: 这样子意味着什么?
B: 把dtx,kk,pqx,和xc的小菜一个一个的显示出来?
A: 难道你当着别人的面穿衣服?
B: 应该在内部组装完毕,然后在显示出来?这好像是建造者模式.
A: 不是.建造者模式建造过程必须是稳定的,而现在我们这个例子,建造过程是不稳定的.换句话说,通过服饰组合出一个有个性的人完全可以有无数种方案,并非是固定.
B: 我们需要把所需要的功能按正确的顺序串联起来进行控制,这好像很难办?

3. 装饰器模式

动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活.

图3
Component是定义一个对象接口,可以给这些对象动态地添加职责.ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责.Decorator,装饰器抽象类,继承了Component,从外类来扩展Component类的功能,但是对于Component来说,是无需知道Decorator的存在的.至于,ConcreteDecorator就是具体的装饰对象,起到给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: 装饰模式的装饰顺序很重要,最理想的情况,是保证装饰类之间彼此独立,这样它们就可以以任意的顺序进行组合.


yuanoung
10 声望1 粉丝

下一篇 »
代理模式

引用和评论

0 条评论