Policy class example 입니다.
#include <iostream> using namespace std; template<class T> struct OpCreateNew { public: T* create() { cout << "Calling new" << endl; return new T; } protected: ~OpCreateNew() { } }; template<class T> struct OpCreateMalloc { public: T* create() { cout << "Calling malloc" << endl; T* result = static_cast<T*>(std::malloc(sizeof(T))); return result; } protected: ~OpCreateMalloc() { } }; template < class T, template<class> class Creator > class Foo:public Creator<T> { public: Foo():storage_(this->create()) { } protected: T* storage_; }; int main() { Foo<int, OpCreateNew> f1; Foo<int, OpCreateMalloc> f2; return 0; }
코드에서 언급할 부분은 3가지입니다.
- protected 로 선언된 destructor는 f1 이나 f2를 Creator<T> 로 받아서 delete 하는 것을 막기 위해서 사용되었습니다.
- storage_(this->create()) 와 같은 this의 사용은 C++에서 기본적으로 템플릿 부모 클래스의 메소드 호출은 그런 메소드가 존재하지 않는다고 가정하기 때문에 필요합니다.
- template<class> class Creator과 같은 표현은 Creator가 템플릿임을 표시하기 위한 template template parameter입니다. (템플릿으로 정의된 템플릿 파라미터라는 말입니다.)
Modern C++ Design 1장의 내용을 그냥 코딩해 봤습니다. Policy Class라는 것은 말하자면 C++의 템플릿을 사용해서 GoF의 strategy 패턴을 구현한 것처럼 보입니다. 하지만 제 생각에 Strategy 패턴과는 다음과 같은 내용이 다릅니다.
- Strategy 패턴은 전략을 적용함에 있어서 인터페이스와 virtual method 호출에 의존하지만, Policy class 방식은 템플릿을 사용한 코드 생성에 의존합니다.
- Strategy 패턴은 후에 코드를 수정할 필요가 있을 때, 클래스 생성 부분에 인자로 주어지는 클래스명을 수정해야하지만, Policy class 방식은 템플릿 인자를 수정해야합니다.
- Strategy 패턴의 타입 안정성에 대한 검사는 동적이지만, Policy class 방식은 정적이며 컴파일시에 완료됩니다.
- Strategy 패턴에서는 정의된 메소드가 모두 상속되며 컴파일과 실행시에 항상 존재하지만, Policy class는 템플릿에 의존하므로 인해 Policy 가 정의하고 있는 메소드 들은 사용될 때에만 instantiation 이 완료됩니다.
Leave a Reply