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

定义

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

要点

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

类图

C++设计模式三--DecoratorPattern(装饰者模式)_第1张图片

设计原则

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

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

示例

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

#ifndef BEVERAGE_H
#define BEVERAGE_H
#include 

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 
#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 
#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 

#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

测试

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

你可能感兴趣的:(设计模式(C++),Decorator,装饰者模式,设计模式)