设计模式之装饰者模式

一、模式动机

  使用继承可以给现有类添加行为,但是这种方法是静态的,用户不能控制增加行为的方式和时机。因此可以使用关联机制,即将一个类的对象嵌入另一个对象中,由另一个对象来决定是否调用嵌入对象的行为以便扩展自己的行为,我们称这个嵌入的对象为装饰器(Decorator)
  装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。这就是装饰模式的模式动机。

二、模式定义

  装饰者模式(Decorator Pattern):动态地将责任附加到对象上。如要扩展功能,装饰者提供了比继承更有弹性的替代方案。包括抽象组件、具体组件、抽象装饰者和具体装饰者。
  
这里写图片描述

三、模式示例

  星巴兹咖啡连锁店由于扩张速度太快了,准备更新订单系统,以满足他们的饮料供应要求。他们的类设计如下:
  
这里写图片描述

购买咖啡,可以要求在其中加入配料,例如:牛奶,摩卡等。星巴兹会根据所加入的配料收取不同的费用。价格表如下:

这里写图片描述

如果用继承的话,设计出很多类。采用装饰者模式来解决问题,UML类图如下:

这里写图片描述

C++代码实现

#include <string>
#include <iostream>
#include "windows.h"
using namespace std;

class Beverage
{
public:
    virtual double cost() = 0;
    virtual string getDescription() const { return description_; }
    Beverage();
    ~Beverage();
protected:
    string description_;
};

Beverage::Beverage()
    :description_("Unknown Beverage")
{

}

Beverage::~Beverage()
{

}

//综合
class HouseBlend : public Beverage
{
public:
    double cost() { return 0.89; }
    string getDescription() const { return description_; }
    HouseBlend();
    ~HouseBlend();
};

HouseBlend::HouseBlend()
{
    description_ = "HouseBlend";
}

HouseBlend::~HouseBlend()
{
}

//浓缩咖啡
class Espresso : public Beverage
{
public:
    double cost() { return 1.99; }
    string getDescription() const { return description_; }
    Espresso();
    ~Espresso();
};

Espresso::Espresso()
{
    description_ = "Espresso";
}

Espresso::~Espresso()
{
}

//深焙咖啡
class DarkRoast : public Beverage
{
public:
    double cost() { return 0.99; }
    string getDescription() const { return description_; }
    DarkRoast();
    ~DarkRoast();

private:

};

DarkRoast::DarkRoast()
{
    description_ = "DarkRoast";
}

DarkRoast::~DarkRoast()
{
}

//低咖啡因
class Decaf : public Beverage
{
public:
    double cost() { return 1.05; }
    string getDescription() const { return description_; }
    Decaf();
    ~Decaf();
};

Decaf::Decaf()
{
    description_ = "Decaf";
}

Decaf::~Decaf()
{
}

//抽象装饰者:调料Condiment
class Condiment : public Beverage
{
public:
    Condiment(Beverage*  beverage);
    ~Condiment();
protected:
    Beverage* beverage_;
};

Condiment::Condiment(Beverage*  beverage)
    :beverage_(beverage)
{
}

Condiment::~Condiment()
{
}

//调料:摩卡
class Mocha : public Condiment
{
public:
    double cost(){ return 0.2 + beverage_->cost(); }
    string getDescription() const { return beverage_->getDescription() + " , Mocha"; }
    Mocha(Beverage*  beverage);
    ~Mocha();
};

Mocha::Mocha(Beverage*  beverage)
    :Condiment(beverage)
{
}

Mocha::~Mocha()
{
}

//调料:牛奶
class Milk : public Condiment
{
public:
    double cost(){ return 0.1 + beverage_->cost(); }
    string getDescription() const { return beverage_->getDescription() + " , Milk"; }
    Milk(Beverage*  beverage);
    ~Milk();
};

Milk::Milk(Beverage*  beverage)
    :Condiment(beverage)
{
}

Milk::~Milk()
{
}


//调料:豆浆
class Soy : public Condiment
{
public:
    double cost(){ return 0.15 + beverage_->cost(); }
    string getDescription() const { return beverage_->getDescription() + " , Soy"; }
    Soy(Beverage*  beverage);
    ~Soy();
};

Soy::Soy(Beverage*  beverage)
    :Condiment(beverage)
{
}

Soy::~Soy()
{
}

//调料:奶泡
class Whip : public Condiment
{
public:
    double cost(){ return 0.1 + beverage_->cost(); }
    string getDescription() const { return beverage_->getDescription() + " , Whip"; }
    Whip(Beverage*  beverage);
    ~Whip();
};

Whip::Whip(Beverage*  beverage)
    :Condiment(beverage)
{
}

Whip::~Whip()
{
}

int _tmain(int argc, _TCHAR* argv[])
{
    Beverage*  beverage = new Espresso;
    cout << beverage->getDescription() << " $" << beverage->cost() << endl;
    beverage = new  Mocha(beverage);
    cout << beverage->getDescription() << " $" << beverage->cost() << endl;
    beverage = new  Milk(beverage);
    cout << beverage->getDescription() << " $" << beverage->cost() << endl;
    beverage = new  Soy(beverage);
    cout << beverage->getDescription() << " $" << beverage->cost() << endl;
    beverage = new  Whip(beverage);
    cout << beverage->getDescription() << " $" << beverage->cost() << endl;
    system("pause");
    return 0;
}

运行结果

这里写图片描述

四、分析总结

  装饰模式用于动态地给一个对象增加一些额外的职责,就增加对象功 能来说,装饰模式比生成子类实现更为灵活。它是一种对象结构型模 式。

优点:

  1. 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。
  2. 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。
  3. 通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
  4. 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”

缺点:

  1. 使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类。这些装饰类和小对象的产生将增加系统的复杂度,加大学习与理解的难度。
  2. 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值