반응형
전략 패턴과 템플릿 메서드 패턴은 매우 유사합니다.
전략 패턴이 구성을 이용하지만 템플릿 메서드 패턴은 상속을 이용합니다.
핵심 원리는 알고리즘과 상세 구현을 분리하여 구현하는 것입니다.
게임 시뮬레이션
보드 게임류는 게임 시작, 턴 플레이, 승자 결정이 되고 게임 종료됩니다.
class Game
{
public:
explicit Game(int number_of_players) : number_of_players(number_of_players) {}
// 게임의 알고리즘
void run()
{
start();
while (!have_winner())
take_turn();
cout << "Player " << get_winner() << " wins.\n";
}
protected:
virtual void start() = 0;
virtual bool have_winner() = 0;
virtual void take_turn() = 0;
virtual int get_winner() = 0;
int current_player{ 0 };
int number_of_players;
};
Game 클래스를 확장하여 상세 구현부를 구현합니다.
class Chess : public Game
{
public:
explicit Chess() : Game{ 2 } {}
protected:
void start() override
{
cout << "Starting a game of chess with " << number_of_players << " players\n";
}
bool have_winner() override
{
return turns == max_turns;
}
void take_turn() override
{
cout << "Turn " << turns << " taken by player " << current_player << "\n";
turns++;
current_player = (current_player + 1) % number_of_players;
}
int get_winner() override
{
return current_player;
}
private:
int turns{ 0 }, max_turns{ 10 };
};
다음과 같이 체크 게임을 실행합니다.
Chess chess;
chess.run();
템플릿 메서드 패턴과 전략 패턴을 알기 쉬운 간단한 예입니다.
-
템플릿 메서드 패턴은 상속을 이용하여 "알고리즘 부분"과 "상세 기능 구현 부분"을 분리합니다.
class Character
{
public:
// 알고리즘
void attack()
{
prepareWeapon();
prepareSkill();
useSkill();
}
protected:
virtual void prepareWeapon() = 0;
virtual void prepareSkill() = 0;
virtual void useSkill() = 0;
};
// 아처 상세 구현
class Archer : public Character
{
public:
void prepareWeapon() override
{
cout << "활을 준비합니다." << endl;
}
void prepareSkill() override
{
cout << "활 스킬 발사를 위해 활을 조준합니다." << endl;
}
void useSkill() override
{
cout << "활에 발사합니다." << endl;
}
};
// 워리어 상세 구현
class Warrior : public Character
{
public:
void prepareWeapon() override
{
cout << "검을 준비합니다." << endl;
}
void prepareSkill() override
{
cout << "검 스킬 사용을 위해 검에 기를 넣습니다." << endl;
}
void useSkill() override
{
cout << "검을 휘두릅니다." << endl;
}
};
int main()
{
Archer archer;
archer.attack();
Warrior warrior;
warrior.attack();
return 0;
}
- 전략 패턴은 구성을 이용하여 "알고리즘 부분"과 "상세 기능 구현 부분"을 분리합니다.
template<typename T>
class Character
{
public:
void attack()
{
Combat.prepareWeapon();
Combat.prepareSkill();
Combat.useSkill();
}
private:
T Combat;
};
class Combat
{
protected:
virtual void prepareWeapon() = 0;
virtual void prepareSkill() = 0;
virtual void useSkill() = 0;
};
class ArcherCombat : public Combat
{
public:
void prepareWeapon() override
{
cout << "활을 준비합니다." << endl;
}
void prepareSkill() override
{
cout << "활 스킬 발사를 위해 활을 조준합니다." << endl;
}
void useSkill() override
{
cout << "활에 발사합니다." << endl;
}
};
class WarriorCombat : public Combat
{
public:
void prepareWeapon() override
{
cout << "검을 준비합니다." << endl;
}
void prepareSkill() override
{
cout << "검 스킬 사용을 위해 검에 기를 넣습니다." << endl;
}
void useSkill() override
{
cout << "검을 휘두릅니다." << endl;
}
};
int main()
{
Character<ArcherCombat> archer;
archer.attack();
Character< WarriorCombat> warrior;
warrior.attack();
return 0;
}
- Strategy Pattern, Template method Pattern 결국 구현은 같은데 왜 둘로 나누고 이름도 다르게 주었을까?
알고리즘이나 세부 구현이 변경될 여기가 있고 좀더 복합적인 상황에서는 Strategy Pattern을 고려하면 좋습니다. 동일한 구현이지만 전략적으로 어떤 세부 구현을 사용할지가 중요하므로 Strategy Pattern으로 이름을 지었을 것이라고 추측합니다. 명쾌하고 한번 구현하면 틀(template)처럼 변화가 없을 것 같은 상황에서는 오히려 코드가 간결하고 가독성도 좋습니다. 이러한 이유로 Template method pattern으로 이름 지었을 것으로 추측합니다. method가 붙은 이유는 세부 구현을 틀화된 method로 구현하기 때문이겠지요.
코드 참고 : https://cpp-design-patterns.readthedocs.io/en/latest/
'프로그래밍 일반 > 디자인 패턴' 카테고리의 다른 글
방문자 패턴(Visitor Pattern) (0) | 2020.03.04 |
---|---|
전략 패턴(Strategy Pattern) (0) | 2020.03.04 |
상태 패턴(State Pattern) (0) | 2020.03.04 |
관찰자 패턴(Observer Pattern) (0) | 2020.03.04 |
Null 객체 (0) | 2020.03.04 |