컴포지트 패턴 (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;
}

+ Recent posts