设计模式03 - 装饰者模式

引入:
曾今以为继承能解决一切问题。在程序运行时发现,扩展的威力远大于编译时扩展的威力。
装饰者模式:
好处:
一旦知道装饰的技巧,你将能给你的(或别人的)对象一个新的责任,而不需要对底层class的代码做任何改变
p.s. 写代码的时候,尽量少对底层代码做修改。
描述:
装饰者模式动态地将额外责任附加到对象上。
对于扩展功能,装饰者提供子类化之外地弹性替代方案。

设计原则:
类应该对扩展开放,但对修改关闭。
我们的目标是允许类容易扩展以容纳新的行为,而不用修改已有代码。
达成这个目标,有什么好处?
这样的设计可以弹性地应对改变,有足够弹性接纳新的功能来应对改变的需求。

main.cpp

/**
 * @file main.cpp
 * @author JeffyGao (gaojune)better@qq.com)
 * 
 * @version 0.1
 * @date 2022-04-30
 * @copyright Copyright (c) 2022
 * 
 * @brief  本节开始介绍 设计模式03 - 装饰者模式
 * 文件描述:
 *  Beverage.h:
 *      class Beverage      基类                                           (抽象组件)
 *      class CondimentDecorator : public Beverage 为调料实现抽象类         (抽象装饰者)
 *  other_Drinks.h:         基于 Beverage (Beverage.h),派生的一些其它饮料
 *      class Espresso   : public Beverage    浓缩咖啡                      (具体组件)
 *      class TeaWithMilk : public Beverage   奶茶                          (具体组件)
 *      
 *  other_Seasonings.h 基于 CondimentDecorator (Beverage.h),派生的一些其它调料
 *      class Mocha : public CondimentDecorator 调料 - 摩卡                 (具体装饰者)
 *      class Cream : public CondimentDecorator 调料 - 奶油                 (具体装饰者)
 *      class Soy   : public CondimentDecorator 调料 - 豆子                 (具体装饰者)
 */

#include <iostream>
#include "Other_Drinks.h"
#include "Beverage.h"
#include "Other_Seasonings.h"

// 开始下订单
class StabuzzCoffee{
public:
    StabuzzCoffee( ){
        std::cout << "Begin buy my coffee ctor" << std::endl;
    }
    ~StabuzzCoffee( ){
        std::cout << "StabuzzCoffee dtor" << std::endl;
    }
public:
    void Print( ){
        // std::cout << _beverage->GetDescription() << " $ "  << _beverage->Cost() << std::endl;
        std::cout << _beverage->Cost() << "$" << std::endl;
    }
    
public:
    Beverage* _beverage;
};

// 点单系统是 一种奶茶/咖啡 + 若干小料
int main( ){
std::cout << "No.1" << std::endl;
    // 来一杯浓缩咖啡,不加调料,打印出它的描述和价格
    StabuzzCoffee coffee1;
    coffee1._beverage = new Espresso();
    std::cout << coffee1._beverage->GetDescription() << std::endl;
    coffee1.Print();

std::cout << "No.2" << std::endl;
    // 来一杯奶茶(0.89),加 摩卡(0.2)、奶油(0.31)
    // 在调用 coffee2.Pring() 的时候调用顺序:
    // -> Cream.Cost() -> Mocha.Cost() -> TraWithMilk.Cost() 
    StabuzzCoffee coffee2;
    coffee2._beverage = new TeaWithMilk();
    coffee2._beverage = new Mocha( coffee2._beverage );
    coffee2._beverage = new Cream( coffee2._beverage );
    std::cout << coffee2._beverage->GetDescription() << std::endl;
    coffee2.Print();

    return 0;
}


Beverage.h

/**
 * @file Beverage.h
 * @author JeffyGao (gaojune)better@qq.com) 
 * @version 0.1
 * @date 2022-04-30
 * @copyright Copyright (c) 2022
 * 
 * @brief 这是一个抽象类 的基类
 * 
 * 文件包含:
 *      GetDescription() 商品描述
 *      virtual double Cost() = 0 商品花费
 *      
 * 
 */

#ifndef BEVERAGE_H
#define BEVERAGE_H

#include <iostream>
#include <string.h>

class Beverage{
public:
    Beverage( ){
        std::cout << "Beverage ctor" << std::endl;
    }

    // 要定义 虚函数
    virtual ~Beverage( ){
        std::cout << "Beverage dtor" << std::endl;
    }

public:
    // 公共接口
    // 商品描述
    virtual std::string GetDescription( ){
        return _description;
    }

    // 商品花费
    // 这里不能定义为 纯虚函数,不然 class CondimentDecorator 无法实例化_beverage
    virtual double Cost( ) = 0;
    //virtual double Cost( ) {}     // 如果要定义为虚函数的话要定义 {}
    // double Cost( ){
    //     std::cout << " Beverage Cost()" << std::endl;
    //     return (double)12345.1234;
    // }

    // 不能设置为 private,不然派生类无法更改改变量
    std::string _description = "Unknown Beverage  ";

};


// 为调料实现抽象类
class CondimentDecorator : public Beverage{
public:
    CondimentDecorator( ){
        std::cout << "CondimentDecorator ctor" << std::endl;
    }
    ~CondimentDecorator( ){
        std::cout << "CondimentDecorator dtor" << std::endl;
    }

public:
    // 书中这一行没看懂 =>  在 Other_Seasonings.h 中要实例化
    // 我在 Beverage 中将 Cost( ) 定义了纯虚函数,因此不能直接实例化,只能实例化其指针
    // 要想能实例化其对象的话,另一种方法是定义好其虚构函数{}
    Beverage* _beverage;

