[모던 c++ 디자인 패턴] 13-17장

hyng·2023년 4월 24일
0

모던 c++ 디자인 패턴 을 읽고 인상 깊었던 내용을 정리합니다.

책임 사슬

어떤 컴퓨터 게임에 크리처들이 있다고 하자. 크리처들은 공격력과 방어력 두 가지 값을 속성으로 가진다.

크리처의 속성은 특정 이벤트가 발생 했을때 이벤트에 맞게 변경되어야 한다. 이러한 처리를 CreatureModifier를 통해서 구현한다고 하자.

struct Creature
{
	string name;
	int attack, defense;
	...
};

class CreatureModifier
{
	CreatureModifier* next{nullptr};
	protected;
		Creature& creature;
	public:
		explicit CreatureModifier(Creature& creature) : creature(creature) {]
		void add(CreatureModifier* cm) 
		{
			if (next) next->add(cm);
			else next = cm;
		}
		virtual void handle()
		{
			if (next) next->handle();
		}
}

CreatureModifier을 구현하여 실질적인 작업들이 추가되기 시작하면 이 구현의 의미가 더 명확 해진다.

class DoubleAttackModifier : public CreatureModifier
{
	public:
		explicit DoubleAttackModifier(Creatrue& creature) : CreatureModifier(creature) {}
		void handle() override
		{
			creature.attack *= 2;
			CreatureModifier::handle(); //변경 작업의 사슬이 연이어질 수 있도록 하기 위함이다.
		}
};

만약 크리처가 어떤 마법의 적용을 받아 상태의 변경이 없도록 해야 한다는 요구사항이 있다면 다음처럼 구현하면 된다.

그리고 책임 사슬의 제일 앞에 NoBonusesModifier을 위치시키면 된다.

class NoBonusesModifier : public CreatureModifier
{
	public:
		explicit NoBonusesModifier(Creatrue& creature)
		void handle() override
		{ 
			// 아무것도 안하기, 부모 클래스의 handle()을 호출하지 않는다.
		}
}; 

매개자

서로 직접적으로 참조하지 않더라도 커뮤니케이션을 할 수 있게 한다는것을 기본 아이디어로 한다.

17.2 매개자와 이벤트

struct EventData
{
	virtual ~EventData() = default;
	virtual void print() const = 0;
};

struct PlayerScoredData : EventData
{
	string player_name;
	int goals_scored_so_far;

	PlayerScoredData(const string& player_name, const int goals_scored_so_far) :player_name(player_name), goals_scored_so_far(goals_scored_so_far) {}
	void print() const override
	{
		cout << player_name << " has scored!" (their " << goals_scored_so_far << " goal)" << "\n";
	}
};

struct Game //매개자, 이벤트 기반 구조에서는 매개자가 직접 일을 수행하지 않는다. 
{
	signal<void(EventData*). events; // 관찰자
};
struct Player
{
	string name;
	int goals_scored = 0;
	Game& game;
	
	Player(const string& name, Game& game) : name(name), game(game) {]
	void score()
	{
		goals_scored++;
		PlayerScoredData ps{name, goals_scored};
		game.events(&ps);
	}
};

struct Coach
{
	Game& game;
	explicit Coach(Game& game) : game(game)
	{
		game.events.connect([](EventData* e)
		{
			PlayerScoredData* ps = dynamic_cast<PlayerScoredData*>(e);
			if (ps && ps->goals_scored_so_far < 3)
			{
				cout << "coach says: well done, " << ps->player_name << "\n";
			}
	}
};
profile
공부하고 알게 된 내용을 기록하는 블로그

0개의 댓글