昨天更新了适配器,今天来盘一盘装饰器模式。装饰器模式以一种动态的方式给对象添加额外的职责,好似“装饰”在对象身上一样,通常通过继承和委托来实现。
目录
一、装饰器模式介绍
二、游戏人物如何使用装饰器模式
三、进阶写法(使用智能指针)
四、使用模板类
代码链接:
Thomas_Lbw / Cpp_Design_Patterns · GitCode
一、装饰器模式介绍
设计模式始终遵循对“修改封闭,拓展开放”这样的特性,说白了就是尽量不要动源代码,去尽力适应源代码的方式去做拓展开发。装饰器模式同样遵循这样的原则,实现装饰器模式的主要手段同样为 C++最基本的特性:继承、C++11新特性:委托。
以一个简单的代码例子:
#include<iostream>
using namespace std;
class Component {
public:
virtual void Operation() = 0;
};
class ConcreteComponent : public Component
{
public:
void Operation() override {
std::cout << "ConcreteComponent Operation" << std::endl;
}
};
class Decorator : public Component {
public:
Decorator(Component *component) : component_(component){}
void Operation() override {
component_->Operation();
}
private:
Component *component_;
};
class ConcreteDecoratorA : public Decorator
{
public:
//委托构造函数
ConcreteDecoratorA(Component *component) : Decorator(component){}
void Operation() override//帮助检查重写时的参数错误
{
Decorator::Operation();
AddedBehavior();
}
private:
void AddedBehavior() {
std::cout << "ConcreteDecoratorA Addedbehavior" << std::endl;
}
};
class ConcreteDecoratorB : public Decorator
{
public:
//委托构造函数
ConcreteDecoratorB(Component *component) : Decorator(component) {}
void Operation() override
{
Decorator::Operation();
AddedBehavior();
}
private:
void AddedBehavior() {
std::cout << "ConcreteDecoratorB Addedbehavior" << std::endl;
}
};
int main()
{
Component *component = new ConcreteComponent();
component = new ConcreteDecoratorA(component);
component = new ConcreteDecoratorB(component);
component->Operation();
}
我们在代码中定义了一个组件类Component,其中有一个纯虚函数Operation,可以在其中定义一组操作。具体的组件ConcreteComponent类继承自该组件,并实现了Operation。装饰器Decorator继承自该组件,并具有一个指向组件类的指针component_,它的Operation方法调用了component_指向的Operation方法。
具体的装饰器ConcreteDecoratorA和ConcreteDecoratorB继承自Decorator,并且重写了Operation方法,在调用父类的Operation方法后,再调用自己的AddedBehavior方法。
main函数中创建了具体的组件对象,然后使用装饰器A和B去装饰该对象,最后调用装饰后的Operation,实现对组件动态地添加新功能。
如果在老的项目中,Compoent和ConcreteComponent为不能修改的代码,但是还需要向上添加新的功能,装饰器模式就非常nice了。
代码类图如下:
二、游戏人物如何使用装饰器模式
#include <iostream>
class Character {
public:
virtual int getAttackPower() = 0;
};
class Warrior : public Character {
public:
int getAttackPower() { return 10; }
};
class CharacterDecorator : public Character {
protected:
Character *character;
public:
CharacterDecorator(Character *c) : character(c) {}
int getAttackPower() { return character->getAttackPower(); }
};
class FireAttack : public CharacterDecorator {
public:
FireAttack(Character *c) : CharacterDecorator(c) {}
int getAttackPower() { return character->getAttackPower() + 5; }
};
class IceAttack : public CharacterDecorator {
public:
IceAttack(Character *c) : CharacterDecorator(c) {}
int getAttackPower() { return character->getAttackPower() - 3; }
};
int main() {
Character *warrior = new Warrior();
Character *fire_warrior = new FireAttack(warrior);
Character *ice_warrior = new IceAttack(fire_warrior);
std::cout << ice_warrior->getAttackPower() << std::endl;
delete ice_warrior;
return 0;
}
在上面的代码中,首先定义了一个组件类 Character,并在 Warrior 类中实现了这个类。接着定义了一个装饰器类 CharacterDecorator,并在两个具体的装饰器类 FireAttack 和 IceAttack 中覆盖了 getAttackPower 方法。最后,在 main 函数中,创建了一个战士对象,并将其用火攻击和冰攻击装饰器包装,最后输出了人物的攻击力。
类图:
三、进阶写法(使用智能指针)
#include <iostream>
#include <memory>
class Character {
public:
virtual int getAttackPower() = 0;
};
class Warrior : public Character {
public:
int getAttackPower() { return 10; }
};
class CharacterDecorator : public Character {
public:
CharacterDecorator(std::shared_ptr<Character> c) : character(c) {}
int getAttackPower() { return character->getAttackPower(); }
public:
std::shared_ptr<Character> character;
};
class FireAttack : public CharacterDecorator {
public:
FireAttack(std::shared_ptr<Character> c) : CharacterDecorator(c) {}
int getAttackPower() { return character->getAttackPower() + 5; }
};
class IceAttack : public CharacterDecorator {
public:
IceAttack(std::shared_ptr<Character> c) : CharacterDecorator(c) {}
int getAttackPower() { return character->getAttackPower() - 3; }
};
int main() {
std::shared_ptr<Character> warrior = std::make_shared<Warrior>();
std::shared_ptr<Character> fire_warrior = std::make_shared<FireAttack>(warrior);
std::shared_ptr<Character> ice_warrior = std::make_shared<IceAttack>(fire_warrior);
std::cout << ice_warrior->getAttackPower() << std::endl;
return 0;
}
在上面的代码中,使用了 shared_ptr 而不是普通的指针来管理对象的生存期,这更加安全。代码中使用了 make_shared 函数来创建对象,而不是手动分配堆内存。这样做可以简化内存管理,提高代码的可读性。此外,由于组件类和装饰器类的关系建立在 shared_ptr 上,所以在 main 函数结束时不需要手动释放内存。
四、使用模板类
#include <iostream>
#include <memory>
template <typename T>
class Character {
public:
virtual int getAttackPower() = 0;
};
class Warrior : public Character<Warrior> {
public:
int getAttackPower() { return 10; }
};
template <typename T>
class CharacterDecorator : public Character<T> {
public:
CharacterDecorator(std::shared_ptr<Character<T>> c) : character(c) {}
int getAttackPower() { return character->getAttackPower(); }
public:
std::shared_ptr<Character<T>> character;
};
class FireAttack : public CharacterDecorator<Warrior> {
public:
FireAttack(std::shared_ptr<Character<Warrior>> c) : CharacterDecorator<Warrior>(c) {}
int getAttackPower() { return character->getAttackPower() + 5; }
};
class IceAttack : public CharacterDecorator<Warrior> {
public:
IceAttack(std::shared_ptr<Character<Warrior>> c) : CharacterDecorator<Warrior>(c) {}
int getAttackPower() { return character->getAttackPower() - 3; }
};
int main() {
std::shared_ptr<Character<Warrior>> warrior = std::make_shared<Warrior>();
std::shared_ptr<Character<Warrior>> fire_warrior = std::make_shared<FireAttack>(warrior);
std::shared_ptr<Character<Warrior>> ice_warrior = std::make_shared<IceAttack>(fire_warrior);
std::cout << ice_warrior->getAttackPower() << std::endl;
return 0;
}
这个例子演示了如何使用模板类实现装饰器模式。通过使用模板类,我们可以更灵活地处理不同类型的人物,并且可以避免类型的重复定义。如果你需要更多类型的人物,你只需要定义一个新的类,并在装饰器类上进行模板特化即可。
类图: