zoukankan      html  css  js  c++  java
  • 设计模式(三)装饰者模式

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

    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();
            }
    

    输出结果即为:

  • 相关阅读:
    无限维
    黎曼流形
    why we need virtual key word
    TOJ 4119 Split Equally
    TOJ 4003 Next Permutation
    TOJ 4002 Palindrome Generator
    TOJ 2749 Absent Substrings
    TOJ 2641 Gene
    TOJ 2861 Octal Fractions
    TOJ 4394 Rebuild Road
  • 原文地址:https://www.cnblogs.com/codersun/p/7064088.html
Copyright © 2011-2022 走看看