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

    输出结果即为:

  • 相关阅读:
    【TYVJ1728】【洛谷P3369】—普通平衡树(Splay写法)
    【BZOJ2388】—旅行规划(分块+凸包)
    【BZOJ3674】—可持久化并查集加强版(可持久化并查集)
    【模板】树链剖分+换根
    【CQOI2007】【BZOJ1257】【洛谷P2261】余数求和(整除分块)
    Old Driver Tree(ODT 老驱动树)
    【CodeForces-896C】— Willem, Chtholly and Seniorious(ODT老驱动树)
    【BZOJ2238】—MST(树链剖分+最小生成树)
    13.PHP_ThinkPHP
    Win64 驱动内核编程-33.枚举与删除对象回调
  • 原文地址:https://www.cnblogs.com/codersun/p/7064088.html
Copyright © 2011-2022 走看看