二十三种设计模式[9]

前言

       装饰模式,属于对象结构型模式。在《设计模式 - 可复用的面向对象软件》一书中将之描述为“ 动态地给一个对象添加一些额外的职责。就增加功能来说,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)

原文地址:https://www.cnblogs.com/wxingchen/p/10078611.html