    // 重写 GetDescription()
    virtual std::string GetDescription( ) {
        return _description;
    }

};


#endif

Other_Drinks.h

/**
 * @file Other_dring.h
 * @author effyGao (gaojune)better@qq.com)
 * @version 0.1
 * @date 2022-04-30
 * @copyright Copyright (c) 2022
 * 
 * @brief 基于 基类 Beverage (Beverage.h),派生的一些其它饮料
 * 
 * 文件包含:
 *  class Espresso : public Beverage ,浓缩咖啡
 *      Espresso()      更改 _description
 *      Cost()          重写了 Cost()
 *  class TeaWithMilk : public Beverage, 奶茶
 *      TeaWithMilk()   更改 _description
 *      Cost()          重写了 Cost()
 */

#ifndef OTHER_DRINKS_H
#define OTHER_DRINKS_H


#include "Beverage.h"
#include <iostream>

// 浓缩咖啡 (具体组件)
class Espresso : public Beverage{
public:
    Espresso( ){
        //std::cout << "Espresso ctor" << std::endl;
        _description= "订单详情: 浓缩咖啡 ";   // 并更改描述
    }
    ~Espresso( ){
        std::cout << "Espresso dtor" << std::endl;
    }

public:
    // 重写了 Cost()
    double Cost( ){
        std::cout << "共花费:  ";
        return 1.99;
    }
};

// 奶茶    (具体组件)
class TeaWithMilk : public Beverage{
public:
    TeaWithMilk( ){
        //std::cout << "TeaWithMilk ctor" << std::endl;
        _description= "订单详情: 奶茶 ";   // 并更改描述
    }
    ~TeaWithMilk( ){
        std::cout << "TeaWithMilk dtor" << std::endl;
    }

public:
    // 重写了 Cost()
    double Cost( ){
        std::cout << "共花费:    ";
        return 0.89;
    }
};

#endif

Other_Seaonings.h

/**
 * @file Other_Seasonings.h
 * @author effyGao (gaojune)better@qq.com)
 * @version 0.1
 * @date 2022-04-30
 * @copyright Copyright (c) 2022
 * 
 * @brief   一些调料~ 
 *  基于 基类 CondimentDecorator (Beverage.h),派生的一些其它调料
 * 
 * 文件包含:
 *  class Mocha : public CondimentDecorator 调料 - 摩卡 (具体装饰者)
 *  class Cream : public CondimentDecorator 调料 - 奶油 (具体装饰者)
 *  class Soy   : public CondimentDecorator 调料 - 豆子 (具体装饰者)
 * 
 *  // 构造函数 传入 Beverage* 型, 在 main.cpp 中通过包裹对象来实现“加小料”,反馈相应的Cost()
 */

#ifndef OTHER_SEASONINGS_H
#define OTHER_SEASONINGS_H

#include <iostream>
#include "Beverage.h"
#include <string>

// 调料 - 摩卡 具体装饰着
class Mocha : public CondimentDecorator{
public:
    Mocha( ){
        std::cout << "Mocha ctor" << std::endl;
    }

    Mocha( Beverage* beverage ){
        std::cout << "Mocha( Beverage beverage )" << std::endl;

        // 在这里实例变量为正在包裹的对象。
        // 这里,我们可以传递正在包装的饮料给装饰者的构造器。
        this->_beverage = beverage;
    }

    ~Mocha( ){
        std::cout << "Mocha dtor" << std::endl;
    }

public:
    // 重写方法
    // 饮料 Description + Mocha 描述
    std::string GetDescription( ){
        std::string name = _beverage->GetDescription() + " , Mocha";
        return  name;
    }

    // 饮料 Cost +  Mocha 价格
    double Cost( ){
        return _beverage->Cost() + 0.20;
    }
};

// 调料 - 奶油 具体装饰着
class Cream : public CondimentDecorator{
public:
    Cream( ){
        std::cout << "Cream ctor" << std::endl;
    }
    Cream( Beverage* beverage ){
        std::cout << "Cream( Beverage beverage )" << std::endl;

        // 在这里实例变量为正在包裹的对象。
        // 这里,我们可以传递正在包装的饮料给装饰者的构造器。
        this->_beverage = beverage;
    }

    ~Cream( ){
        std::cout << "Cream dtor" << std::endl;
    }

public:
    // 重写方法
    // 饮料 Description + Cream 描述
    std::string GetDescription( ){
        //std::cout << "调用了 奶油" << std::endl;
        std::string name = _beverage->GetDescription() + " , Cream";
        return  name;
    }

    // 饮料 Cost +  Cream 价格
    double Cost( ){
        return _beverage->Cost() + 0.31;
    }
};

// 调料 - 豆子 具体装饰着
class Soy : public CondimentDecorator{
public:
    Soy( ){
        std::cout << "Soy ctor" << std::endl;
    }
    Soy( Beverage* beverage ){
        std::cout << "Soy( Beverage beverage )" << std::endl;

        // 在这里实例变量为正在包裹的对象。
        // 这里,我们可以传递正在包装的饮料给装饰者的构造器。
        this->_beverage = beverage;
    }

    ~Soy( ){
        std::cout << "Soy dtor" << std::endl;
    }

public:
    // 重写方法
    // 饮料 Description + Soy 描述
    std::string GetDescription( ){
        std::string name = _beverage->GetDescription() + " , Soy";
        return  name;

    }

    // 饮料 Cost +  Soy 价格
    double Cost( ){
        return _beverage->Cost() + 0.39;
    }
};

#endif  




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值