2019년 10월 26일 토요일

디자인 패턴 다시보기(정리중)

------------------------------------------------------
------------------------------------------------------
Command Pattern(명령 패턴)

가능한 모든 요청명령을 캡슐화화여 스트림으로 처리되도록 구현
스퀀셜한 명령 처리가 가능하고 취소(undo) 및 재실행(redo)이 가능함

- 플레이어를 포함한 NPC, Monster들의 동작 지시에 활용
- UI에 적용할 경우 튜토리얼 동작에도 활용가능


------------------------------------------------------
------------------------------------------------------
flyweight Pattern(경량/플라이급 패턴)

공통된 자원을 메모리상 공유하게금 처리하여 메모리 손실을 줄이고
- 유사한 모양의 다수의 오브젝트들을 구성할때...
  > 수많은 나무들, 지형 타일들
- 메쉬, 텍스쳐, 메터리얼 등 공통된 자원은 서로 공유하여 사용되게금 처리
- 객체 풀 패턴과 함께 사용해야 유용함

* 드로잉 콜을 줄여주는 인스턴스 렌더링 기술과 접목하면 효과적!


------------------------------------------------------
------------------------------------------------------
observer Pattern(관찰자 패턴)

특정 변화를 감시하고 변화(이벤트)가 생길경우(통지가 날라오면) 값의 변화에 따라 정해진 처리 흐름을 수행하도록 구현
- 보유 자원량의 변화
- 업적 성취 여부 판단
- 패시브 아이템의 사용 여부
- 기본 설정값의 변화

* ReactiveX를 활용!


------------------------------------------------------
------------------------------------------------------
prototype Pattern(프로토타입 패턴)

원형의 인스턴스로 부터 동일한(혹은 성질만 일부 다른) 인스턴스를 복사 생성하는 패턴
원형이 되는 프로토타입 히든 인스턴스를 만들어 놓고 특정 오브젝트를 일정 주기별로 스폰!
구현레벨에서는 clone 가상함수를 통해 인스턴스를 복사생성 한다는 개념으로 이해
- 몬스터나 총알등의 스포너 spawner

데이터 모델링을 위한 프로토 타임
- json형태의 대상 객체를 생성
- 상속개념이 없는 json의 구조를 위임이라는 의미로 객체간 연결

