装饰器模式

徐璆
• 阅读 952

1. 小菜扮靓第一版

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

结构图:
装饰器模式

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

2. 小菜扮靓第二版

代码结构图:
装饰器模式

仔细看下下面的代码:

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

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

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: 装饰模式的装饰顺序很重要,最理想的情况,是保证装饰类之间彼此独立,这样它们就可以以任意的顺序进行组合.

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
java之设计模式
看了设计模式,感觉自己很多不理解什么意思,通过看博客别人写的理解,总结了一下,方便查阅。一、设计模式六大原则1、单一职责原则:定义:应该有且只有一个原因引起类的变化。注意:这里的类不光指类,也适用于方法和接口,比如我们常说的一个方法实现一个功能。2、开放封闭原则:定义:类、模块、函数等
zdd小小菜鸟 zdd小小菜鸟
2年前
设计模式–六大原则
设计模式–六大原则tex在238中设计模式中,我们提炼出了六大面向对象设计原则我们可以不知道那数量繁多的设计模式,但一定要记住这六大设计原则1.开闭原则(OpenClosePrinciple
zdd小小菜鸟 zdd小小菜鸟
2年前
设计模式面试
设计模式面试1.单例设计模式使用设计模式为了代码复用,增加可维护性。设计模式的六大原则:开闭原则、里氏代换原则、依赖倒转原则、接口隔离原则、迪米特法则(最少知道原则)、合成/聚合复用原则Singleton(创建):保证一个类仅
Wesley13 Wesley13
3年前
Java设计模式之三种工厂模式
工厂模式实现了创建者和调用者的分离,实现了更好的解耦。详细分类:1)简单工厂模式(静态工厂模式);2)工厂方法模式;3)抽象工厂模式面向对象设计的基本原则:1)      OCP(开闭原则,OpenClosedPrinciple):一个软件的实体应当对扩展开放,对修改关闭。2)      
Wesley13 Wesley13
3年前
23种设计模式(1):单例模式
定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。类型:创建类模式类图:!23种设计模式(1):单例模式第1张|快课网(http://static.oschina.net/uploads/img/201407/05200605_0dij.gif"23种设计模式(1):单例模式
Stella981 Stella981
3年前
Python装饰器、内置函数之金兰契友
装饰器:装饰器的实质就是一个闭包,而闭包又是嵌套函数的一种。所以也可以理解装饰器是一种特殊的函数。因为程序一般都遵守开放封闭原则,软件在设计初期不可能把所有情况都想到,所以一般软件都支持功能上的扩展,而对源代码的修改是封闭的。开放封闭原则主要体现在两个方面:对功能扩展开放:意味着有新的需求或变化时,可以对现有代码进行扩展,以适
Wesley13 Wesley13
3年前
Java描述设计模式(06):建造者模式
一、生活场景基于建造者模式,描述软件开发的流程。1、代码实现/基于建造者模式描述软件开发/publicclassC01_InScene{publicstaticvoidmain(Stringargs){B
Wesley13 Wesley13
3年前
JavaWeb之动态代理解决request请求编码问题
动态代理解决编码问题1.设计模式出现原因:软件开发过程中,遇到相似问题,将问题的解决方法抽取模型(套路)常见设计模式:单例,工厂,适配器,装饰者,动态代理。2.装饰者模式简单介绍谷歌汽车开发场景1.Java定义了汽车开发约定interfaceICar{s
京东云开发者 京东云开发者
5个月前
设计模式-策略模式
作者:京东工业孙磊一、概念策略模式(StrategyPattern)也称为(PolicyParttern)。它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变换,不会影响到使用算法的客户。策略模式属性行为模式。策略模式结构图\二、实际
京东云开发者 京东云开发者
2个月前
设计模式-策略模式
作者:京东工业孙磊一、概念策略模式(StrategyPattern)也称为(PolicyParttern)。它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变换,不会影响到使用算法的客户。策略模式属性行为模式。策略模式结构图\二、实际
京东云开发者 京东云开发者
2星期前
设计模式-策略模式
作者:京东工业孙磊一、概念策略模式(StrategyPattern)也称为(PolicyParttern)。它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变换,不会影响到使用算法的客户。策略模式属性行为模式。策略模式结构图\二、实际