2009년 12월 01일
[방명록] Leave a Trace!!
# by | 2009/12/01 13:20 | 트랙백 | 덧글(1)
# by | 2009/08/01 13:19 | Gossip | 트랙백 | 덧글(0)
character 관련 FSM 을 realization 하면서 와우정도의 상태머신은 아니더라도, 국내 출시작인 AION만큼의 상태체크를 하고 싶어서
요새 새로운 Task를 진행하면서도 character에 관하여 가장 중요하다고 할수 있는 status machine 이기에 꾸준히
Improve 하던중 우연잖게 좋은글을 보고 동감하는 부분이 있어 링크를 겁니다.
-----------------------------------------------------------------------------------------------------------
[origin likn : http://www.gisdeveloper.co.kr/entry/Template을-이용한-Observer-패턴-1단계]
C++의 template을 이용해서 Observer를 구현하는 것에 대한 단계적 설명입니다. 원본은 데브피아에서 김태현(tipani)님이 올려 놓으신 글을 기반으로 작성했으며 한단계 더 업그레이드 했습니다. 제가 늘 느껴오는 것이지만 C++의 template은 기존의 클래스간 관계도에 한정해 볼적에 그 디자인을 획기적으로 개선한다는 점에서 그 판도를 확 바꿀 수 있는 강력한 개념이라고 생각합니다. 아무쪼록 제가 김태현님의 글을 보고 매우 재미있게 template에 한발짝 다가섯듯이 여러분도 제 글을 통해 template에 한발짝 다가 설수있다면 정말 기쁘겠습니다. 참고로 이 글을 읽기 전에 Observer 패턴이 무엇인지 패턴입문서를 살펴보시길 바랍니다. 또한 이 글의 진행은 단계 단계 개선해 나가는 흐름으로 진행된다는 점에 유의하시길 바랍니다.
먼저 1단계입니다. 아래의 코드는 Observer들의 관리에 대한 책임을 맡고 있는 Observed 클래스입니다.
template <class T>
class Observed {
public:
Observed() {}
typedef std::list<T *> typeObservers;
virtual ~Observed() {}
void RegisterObserver(T *pOb) {
m_listObserver.push_back( pOb );
}
void UnRegisterObserver(T *pOb) {
m_listObserver.remove(pOb);
}
protected:
typeObservers m_listObserver;
};
Observed가 관리하는 Observer 클래스인 Observabe 입니다. 단순히 Observed가 호출할 Observer의 OnEvent 함수가 순수가상함수로 선언되어 있습니다.
class Observable {
virtual void OnEvent(int a) = 0;
};
그리고 아래는 Obserable를 상속받아 구현한 클래스들입니다.
class Observable_A : public Observable
{
virtual void OnEvent(int a) {
std::cout << "Fire_A -> " << a << std::endl;
}
};
class Observable_B : public Observable
{
virtual void OnEvent(int a) {
std::cout << "Fire_B -> " << a << std::endl;
}
};
이제 마지막으로 Observed가 자신이 관리하고 있는 Observable의 OnEvent를 호출해 줘야 하는데, Observed 클래스는 자신이 관리하고 있는 Observable의 타입을 모르기 때문에 Observed와 Observable의 관계를 연결해 주기 위한, Observed로부터 상속받은 EventSrc 클래스가 필요합니다.
class EventSrc : public Observed<Observable>
{
void Fire(int a)
{
typeObservers::itrator it;
for(it=m_listObserver.begint(); it!=m_listObserver.end; ++it) {
(*it)->OnEvent(a);
}
}
};
드디어 1단계의 Observer 패턴의 구현이 완성되었습니다. 실제 사용하는 예는 다음과 같습니다.
int main() {
EventSrc *pES = new EventSrc();
Observable *pO_A = new Observale_A();
Observable *pO_B = new Observale_B();
pES->RegisterObserver(pOA);
pES->RegisterObserver(pOB);
pES->Fire(99);
delete pO_B;
delete pO_A;
delete pES;
return 0;
}
1단계에서 산출된 소스만으로도 충분할 수도 있겠지만, 큰 문제점이 하나 있습니다. 그것은 바로 SRP(Single Responsiblity Principle)를 위반한다는 사실입니다. 즉, Obserable를 관리하는 책임을 Observed와 EventSrc라는 두개의 클래스가 책임을 나눠서 지고 있다는 점입니다. 그럴수밖에 없는 이유는 본문에 언급을 했구요.
이제 다음 2단계 이후부터는 이러한 SRP의 원칙을 지켜나가는 것을 해결문제로 다뤄나가면서 점차적으로 개선된 Observer 패턴을 구현해보겠습니다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰~ 힘이 됩니다. ^^*
# by | 2008/11/27 22:24 | Do Job | 트랙백 | 덧글(1)

# by | 2008/07/27 22:11 | 트랙백(1) | 덧글(0)

# by | 2008/07/27 22:08 | Gossip | 트랙백 | 덧글(0)
► CRuntimeClass는 본질적으로 특정 클래스에 대한 정보를 담고있는 구조체이다. RTTI는컴파일러 레벨에서 제공되는 반면,CRuntimeClass 는 MFC에서제공된다.
또한 RTTI와달리 객체 생성 기능,객체 저장을 위한 직렬화 기능도 제공을 한다.
▪ 일반화된 객체 생성 :클래스 이름을 사용하지 않고 객체를 생성하는기능
▪ 메모리 상의 객체 자료형검사 : RTTI 와같은 기능
▪ 메모리 상의 객체 데이터유효성 검사 : 메모리상에서의 유효한 영역을 점유하고 있는지 검사
▪ 객체 직렬화 및 이를 위한정보 제공 : 객체를저장 매체에 일관된 방법으로 저장하는 기능
► CRuntimeClass구조체를 클래스의 정적 멤버 변수로 선언해야한다.일반 멤버변수는 객체가 생성되어야 사용을 할 수가 있다.객체가생성되지 않은 상태에서도 사용할 수 있어야 하므로정적 멤버로 선언한다.
MFC는CRuntimeClass 를 정적멤버로 쉽게 선언할 수 있도록 세 종류의 매크로를제공한다.
이하는 다음에...VNC.. ㅎㄷㄷ 훗훗..
# by | 2008/07/24 11:15 | Do Job | 트랙백 | 덧글(0)
► 종종 라이브 업데이트 일을하다 보면 분명 작업을 해서 배포를 했는데,거짓말과도 비슷한 버그 리포팅이 들어올때가 한두번이 아니다..
그래서 생각을 한게 레지나정보파일을 따로 둬서 버젼체크를 하는 방식이 아니고,(요즘 어지간한 유저들은 레지를 만져 버젼이나 기타 정보를 수정함으로서 업그레이드 서버를 안 거치고 그냥 인증으로 가는 경우가 많은듯 하다...;;;)클라이언트 파일 자체에 버젼 리소스를 할당함으로써 버젼체크를 하도록 구조를 변경하였다.
이제 거짓말장이 유저와 거짓말장이운영진과도 안녕이군..하하하.
이하는 아주 간단하게 WinEntry에서 버젼리소스의 값을 검사한 코드이다....
또한 안정성을 위해서 역시런쳐에서도 이와 비슷한 작업을 해 주었다.
///search directory
GetModuleFileName(0,szPath, _MAX_PATH);
DWORD dwSize = GetFileVersionInfoSize(szPath, 0);
LPVOID lpData = malloc(dwSize);
///Get fileversioninfo resource
GetFileVersionInfo(szPath,0, dwSize, lpData);
structLANGANDCODEPAGE
{
WORDwLanguage;
WORDwCodePage;
}*lpTranslate;
UINTcbTranslate = 0;
VerQueryValue(lpData,_T("\\VarFileInfo\\Translation"), (void**)&lpTranslate,&cbTranslate);
TCHARszKey[256];
_stprintf(szKey,_T("\\StringFileInfo\\%04x%04x\\FileVersion"),
lpTranslate->wLanguage,lpTranslate->wCodePage);
TCHAR*pszValue = 0;
UINTuLen;
VerQueryValue(lpData,szKey, (void**)&pszValue, &uLen);
//_putts(pszValue);
free(lpData);
함수의원형이다... 다른함수의 원형에 대해서도 궁금하시면...MSDN을 만나세요..^^
boolAPIENTRY VerQueryValue( const LPVOID pBlock, LPSTR lpSubBlock,LPVOID* lplpBuffer,
PUINTpuLen);
앗 하나더 중요한것이 ...#pragma comment (lib, "version.lib") 훗훗
# by | 2008/07/24 11:05 | Do Job | 트랙백 | 덧글(0)
[항목.5]컴파일러가 만드는 함수들을 주의하자.
► 컴파일러는 기본적으로 복사생성자, 복사 대입연산자를 선언하지 않고 외부에서 호출할 경우 자동으로public 선언을 한다.
► 참조자를 멤버로 갖고 있는클래스에 대입연산을 지원하려면 직접 복사 대입연산자를 정의해 주어야 한다.
ex)
classDev{
public:
string&m_strName;
}
Deva;
Devb;
a= b;
컴파일 에러 :C++참조자는 원래 자신이 참조하고 있는 것과 다른객체를 참조할수 없다.
► 상수 멤버에 대해서도 위와같은 동작을 한다.
[항목.6]컴파일러가만들어낸 함수가 필요 없으면 확실히 이들의 사용을막자.
► 컴파일러는 복사 생성자,복사 대입 연산자를 자동으로 public선언을할수 있다.
그러므로,해당 클래스에 대해서 복사관련 작업을 막고싶다면, 직접Private로 선언하자.
► 하지만 위와 같이 할경우 또하나의 문제는 멤버로써 호출을 하거나,friend 함수가 호출될수 있다....그래서선언만 하되 정의는 하지 않는 방법이 있다.
ex)
classDev{
private:
Dev(constDev&);
Dev&operator=(const Dev&);
}
► 더좋은 방법 :링크시의 에러를 컴파일시로 옮겨보자..에러를빨리 잡자..
ex)
classUnCopy{
procted:
UnCopy(){}
~UnCopy(){}
private:
UnCopy(constUnCopy&);
UnCopy&operator=(const UnCopy&);
}
classDev : private UnCopy{ ... }
► 위와 같이 기본 클래스를상속하여서 사용한다면......멤버로써호출이 안 된다.
# by | 2008/07/24 10:51 | Dairy Floating | 트랙백 | 덧글(0)
# by | 2008/07/08 11:53 | Dairy Floating | 트랙백 | 덧글(0)
◀ 이전 페이지다음 페이지 ▶