昨天更新了擴充卡,今天來盤一盤裝飾器模式。裝飾器模式以一種動态的方式給對象添加額外的職責,好似“裝飾”在對象身上一樣,通常通過繼承和委托來實作。
目錄
一、裝飾器模式介紹
二、遊戲人物如何使用裝飾器模式
三、進階寫法(使用智能指針)
四、使用模闆類
代碼連結:
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;
}
這個例子示範了如何使用模闆類實作裝飾器模式。通過使用模闆類,我們可以更靈活地處理不同類型的人物,并且可以避免類型的重複定義。如果你需要更多類型的人物,你隻需要定義一個新的類,并在裝飾器類上進行模闆特化即可。
類圖: