설명
구현부와 인터페이스를 분리 시키는 기법.
구현부는 따로 클래스로 빠지기 때문에 런타임에 구현을 변경할 수 있음.
또한 인터페이스를 사용하는 프로젝트는 놔두고 구현부만 다시 컴파일하거나 교체하면 되기 때문에 더욱 유연해짐.
이때 구현부와 인터페이스가 1대1 인 경우는 후자의 장점만 살리는 경우임.
예제 코드
1 2 3 4 5 6 7 8 9 10 | // 구현부 class WindowImp { public: virtual void ImpSetExtent(const Point&) = 0; virtual void ImpSetOrigin(const Point&) = 0; protected: WindowImp() = default; }; | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // 인터페이스 class Window { public: Window(View* contents); virtual void DrawContents(); //인터페이스 virtual void Open(); virtual void Close(); //구현클래스에 위임할 메소드 virtual void SetOrigin(const Point& at); virtual void SetExtent(const Point& extent); protected: WindowImp* GetWindowImp(); View* GetView(); private: WindowImp* _imp; View* _contents; }; | cs |
1 2 3 4 5 6 | // class XWindowImp : public WindowImp { public: XWindowImp() = default; }; | cs |
보통 구현부는 Imp 를 인터페이스 이름 뒤에 붙여서 명명함.
이러한 Imp 는 구현부의 멤버로서 들어가게 됨.
WindowImp 를 객체가 인터페이스에서 사용할 수도 있고 안할 수도 있음.
사용하는 경우 컴파일을 따로 할 수는 없게됨.
Imp 파일은 위처럼 확장되어도 인터페이스와 호환이 잘됨.
이러한 확장된 Imp 파일을 pool 이나 manager 를 구현해서 여러개의 imp 를 인터페이스가 동작중에 변경 할 수 있게 하는 것도 좋음.
추가 설명
Abstract Factory 패턴을 사용해서 위에서 만드는 구현부들을 생성, 수정하는 것이 시너지가 높음.
Adapter 랑 비슷한데 사용하는 목적이 다름. 전자는 이미 주어진 클래스와의 호환성을 위한 거고, 이건 구현부와 인터페이스를 떼놔서 얻는 유연성을 위한 거임.
댓글 없음:
댓글 쓰기