컴포지트 패턴 (Composite Pattern)
객체를 트리구조로 구성해서 부분-전체 계층구조를 구현한다.
컴포지트를 사용하면 클라이언트에서 개별 객체와 복합 객체를 같은 방법으로 다룰 수 있다.
- 전체-부분 관계를 트리 구조로 표현하고 싶을 경우.
- 전체-부분 관계를 클라이언트에서 부분, 관계 객체를 균일하게 처리하고 싶을 경우.
-> 스타크래프트 프로토스를 상속받은 질럿, 드라군, 리버가 있지만 이 들을 한 번에 부대지정으로 같은 명령을 수행할 수 있다.
#include <iostream>
#include <vector>
#include <memory>
#include <string>
#define abstract
using namespace std;
enum UnitType {
AirUnit,
LandUnit
};
enum AttackType {
AirOnly,
LandOnly,
CanAll
};
class Race {
public:
Race(const UnitType& _unitType, const AttackType& _attackType, const string& _unitName)
:unitType(_unitType), attackType(_attackType), unitName(_unitName) { cout << "Race 생성자" << endl; }
virtual ~Race() { cout << "Race 소멸자" << endl; }
virtual void Attack(shared_ptr<Race> target) {
cout << unitName;
if (target->GetType() == UnitType::AirUnit)
AirAttack(target);
else if (target->GetType() == UnitType::LandUnit)
LandAttack(target);
}
virtual void LandAttack(shared_ptr<Race> target) {
if (attackType == AttackType::AirOnly)
{
cout << "은(는) 지상 유닛을 공격할 수 없습니다." << endl;
return;
}
cout << "의 " + target->GetUnitName() + " 에게 ";
}
virtual void AirAttack(shared_ptr<Race> target) {
if (attackType == AttackType::LandOnly)
{
cout << "은(는) 공중 유닛을 공격할 수 없습니다." << endl;
return;
}
cout << "의 " + target->GetUnitName() + " 에게 ";
}
virtual void Move() {
cout << unitName + " 의 ";
}
string& GetUnitName() { return unitName; }
UnitType GetType() { return unitType; }
protected:
UnitType unitType;
AttackType attackType;
string unitName;
};
class Terran abstract: public Race {
public:
Terran(const UnitType& _unitType, const AttackType& _attackType, const string& _unitName)
:Race(_unitType, _attackType, _unitName) { cout << "Terran 생성자" << endl; }
~Terran() { cout << "Terran 소멸자" << endl; }
};
class Zerg abstract: public Race {
public:
Zerg(const UnitType& _unitType, const AttackType& _attackType, const string& _unitName)
:Race(_unitType, _attackType, _unitName) { cout << "Zerg 생성자" << endl; }
~Zerg() { cout << "Zerg 소멸자" << endl; }
};
class Protoss abstract: public Race {
public:
Protoss(const UnitType& _unitType, const AttackType& _attackType, const string& _unitName)
:Race(_unitType, _attackType, _unitName) { cout << "Protoss 생성자" << endl; }
~Protoss() { cout << "Protoss 소멸자" << endl; }
};
class Zealot : public Protoss {
public:
Zealot() : Protoss(UnitType::LandUnit, AttackType::LandOnly, "질럿") { cout << "지상 유닛 질럿 생성" << endl; }
~Zealot() { cout << "질럿 소멸자" << endl; }
void LandAttack(shared_ptr<Race> target) override {
Race::LandAttack(target);
cout << "쌍칼 공격" << endl;
}
void Move() override {
Race::Move();
cout << "뚜벅뚜벅" << endl;
}
};
class Dragoon : public Protoss {
public:
Dragoon() : Protoss(UnitType::LandUnit, AttackType::CanAll, unitName = "드라군") { cout << "지상 유닛 드라군 생성" << endl; }
~Dragoon() { cout << "드라군 소멸자" << endl; }
void LandAttack(shared_ptr<Race> target) override {
Race::LandAttack(target);
cout << "캐논 공격" << endl;
}
void AirAttack(shared_ptr<Race> target) override {
Race::AirAttack(target);
cout << unitName + " 의 캐논 공격" << endl;
}
void Move() override {
Race::Move();
cout << "뚜벅뚜벅" << endl;
}
};
class Reaver : public Protoss {
public:
Reaver() : Protoss(UnitType::LandUnit, AttackType::LandOnly, "리버") { cout << "지상 유닛 리버 생성" << endl; }
~Reaver() { cout << "리버 소멸자" << endl; }
void LandAttack(shared_ptr<Race> target) override {
Race::LandAttack(target);
cout << "강력한 캐논 공격" << endl;
}
void Move() override {
Race::Move();
cout << "뒤뚱뒤뚱" << endl;
}
};
class Corsair : public Protoss {
public:
Corsair() : Protoss(UnitType::AirUnit, AttackType::AirOnly, "커세어") { cout << "공중 유닛 커세어 생성" << endl; }
~Corsair() { cout << " 커세어 소멸자" << endl; }
void AirAttack(shared_ptr<Race> target) override {
Race::AirAttack(target);
cout << unitName + " 의 레이저 공격" << endl;
}
void Move() override {
Race::Move();
cout << "공중 이동" << endl;
}
};
class ProtossSquad : public Protoss {
public:
ProtossSquad() : Protoss(UnitType::AirUnit, AttackType::AirOnly, "프로토스 부대") { cout << "프로토스 부대지정 생성자" << endl; }
~ProtossSquad() { cout << "프로토스 부대지정 소멸자" << endl; }
void addUnit(shared_ptr<Protoss> protossUnit) {
squad.push_back(protossUnit);
cout << protossUnit->GetUnitName() + " 부대지정 추가" << endl;
}
void removeUnit() {
}
void Attack(shared_ptr<Race> target) override {
for(const shared_ptr<Protoss> unit : squad) {
unit->Attack(target);
}
}
void Move() override {
for(const shared_ptr<Protoss> unit : squad) {
unit->Move();
}
}
private:
vector<shared_ptr<Protoss>> squad;
};
class Goliath : public Terran {
public:
Goliath() : Terran(UnitType::LandUnit, AttackType::CanAll, "골리앗") { cout << "지상 유닛 골리앗 생성" << endl; }
~Goliath() { cout << " 골리앗 소멸자" << endl; }
void LandAttack(shared_ptr<Race> target) override {
Race::LandAttack(target);
cout << "개틀링 공격" << endl;
}
void AirAttack(shared_ptr<Race> target) override {
Race::AirAttack(target);
cout << "미사일 공격" << endl;
};
void Move() override {
Race::Move();
cout << "웅 치킨" << endl;
}
};
int main() {
cout << "--------------게임 시작-----------------" << endl;
unique_ptr<Protoss> zealot1 = make_unique<Zealot>();
unique_ptr<Protoss> corsair1 = make_unique<Corsair>();
unique_ptr<Terran> goliath = make_unique<Goliath>();
goliath->Move();
goliath->Attack(move(zealot1));
zealot1.reset(); // 질럿 죽음
goliath->Move();
goliath->Attack(move(corsair1));
corsair1.reset(); // 커세어 죽음
unique_ptr<Protoss> zealot2 = make_unique<Zealot>();
unique_ptr<Protoss> dragoon1 = make_unique<Dragoon>();
unique_ptr<Protoss> reaver1 = make_unique<Reaver>();
unique_ptr<Protoss> corsair2 = make_unique<Corsair>();
// 부대 지정
unique_ptr<ProtossSquad> protossSquad = make_unique<ProtossSquad>();
protossSquad->addUnit(move(zealot2));
protossSquad->addUnit(move(dragoon1));
protossSquad->addUnit(move(reaver1));
protossSquad->addUnit(move(corsair2));
protossSquad->Attack(move(goliath));
goliath.reset();
cout << "--------------게임 종료-----------------" << endl;
}
'디자인 패턴' 카테고리의 다른 글
상태 패턴 (State Pattern) (1) | 2023.05.17 |
---|---|
템플릿 메소드 패턴 (Template Method pattern) (0) | 2023.05.06 |
퍼사드 패턴 (Facade pattern) (0) | 2023.05.01 |
어댑터 패턴 (Adaptor pattern) (0) | 2023.04.30 |
커맨드 패턴 (Command Pattern) (0) | 2023.04.23 |