一、为什么用装饰器模式
在游戏开发中,一个角色往往有基础的攻击、防御等功能。但随着游戏设计的复杂化,角色可能需要装备武器、护甲、宝石,或者临时获得某种技能效果。
如果我们把这些额外的效果都直接写进角色类里,会导致以下问题:
角色类过于庞大,耦合了所有可能的功能;
扩展性差,新增装备或技能都要修改角色类;
组合不灵活,难以在运行时动态组合效果。
装饰器模式正好解决了这个问题。它允许我们在不修改原有角色类的前提下,动态地给角色增加装备/技能效果,而且这些效果可以灵活组合。
二、场景说明
我们设计一个简单的战斗系统:
游戏里有一个基础角色(Hero),它有
attack()
方法;角色可以装备 武器(提高攻击力);
角色可以装备 护甲(增加防御效果,表现为输出提示);
角色可以同时拥有多种装备,比如武器 + 护甲。
如果不用装饰器模式,可能会写出 HeroWithWeapon
、HeroWithArmor
、HeroWithWeaponAndArmor
等类,数量会爆炸。
而装饰器模式只需把功能拆成一个个“装备装饰器”,然后在运行时自由组合。
三、类图
四、C++代码实现
#include <iostream>
#include <memory>
#include <string>
// 抽象角色
class Character {
public:
virtual ~Character() = default;
virtual void attack() = 0;
};
// 具体角色:英雄
class Hero : public Character {
public:
Hero(const std::string& name) : m_name(name) {}
void attack() override {
std::cout << m_name << " 发起了普通攻击!" << std::endl;
}
private:
std::string m_name;
};
// 装饰器基类
class Equipment : public Character {
public:
Equipment(std::shared_ptr<Character> character) : m_character(character) {}
void attack() override {
if (m_character) {
m_character->attack();
}
}
protected:
std::shared_ptr<Character> m_character;
};
// 武器装饰器
class WeaponDecorator : public Equipment {
public:
WeaponDecorator(std::shared_ptr<Character> character) : Equipment(character) {}
void attack() override {
Equipment::attack();
std::cout << ">>> 装备武器:攻击力提升!" << std::endl;
}
};
// 护甲装饰器
class ArmorDecorator : public Equipment {
public:
ArmorDecorator(std::shared_ptr<Character> character) : Equipment(character) {}
void attack() override {
Equipment::attack();
std::cout << ">>> 穿戴护甲:防御力提升!" << std::endl;
}
};
// 客户端
int main() {
// 基础角色
std::shared_ptr<Character> hero = std::make_shared<Hero>("勇者");
std::cout << "--- 普通英雄 ---" << std::endl;
hero->attack();
std::cout << "\n--- 英雄装备武器 ---" << std::endl;
std::shared_ptr<Character> heroWithWeapon = std::make_shared<WeaponDecorator>(hero);
heroWithWeapon->attack();
std::cout << "\n--- 英雄穿戴护甲 ---" << std::endl;
std::shared_ptr<Character> heroWithArmor = std::make_shared<ArmorDecorator>(hero);
heroWithArmor->attack();
std::cout << "\n--- 英雄装备武器 + 护甲 ---" << std::endl;
std::shared_ptr<Character> heroWithAll =
std::make_shared<ArmorDecorator>(
std::make_shared<WeaponDecorator>(hero));
heroWithAll->attack();
return 0;
}
程序运行结果:
--- 普通英雄 ---
勇者 发起了普通攻击!
--- 英雄装备武器 ---
勇者 发起了普通攻击!
>>> 装备武器:攻击力提升!
--- 英雄穿戴护甲 ---
勇者 发起了普通攻击!
>>> 穿戴护甲:防御力提升!
--- 英雄装备武器 + 护甲 ---
勇者 发起了普通攻击!
>>> 装备武器:攻击力提升!
>>> 穿戴护甲:防御力提升!
代码说明:
在这段代码里,Character 定义了角色的统一接口,Hero
作为具体实现提供了最基础的攻击行为。Equipment 则是一个抽象的装饰器,它内部保存了一个角色对象,并在调用时转发给原始角色。
WeaponDecorator 和 ArmorDecorator
继承自 Equipment
,在原有攻击行为的基础上分别增加了武器和护甲的效果。
这样,当我们在 main
函数里把英雄用不同的装饰器包裹起来时,就能够灵活地给角色动态添加功能,而且这些功能可以自由叠加,而不用修改英雄类本身。
五、总结
装饰器模式让我们在游戏开发中能够更灵活地为角色增加装备或技能效果,而不需要写出大量的组合类。
相比继承的方式,装饰器模式具有以下优势:
解耦:角色与装备的功能独立,扩展不会影响原有类;
灵活组合:装备可以随意叠加,避免类爆炸;
符合开闭原则:增加新装备时只需写新装饰器类,不必修改已有类。
这种模式在实际游戏开发中非常实用,比如:角色技能 Buff 叠加、武器/装备系统、特效系统等。