상태(state) 패턴 한번 써 볼까?
일이 일이다 보니 상태(state)를 다룰 일이 아주 많습니다. 상태로 시작해 상태로 끝난다고 해도 과언이 아닐 정도지만, 패턴에 익숙하지 않아 그다지 쓰지 않다 보니 보통 그렇듯 간편하게(?) 상태 값으로 처리합니다. 이미 책과 인터넷에서 많이 찾아 볼 수 있는 내용이긴 하겠지만 상태 패턴을 한번 써 보기로 맘 먹은지라 기억도 되살릴겸 간단히 정리해 봅니다.
IMM 객체 상태 도해인데 이게 뭔지는 중요하지 않으니 넘어갑니다. 중요한 것은 이 객체에 크게 IN SERVICE, NOT IN SERVICE로 두 가지 상태가 있고 NOT IN SERVICE에는 하위 상태인 EXTERNAL SELECT, INTERNAL SELECT 상태가 있다는 점입니다. 화살표는 상태 전이 경로를 나타냅니다. 정리하면 다음과 같습니다.
From | To |
IN SERVICE | EXTERNAL SELECT |
IN SERVICE | INTERNAL SELECT |
EXTERNAL SELECT | IN SERVICE |
INTERNAL SELECT | IN SERVICE |
상태 패턴에서는 흔히 상태 값으로 나타내는 상태 하나하나를 모두 객체로 정의하며 상태 전이를 일으키는 방아쇠(trigger)를 메소드로 정의합니다. 그럼 실제로 구현하기 전에 일반적인 상태 패턴을 보겠습니다.
그림은 Head First Design Patterns에서 가져왔습니다. 간단히 설명하면 Context
에서는 인터페이스인 State
만 사용해 handle()
을 호출하는데 실제 호출하는 handle()
은 ConcreteStateA::handle()
또는 ConcreteStateB::handle()
이 됩니다. 이는 당시 Context 상태 전이에 따라 처리합니다. 그럼 다시 처음 상태 도해를 바탕으로 클래스 도해를 만들어 봅니다.
이제 실제 코드 예를 보겠습니다. 먼저 ImmTransitionState
클래스입니다.
1 2 3 4 5 6 7 8 9 10 11 |
#ifndef IMM_TRANSITION_STATE_H_ #define IMM_TRANSITION_STATE_H_ class ImmTransitionState { public: virtual void toInService() = 0; virtual void toNoInServiceExternal() = 0; virtual void toNoInServiceInternal() = 0; }; #endif |
ImmTransitionInService
클래스입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#ifndef IMM_TRANSITION_INSERVICE_H_ #define IMM_TRANSITION_INSERVICE_H_ #include "ImmTransitionState.h" class ImmObject; class ImmTransitionInService : public ImmTransitionState { public: ImmTransitionInService(ImmObject* immObj) : immObject_(immObj) {}; ~ImmTransitionInService() {}; virtual void toInService(); virtual void toNoInServiceExternal(); virtual void toNoInServiceInternal(); private: ImmObject* const immObject_; }; #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include <iostream> #include "ImmTransitionInService.h" #include "ImmObject.h" void ImmTransitionInService::toInService() { std::cout << "Already here!" << std::endl; std::cout << "InService State" << std::endl << std::endl; return; } void ImmTransitionInService::toNoInServiceExternal() { std::cout << "ImmTransitionInService::toNoInServiceExternal()" << std::endl; immObject_->transitionState(immObject_->getNoInServiceExteranlState()); std::cout << "External State" << std::endl << std::endl; return; } void ImmTransitionInService::toNoInServiceInternal() { std::cout << "ImmTransitionInService::toNoInServiceInternal()" << std::endl; immObject_->transitionState(immObject_->getNoInServiceInteranlState()); std::cout << "Internal State" << std::endl << std::endl; return; } |
ImmTransitionNoInServiceExternal
클래스입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#ifndef IMM_TRANSITION_NOINSERVICE_EXTERNAL_H_ #define IMM_TRANSITION_NOINSERVICE_EXTERNAL_H_ #include "ImmTransitionState.h" class ImmObject; class ImmTransitionNoInServiceExteranl : public ImmTransitionState { public: ImmTransitionNoInServiceExteranl(ImmObject* immObj) : immObject_(immObj) {}; ~ImmTransitionNoInServiceExteranl() {}; virtual void toInService(); virtual void toNoInServiceExternal(); virtual void toNoInServiceInternal(); private: ImmObject* const immObject_; }; #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <iostream> #include "ImmTransitionNoInServiceExternal.h" #include "ImmObject.h" void ImmTransitionNoInServiceExteranl::toInService() { std::cout << "ImmTransitionNoInServiceExteranl::toInService()" << std::endl; immObject_->transitionState(immObject_->getInServiceState()); std::cout << "InService State" << std::endl << std::endl; return; } void ImmTransitionNoInServiceExteranl::toNoInServiceExternal() { std::cout << "Already here!" << std::endl; std::cout << "External State" << std::endl << std::endl; return; } void ImmTransitionNoInServiceExteranl::toNoInServiceInternal() { std::cout << "ImmTransitionNoInServiceExteranl::toNoInServiceInternal()" << std::endl; std::cout << "Invalid Transition!" << std::endl; std::cout << "External State" << std::endl << std::endl; return; } |
ImmTransitionNoInServiceInteranl
클래스입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#ifndef IMM_TRANSITION_NOINSERVICE_INTERNAL_H_ #define IMM_TRANSITION_NOINSERVICE_INTERNAL_H_ #include "ImmTransitionState.h" class ImmObject; class ImmTransitionNoInServiceInteranl : public ImmTransitionState { public: ImmTransitionNoInServiceInteranl(ImmObject* immObj) : immObject_(immObj) {}; ~ImmTransitionNoInServiceInteranl() {}; virtual void toInService(); virtual void toNoInServiceExternal(); virtual void toNoInServiceInternal(); private: ImmObject* const immObject_; }; #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include "stdafx.h" #include <iostream> #include "ImmTransitionNoInServiceInternal.h" #include "ImmObject.h" void ImmTransitionNoInServiceInteranl::toInService() { std::cout << "ImmTransitionNoInServiceInteranl::toInService()" << std::endl; immObject_->transitionState(immObject_->getInServiceState()); std::cout << "InService State" << std::endl << std::endl; return; } void ImmTransitionNoInServiceInteranl::toNoInServiceExternal() { std::cout << "ImmTransitionNoInServiceInteranl::toNoInServiceExternal()" << std::endl; std::cout << "Invalid Transition!" << std::endl; std::cout << "External State" << std::endl << std::endl; return; } void ImmTransitionNoInServiceInteranl::toNoInServiceInternal() { std::cout << "Already here!" << std::endl; std::cout << "Internal State" << std::endl << std::endl; return; } |
ImmObject
클래스입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#ifndef IMM_OBJECT_H_ #define IMM_OBJECT_H_ #include <memory> #include "ImmTransitionState.h" class ImmObject { public: ImmObject(); ~ImmObject() {}; void toInService(); void toNoInServiceExternal(); void toNoInServiceInternal(); void transitionState(std::shared_ptr<ImmTransitionState> state) { state_ = state; } std::shared_ptr<ImmTransitionState> getInServiceState() { return inService_; } std::shared_ptr<ImmTransitionState> getNoInServiceExteranlState() { return exteranl_; } std::shared_ptr<ImmTransitionState> getNoInServiceInteranlState() { return interanl_; } private: std::shared_ptr<ImmTransitionState> inService_; std::shared_ptr<ImmTransitionState> exteranl_; std::shared_ptr<ImmTransitionState> interanl_; std::shared_ptr<ImmTransitionState> state_; }; #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include "ImmObject.h" #include "ImmTransitionInService.h" #include "ImmTransitionNoInServiceExternal.h" #include "ImmTransitionNoInServiceInternal.h" ImmObject::ImmObject() { inService_.reset(new ImmTransitionInService(this)); exteranl_.reset(new ImmTransitionNoInServiceExteranl(this)); interanl_.reset(new ImmTransitionNoInServiceInteranl(this)); state_ = interanl_; } void ImmObject::toInService() { state_->toInService(); } void ImmObject::toNoInServiceExternal() { state_->toNoInServiceExternal(); } void ImmObject::toNoInServiceInternal() { state_->toNoInServiceInternal(); } |
마지막으로 시험 코드입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <memory> #include "ImmObject.h" int _tmain(int argc, _TCHAR* argv[]) { std::shared_ptr<ImmObject> immObj(new ImmObject); immObj->toInService(); immObj->toNoInServiceExternal(); immObj->toNoInServiceInternal(); immObj->toNoInServiceInternal(); immObj->toNoInServiceExternal(); immObj->toInService(); immObj->toInService(); immObj->toNoInServiceInternal(); immObj->toNoInServiceExternal(); immObj->toInService(); return 0; } |