设计模式(三)装饰者模式

前段时间忙着出去玩,又是骑行又是去岛上,搞得一度没有时间继续写下去(其实还不是自己懒哈哈哈),今天写装饰者模式,在看书实现的过程中还遇到了一些插曲,顺便也一起写下来。

1.1定义

装饰者模式

动态的将责任附加到对象上,若要拓展功能,装饰者提供了比继承更有弹性的替代方案。

OO原则

类应该对拓展开放,对修改关闭。

我们的目标是允许类容易拓展,在不修改现有代码的基础上,就可以搭配新的行为。这样的设计具有弹性可以应该对改变,可以接受新的功能来应对改变的需求。

2.1 需求

image
这是一个咖啡店咖啡的基类和其实现,现在的问题是咖啡其实是有很多不同的调料,例如蒸奶,豆浆,摩卡等等,咖啡店会根据咖啡加入的调料的不同而收取不同的费用。

ps:调料会不定时更新,添加等等。

2.2 分析

这个设计的主要问题是使用组合替代继承,避免类爆炸。

如果只是使用继承,因为多种咖啡可以添加多种调料,所以最后的结果可以有非常多个,用具体的实现来覆盖所有这些情况显然是不可行的,这时我们就要用组合替代继承。

2.3 失败的例子

书里面提到了一个应对这个问题的一个错误思路,也不能叫错误思路,只是说开放关闭原则做的不好,有需求变化时,甚至要修改超类的代码。比如新增一种调料


这种设计在应对需求变化时非常的不方便,因为继承这个东西实在是不太灵活,要用组合替代继承

3.1 具体实现

3.1.1 装饰者模式的要点

  1. 装饰者和被装饰者具有相同的超类型
  2. 你可以用一个或者多个装饰者包装一个对象
  3. 既然装饰者和被装饰者拥有相同的超类型,所以在任何需要原始对象的情况下,都可以用装饰过的对象代替他。
  4. (关键) 装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特殊目的。
  5. 对象可以在任何时候被装饰,所以可以在运行时动态的,不限量的用你喜欢的装饰者来装饰对象。

3.2.1 具体代码实现

先是对原始的饮料超类做出一些修改:

 public abstract class Beverage
    {
        protected string description = "unknow beverage";
        public virtual string getDescription()
        {
            return description;
        }
        public abstract double cost();
    }

这里的virtual关键字很重要,我不知道java里对方法重写是如何定义的,在C#中,方法不加virtual或者abstract,或者本身不处于接口中,这样的方法不能被重写override,只能被覆盖new,但是覆盖后的方法调用原则是,如果直接调用基类的方法,还是最原始的那个起作用,调用子类的方法,会使用new后的替代,所以现在的场景需要override不需要new.

下面是装饰者的超类:

//装饰者超类
    public abstract class CondimentDectorator : Beverage
    {
        public override  abstract  string getDescription();
    }

所有继承CondimentDectorator的类都必须重写getDescription()方法,而CondimentDectorator中的getDescription()其实又重写了基类的方法,所以最终是重写了基类的方法。

下面是饮料Beverage类的一些子类:

//浓咖啡
    public class Espresso : Beverage
    {
        public Espresso()
        {
            description = "espresso";
            
        }

        public override double cost()
        {
            return 1.99;
        }
    }
    //不知道叫什么的咖啡
    public class HouseBlend : Beverage
    {
        public HouseBlend()
        {
            description = "houseblend";
        }
        public override double cost()
        {
            return 2.33;
        }
    }

下面是最关键的具体装饰者的代码:

//调料装饰者摩卡
    public class Mocha : CondimentDectorator
    {
        Beverage beverage;

        public Mocha(Beverage b)
        {
            beverage = b;
         
        }
        public override double cost()
        {
            return 0.2 + this.beverage.cost();
        }

        public override string getDescription()
        {
            return this.beverage.getDescription() + " mocha";
        }
    }

    //调料装饰者奶油
    public class Whip : CondimentDectorator
    {
        Beverage beverage;

        public Whip(Beverage b)
        {
            beverage = b;
        }
        public override double cost()
        {
            return 0.01 + this.beverage.cost();
        }

        public override string getDescription()
        {
            return this.beverage.getDescription() + " Whip";
        }
    }

这里在设计中用到了C#的virtual和abstract组合来实现基类中有方法体的方法在子类中必须重写的需求。

3.1 使用示例

   static void Main(string[] args)
        {
            Beverage b = new HouseBlend();
            b = new Whip(b);
            b = new Mocha(b);
            Console.WriteLine(b.getDescription());
            Console.WriteLine("==");
            Console.WriteLine("cost:"+b.cost());
            Console.ReadKey();
        }

输出结果即为:

原文地址:https://www.cnblogs.com/codersun/p/7064088.html