天天看點

設計模式之裝飾器模式,以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++為例。 一、裝飾器模式介紹二、遊戲人物如何使用裝飾器模式三、進階寫法(使用智能指針)四、使用模闆類

繼續閱讀