아주 간단한 GUI 예제 프로그램을 만든다고 생각해보자. 기본 윈도우 위에 버튼이 하나 배치되어 있고,
버튼을 누르면 "Hello" 라는 팝업 윈도우를 띄워주는 프로그램이다

버튼 하나와 윈도우 하나가 들어가는 아주 간단한 예제이지만, 이 프로그램을 만드는데는 여러가지
방법이 있다. 가상코드를 통해서 살펴보자

1. 버튼을 상속해서 만들기

class MyButton : Button {
    OnClick() { MsgBox("Hello"); }
}

Window w = new Window();
MyButton b = new MyButton();
w.AddChild(b);
w.Show();

버튼이 눌렸을 때 해야 할 일을 지정하기 위해, 버튼을 상속해서 마이버튼을 만들어서 해결하는 경우다.
버튼이 생길때마다 상속된 클래스가 하나씩 추가되어야 하기 때문에 이런식으로 하는 경우는 거의 없다.


2. 윈도우를 상속해서 만들기

class MyWindow : Window {
    OnButton1Clicked() { MsgBox("Hello"); }
}

MyWindow w = new MyWindow();
Button b = new Button();
connect(w.OnButton1Clicked(), b.onclick());
w.AddChild(b);
w.Show();

버튼은 일반적인 버튼을 사용하되, 버튼이 눌릴 때 onclick 이라는 시그널 (혹은 이벤트, 메시지) 가 발생
되도록 하고, 윈도우를 상속해서 만든 마이윈도우가 그 시그널을 받는 슬롯 (혹은 핸들러) 을 정의해서
처리하는 방식이다

위의 식으로 런타임에서 connect 를 하는 경우는 Qt 같은 프레임워크가 사용하는 방식이고 MFC 는
메시지 맵을 매크로를 이용해서 컴파일타임에 연결하는 방식이다.

버튼이 하는 일을 윈도우에게 메시지를 보내서 처리해야 하는 방식이니 중간 단계를 하나 걸치게 되고
매번 윈도우를 상속받아서 만들어야 하니 윈도우의 갯수만큼 서브클래스가 늘어나는 것이 단점이고
MFC 의 경우처럼 메시지맵을 매크로를 이용해 처리하려면 type safety 에도 문제가 생기고, 동적으로
변경하는 것도 어렵고, 위자드가 만들어준 코드에 의존하게 되는 등 단점이 아주 많다.
Qt 의 경우는 조금 낫지만, 일반적인 c++ 문법을 사용해서 signal/slot 을 구현한게 아니고 외부 전처리기
인 MOC (Meta Object Compiler) 를 의존하게 된다


3. 델리게이트의 이용

Window w = new Window();
Button b = new Button();
b.onclick = func { MsgBox("Hello"); }    // func 는 익명함수, 람다함수, 델리게이트 의 개념
w.AddChild(b);
w.Show();

버튼과 윈도우 둘 다 상속을 할 필요도 없고, 서로간에 메시지를 보낼 필요도 없다. 가장 이상적인 방식
이라고 생각할 수 있는데, 단점은 C++ 이 위와 같은 문법을 지원하지 않는다는 점이다.


그동안 많은 C++/MFC 개발자들은 간단한 일을 어렵게 하면서 낮은 생산성을 감수하고 살아왔다.
특히 상속이라는 개념을 당연히 써야 하는 것으로 받아들임으로써, 재사용성의 저하, 불필요한 코드의
증가등 유지보수의 어려움을 겪게 되었다.


상속이라는 개념 자체는 나쁜 것이 아니다. 다만 상속 개념을 남용한 것이 문제이다.

Button 이나 Window 는 라이브러리의 일부분이고, 라이브러리를 '확장' 할 때는 상속을 쓰는 것이
타당한 방법이지만 (예를 들면 BitmapButton 같은 또 다른 재사용 가능한 컴포넌트), 라이브러리
를 그저 '사용' 할 때는 상속을 쓰는 것보다는 3번과 같은 방법이 가장 이상적이라고 할 수 있다.

그렇다면 C++ GUI 개발자들은 C# 이나 다른 언어로 갈아타야만 하는 것인가? 한가지 대안은
스크립트 언어를 사용하는 것이다

Window *w = new Window();
Button *b = new Button();
b->SetHandler("onclick", "MsgBox 'Hello'" }    // MsgBox 'Hello' 는 루아 코드
w->AddChild(b);
w->Show();

Window 나 Button 이 적절하게 구성되어 있다면, 위의 라이브러리를 '사용' 하는 사람의 입장에서는
전혀 서브클래스 (마이버튼이나 마이윈도우) 를 만들 필요도, 메시지를 정의할 필요도 없다.


다시 정리
올바르게 설계된 프레임워크는 라이브러리를 '사용' 할때 서브클래싱을 필수로 요구하지 않는다
서브클래싱은 라이브러리를 '확장' 할 때에 유용한 개념이다

마찬가지로 재사용 가능한 OOP 컴포넌트로 Character 라던가 Actor 같은 클래스를 만들었다면
서브클래싱 (상속)을 남용하고 있는 것이 아닌가 한번 자신이 만든 C++ 코드를 살펴보기 바란다.

코드의 상당부분을 서브클래싱한 응용 프로그램 코드가 차지하고 있다면, 루아 같은 스크립트
언어를 이용해서 재사용해야 하는 라이브러리 코드와 재사용 할 필요가 없는 스크립트 코드를
분리하는 것을 추구해보라

imcgames 의 김학규입니다