뭔가 코드를 만들다 보니 너무 길어졌다 ㅋㅋ 코딩을 시작하면 왜 이렇게 진지하게 되어버리는가… 대충 하고 치우려고 했는데 사실 ㅋㅋ 그래도 집중 못하는 것보다는 낫겠지.

아무튼 이번에 볼 패턴은 스테이트 패턴.



- 객체의 상태를 구현된 인터페이스에 맞춰 바꿔주는 패턴

장점 1. 런타임 중에 객체의 사용 용도를 아예 바꿔줄 수 있다.

장점 2. 내부를 캡슐화 한 채로 용도를 바꿀 수 있다.



예제.

class State{
public:
    State() : hp(100), maxHp(100), speed(1), ap(10) {}
    State(State* state) : maxHp(state->getMaxHp()), hp(state->getHp()), speed(state->getSpeed()), ap(state->getAp()) {
        if (state->state == "Poison"){
            speed *= 2;
            ap *= 2;
        }
    }
    virtual ~State() = 0;

    virtual int getHp(){
        return hp;
    }
    int getMaxHp(){
        return maxHp;
    }
    virtual float getSpeed(){
        return speed;
    }
    virtual int getAp(){
        return ap;
    }
    virtual void damaged(int damage){
        hp -= damage;
        if (hp <= 0){
            hp = 0;
            cout << "dead player" << endl;
        }
    }

    void printState(){
        cout << "state : " << state << endl;
        cout << "hp : " << maxHp << '/' << getHp() << endl;
        cout << "speed : " << getSpeed() << endl;
        cout << "ap : " << getAp() << endl;
    }
protected:
    void setHp(int hp){
        this->hp = hp;
    }
    void setSpeed(float speed){
        this->speed = speed;
    }
    void setAp(int ap){
        this->ap = ap;
    }
    void setState(const char* state){
        this->state = state;
    }
private:
    const char* state;
    int hp, maxHp;
    float speed;
    int ap;
};
State::~State() {}
// 보통
class NormalState : public State{
public:
    NormalState(){
        setState("Normal");
    }
    NormalState(State* state) : State(state) {
        setState("Normal");
    }
    ~NormalState() {}
};
// 중독
class PoisonState : public State{
public:
    PoisonState(State* state) : State(state), _time(time(NULL))  {
        setState("Poison");
    }
    ~PoisonState(){}
    // 초마다 1씩 hp를 깎는다.
    int getHp() override {
        setHp(State::getHp() - getCalSec());
        // 현재 시간으로 다시 저장
        _time = time(NULL);
        return State::getHp();
    }
    // 스피드와 공격력이 절반
    float getSpeed() override {
        return State::getSpeed() / 2;
    }
    int getAp() override {
        return State::getAp() / 2;
    }
private:
    // 중독된 시간 저장
    time_t _time;

    int getCalSec(){
        return static_cast<int>(time(NULL) - _time);
    }
};
// 무적
class SuperState : public State{
public:
    SuperState(State* state) : State(state) {
        setState("Super");
    }
    ~SuperState() {}

    // 데미지를 받지 않는다.
    void damaged(int damage) override{
        return;
    }
};

class Player{
public:
    Player() : _state(new NormalState()) {}

    void setState(State* state){
        _state.reset(state);
    }
    void printState(){
        _state->printState();
    }
    void damaged(int damage){
        _state->damaged(damage);
    }
    State* getState(){
        return _state.get();
    }
private:
    std::unique_ptr<State> _state;
};

int main(){
    Player p;
    p.printState();
    cout << endl;
    
    // 데미지 2
    p.damaged(2);
    p.printState();
    cout << endl;

    // 중독
    p.setState(new PoisonState(p.getState()));
    p.printState();
    cout << endl;

    // 5초동안 데미지
    time_t now = time(NULL);
    while (time(NULL) - now < 5){}
    p.printState();
    cout << endl;

    // 무적
    p.setState(new SuperState(p.getState()));
    p.printState();
    cout << endl;

    // 데미지 없음
    p.damaged(100);
    p.printState();
    cout << endl;

    // 죽음
    p.setState(new NormalState(p.getState()));
    p.damaged(100);
    cout << endl;
    p.printState();

    return 0;
}