设计模式之装饰者(C++)

1. 作用

装饰者模式是对继承的补充。怎么讲?
想想假如你想给某个类的方法加上一些功能,补充一下,但是又不能在原本的类上进行改动。首先想到的办法是继承这个类,重写这个需要加上某些功能的方法。过一段时间有需要加某些功能,你又继承刚刚那个类,又进行重写方法,几次下来,你继承层次就吓人了。
装饰者模式就是解决此类问题的,它避免了多次继承而实现改变某个方法的作用。
意图:动态的给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更加灵活。

2. UML类图


这里写图片描述
参与者:

  • Component:定义一个对象接口,可以给这些对象动态地添加职责。
  • ConcreteComponent:定义一个对象,可以给这个对象添加一些职责。
  • Decorator:维持一个指向Component对象的指针,并定义一个与Component接口一致的接口。
  • ConcreteDecorator:向组件添加职责。

3. 实现

  • 举例:相信很多人早餐都爱吃煎饼,去买煎饼一般都会加上各种东西,比如煎蛋,火腿肠,生菜等,想想这些加的东西不就是用来装饰煎饼的吗?加上这些东西之后煎饼依然还是煎饼。

    这里写图片描述
    代码:

#include <iostream>
#include <string>
using namespace std;


//抽象构件
//食物
class Food
{
public:
    virtual string name() = 0;
    virtual int cost() = 0;
};

//具体构件
//原味煎饼,啥都没加的
class Pancake :public Food
{
public:
    virtual string name()
    {
        return "原味煎饼果子 ";
    }

    virtual int cost() 
    {
        return 3;
    }
};

//装饰者抽象角色,最重要的是持有Food
class ExtraFood :public Food
{
public:
    ExtraFood(Food* food) :m_pFood(food){}
    virtual string name()
    {
        return m_pFood->name();
    }
    virtual int cost()
    {
        return m_pFood->cost();
    }

protected:
    Food *m_pFood;
};


//具体装饰角色
//煎蛋
class Ege :public ExtraFood
{
public:
    Ege(Food* food) :ExtraFood(food){}
    virtual string name()
    {
        return m_pFood->name() + "鸡蛋 ";
    }
    virtual int cost()
    {
        return m_pFood->cost() + 1;
    }
};

//具体装饰角色
//火腿
class Ham :public ExtraFood
{
public:
    Ham(Food* food) :ExtraFood(food){}
    virtual string name()
    {
        return m_pFood->name() + "火腿 ";
    }
    virtual int cost()
    {
        return m_pFood->cost() + 2;
    }
};

//具体装饰角色
//生菜
class Lettuce :public ExtraFood
{
public:
    Lettuce(Food* food) :ExtraFood(food){}
    virtual string name()
    {
        return m_pFood->name() + "生菜 ";
    }
    virtual int cost()
    {
        return m_pFood->cost() + 1;
    }
};


//买煎饼果子了
int main()
{
    //先来一个原味的煎饼
    Food * pancake = new Pancake;
    cout << pancake->name() << "价格是" << pancake->cost() << "元" << endl;


    //加个蛋
    pancake = new Ege(pancake);
    cout << pancake->name() << "价格是" << pancake->cost() << "元" << endl;

    //加个火腿肠
    pancake = new Ham(pancake);
    cout << pancake->name() << "价格是" << pancake->cost() << "元" << endl;

    //加生菜
    pancake = new Lettuce(pancake);
    cout << pancake->name() << "价格是" << pancake->cost() << "元" << endl;

    //资源释放.......

    return 0;
}

结果:
原味煎饼果子 价格是3元
原味煎饼果子 鸡蛋 价格是4元
原味煎饼果子 鸡蛋 火腿 价格是6元
原味煎饼果子 鸡蛋 火腿 生菜 价格是7元
请按任意键继续. . .

4. 优缺点

  • 优点:
    比继承更加灵活,很容易重复添加或改变一个特性。
  • 缺点:
    多层装饰比较复杂,层次越多,小类越多,越里层的装饰需要改动,越复杂。
    装饰模式是针对抽象构建(Component)类型编程。但是,如果要针对具体构件(ConcreteComponent)编程,应该重新思考应用架构,以及装饰者是否合适。当然也可改变 Component 接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择

5. 适用场景

需要扩展一个类的功能,或给一个类增加附加功能。
需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。

6. 总结

装饰者模式是继承之外可以改变一个方法的模式,值得注意的是当具体装饰者较时少,可以考虑取消装饰者抽象类。

猜你喜欢

转载自blog.csdn.net/a369189453/article/details/81210739