C++设计模式三--DecoratorPattern(装饰者模式)

定义

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

要点

  1)装饰者和被装饰者有相同的超类,是利用继承达到“类型匹配”,而不是利用继承获得“行为”。
  2)可以用一个或多个装饰者包装一个对象。
  3)因为装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装者)的场合,可以用装饰过的对象代替它。
  4)装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定的目的。
  5)对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。
  6)装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得复杂。

类图

这里写图片描述

设计原则

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

  1)此设计原则的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。这样的设计具有弹性,可以应对改变,可以接受新的功能来应对改变的需求。
  2)需要把注意力集中在设计中最有可能改变的地方,然后应用开放-关闭原则。不要把设计的每个部分都这么做。

示例

  下面实现咖啡馆点餐系统。不同客人对咖啡的喜好个不相同,有的喜欢加摩卡,有的喜欢加奶泡,咖啡店需要根据客户对咖啡添加品的不同计算出不同的价格。
 
Beverage.h

#ifndef BEVERAGE_H
#define BEVERAGE_H
#include <string>

namespace starbuzz
{
using std::string;

// 饮料超类
class Beverage
{
public:
    Beverage() {}
    virtual ~Beverage() {}

    virtual int getCost() = 0;
    virtual string getDescription() = 0;
};
}

#endif

Coffee.h

#ifndef COFFEE_H
#define COFFEE_H
#include "Beverage.h"

namespace starbuzz
{

// 咖啡类
class Coffee: public Beverage
{
public:
    Coffee(string str, int p) : description(str), cost(p)
    {
    }
    ~Coffee() {}

    int getCost()
    {
        return cost;
    }
    string getDescription()
    {
        return description;
    }
private:
    string description;
    int cost;
};

}

#endif

CondimentDecorator.h

#ifndef CONDIMENT_DECORATOR_H
#define CONDIMENT_DECORATOR_H

#include "Beverage.h"

namespace starbuzz
{

// 装饰者超类,继承自Beverage是为了装饰者和被装饰者有相同的超类
class CondimentDecorator: public Beverage
{
public:
    CondimentDecorator() {}
    ~CondimentDecorator() {}
};
}

#endif

CondimentMocha.h

#ifndef CONDIMENT_MOCHA_H
#define CONDIMENT_MOCHA_H

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

namespace starbuzz
{

// 摩卡装饰者
class CondimentMocha: public CondimentDecorator
{
public:
    CondimentMocha(Beverage *b): cost(3), description("Mocha")
    {
        this->beverage = b;
    }
    ~CondimentMocha() {}
    int getCost()
    {
        // 包装新的价格
        return beverage->getCost() + this->cost;
    }
    string getDescription()
    {
        // 包装新的描述
        return this->description + " " + beverage->getDescription();
    }
private:
    int cost;
    string description;
    Beverage *beverage;
};
}

#endif

CondimentWhip.h

#ifndef CONDIMENT_WHIP_H
#define CONDIMENT_WHIP_H

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

namespace starbuzz
{

// 奶泡装饰者
class CondimentWhip: public CondimentDecorator
{
public:
    CondimentWhip(Beverage *b): cost(10), description("Whip")
    {
        this->beverage = b;
    }
    ~CondimentWhip() {}
    int getCost()
    {
        // 包装新的价格
        return beverage->getCost() + this->cost;
    }
    string getDescription()
    {
        // 包装新的描述
        return this->description + " " + beverage->getDescription();
    }
private:
    int cost;
    string description;
    Beverage *beverage;
};
}

#endif

main.cpp

#include <iostream>

#include "Beverage.h"
#include "Coffee.h"
#include "CondimentDecorator.h"
#include "CondimentMocha.h"
#include "CondimentWhip.h"

using std::cout;
using std::endl;
using namespace starbuzz;

int main()
{
    Beverage *beverage = new Coffee("Coffee", 3);   // 咖啡
    Beverage *mocha = new CondimentMocha(beverage); // 加入摩卡
    Beverage *whip = new CondimentWhip(mocha);      // 加入奶泡

    cout << beverage->getDescription() << ":" << beverage->getCost() << endl; 
    cout << mocha->getDescription() << ":" << mocha->getCost() << endl; 
    cout << whip->getDescription() << ":" << whip->getCost() << endl; 

    delete whip;
    delete mocha;
    delete beverage;

    return 0;
}

Makefile

CXX = g++
CFLAGS = -Wall
LDFLAGS = 

target = res
srcs = main.cpp
objs = $(srcs:.cpp=.o)

.PHONY: all
all: $(target)

$(target): $(objs) FORCE
    $(CXX) $(LDFLAGS) -o $(target) $(srcs)

$(objs):%.o:%.cpp
    $(CXX) $(CFLAGS) -c -o $@ $<

.PHONY: FROCE
FORCE:  

clean:
    rm -f $(target) *.o
测试

测试结果如下图所示:
这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值