天天看点

设计模式之装饰器模式,以C++为例。 一、装饰器模式介绍二、游戏人物如何使用装饰器模式三、进阶写法(使用智能指针)四、使用模板类

        昨天更新了适配器,今天来盘一盘装饰器模式。装饰器模式以一种动态的方式给对象添加额外的职责,好似“装饰”在对象身上一样,通常通过继承和委托来实现。

设计模式之装饰器模式,以C++为例。 一、装饰器模式介绍二、游戏人物如何使用装饰器模式三、进阶写法(使用智能指针)四、使用模板类

目录

 一、装饰器模式介绍

二、游戏人物如何使用装饰器模式

三、进阶写法(使用智能指针)

四、使用模板类

代码链接:

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了。

        代码类图如下:

设计模式之装饰器模式,以C++为例。 一、装饰器模式介绍二、游戏人物如何使用装饰器模式三、进阶写法(使用智能指针)四、使用模板类

二、游戏人物如何使用装饰器模式

#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 函数中,创建了一个战士对象,并将其用火攻击和冰攻击装饰器包装,最后输出了人物的攻击力。

        类图:

设计模式之装饰器模式,以C++为例。 一、装饰器模式介绍二、游戏人物如何使用装饰器模式三、进阶写法(使用智能指针)四、使用模板类

三、进阶写法(使用智能指针)

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

        这个例子演示了如何使用模板类实现装饰器模式。通过使用模板类,我们可以更灵活地处理不同类型的人物,并且可以避免类型的重复定义。如果你需要更多类型的人物,你只需要定义一个新的类,并在装饰器类上进行模板特化即可。

        类图:

设计模式之装饰器模式,以C++为例。 一、装饰器模式介绍二、游戏人物如何使用装饰器模式三、进阶写法(使用智能指针)四、使用模板类

继续阅读