{
"이름":"고블린보병",
"체력":20,
"내성":["추위, "독"],
"약점":["불", "빛"]
}

{
"이름":"고블린마법사"
"프로토타입":"고블린보병",
"마법":["화염구"]
"보너스 대미지":20,
}


------------------------------------------------------
------------------------------------------------------
singleton Pattern(싱글톤 패턴)

각종 메니져,메니져,메니져에 사용하고 있음..
코드들간의 커플링 문제를 야기함, 멀티쓰레드에 취약, 전역변수나 다름없음.
- 가능하면 메니져는 최소화
- 함수 인자로 넘길수 있다면 싱글톤으로 만들지 말자. 가능하다면 말이지...
- 필요하다면 최소한으로 묶어라..
  Game::Instance()->getFile()->save(...);
  Game::Instance()->getAudio()->play(...);

메니저들에 활용할 용도라면 서비스 중개자 패턴을 참고해보자


------------------------------------------------------
------------------------------------------------------
state Pattern(상태 패턴)

오브젝트 상태에 대한 인터페이스를 정의하고, 각 상태 동작을 처리하는 독립된 클래스 생성
상태가 변경됨에 떄라 상태 동작을 수행하는 인스턴스로 핸들 변경 처리..
(같은 상태에 대한 모든 동작과 데이터를 클래스 하나에 캡슐화!)
- 플레이어나 NPC, 몬스터등 FSM상태의 특성을 가지는 오브젝트들에 활용

class HeroState
{
   virtual ~HeroState();
   virtual void handleInput(Hero &hero, Input input) {}
   virtual void update(Hero &hero) {}
}

class StandingState : HeroState
{
   virtual void handleInput(Hero &hero, Input input)
   {
      if(input == RELEASE_DOWN)
         return new StrandingState();
   }
   ...
}


class Hero
{
public:
   enum class State { Standing, Ducking, Jumping, Siving };

   void handleInput(Input input)
   {
      HeroState *newState = state_->handleInput(*this, input);
      if(null != newState)
      {
         delete state_;
         state_ = newState
         state_->enter(*this);
      }
   }

   void update(Hero &hero)
   {
      state_->update(*this);
   }

private:
   HeroState *state_;
   //HeroState *state2_; ///< 상태를 여러개 두면 이 자체가 parallel state machine(병행 상태 기계)인것임.
}

** FSM(finite state machine) 유한 상태 기계
- 가질 수 있는 상태가 한정되어 있다.
- 한번에 한가지 상태만 유지할 수 있다.
- 입력이나 이벤트가 기계에 전달된다.
- 각 상태에는 입력에 따라 다음상태로 변경되는 전이가 있다.

** 푸쉬다운 오토마타
위 클래스에서 state_ 변수를 스택으로 관리하고 한 상태가 끝나면 스택의 이전 상태로 자동 회귀하는 방식



------------------------------------------------------
------------------------------------------------------
Service Mediator Pattern(서비스 중개자 패턴)
객체나 시스템 거의 모든 코드에서 사용되는 기능을..
로그나 오디오, 광고, IAP등 여기저기 고정 위치를 종잡기 어려운 기능들을 위한 패턴이랄까
싱글톤 형식만으로 구현하지 말고 각 기능별 인터페이스를 만들어 null인스턴스(널 서비스)를 만들어 초기화해두고 사용하는게 기본 개념


AudioService *pAudioService = ServiceProvider::Instance()->GetAudioService();
pAudioService->PlaySound("Lobby_BGM");


class ServiceProvider
{
public:
    static void initialize()
    {
        service_ = &nullService_;
    }

    static Audio& GetAudioService() { return *pAudioService_; }

    static void SetAudioService(AudioService *pAudioService)
    {
        if(service == NULL) // 널 서비스로 돌려 놓는다.
            pAudioService_ = &nullAudioService_;
        else
            pAudioService_ = pAudioService;
    }
private:
    static AudioService* pAudioService_;
    static NullAudioService nullAudioService_;
};


class AudioService
{
public:
    virtual ~Audio() {}
    virtual void playSound(int soundID) = 0;
    virtual void stopSound(int soundID) = 0;
    virtual void stopAllSounds() = 0;
};

class NullAudioService : public AudioService
{
public:
    virtual void playSound(int soundID) { /* 아무것도 하지 않는다. */ }
    virtual void stopSound(int soundID) { /* 아무것도 하지 않는다. */ }
    virtual void stopAllSounds(int soundID) { /* 아무것도 하지 않는다. */ }
};


class PlatformAudioService : public AudioService
{
public:
    virtual void playSound(int soundID) {
        // 콘솔의 오디오 API를 이용해 사운드를 출력한다...
    }
    virtual void stopSound(int soundID) {
        // 콘솔의 오디오 API를 이용해 사운드를 wndwl한다...
    }
    virtual void stopAllSounds(int soundID) {
        // 콘솔의 오디오 API를 이용해 모든 사운드를 중지한다...
    }
};


------------------------------------------------------
------------------------------------------------------
캐쉬 미쓰

데이터 메모리를 어떻게 배치하느냐에 따라 CPU의 캐쉬활용 성능이 크게 바뀐다.
(크게 50배까지 성능 향상을 볼 수 있단다.)

반복문에서 호출되는 포인터들을 가능한 한 배열안에 떄려 넣어 그 배열이 캐싱되어 고속처리 되게금 유도하는 구현 기법이랄까..

댓글 없음:

댓글 쓰기