Thursday, March 18, 2010

MVC 패턴 Architecter / SW Engineering


사실 MVC패턴과 MVP패턴은 디자인 패턴이 아닌 아키텍처 패턴이다. 디자인패턴이건 아키텍처 패턴이건
상관없이 가장 중요하다고 생각하는 패턴이며, 디자인 패턴을 공부하기 전에 먼저 공부해야 할 패턴들임이
분명하다.

시기상으로 MVC패턴이 먼저 나왔고 MVC패턴의 두번째 버전인 Model2까지(이미 오래전에) 나온상태이다.
하지만 뷰와 모델의 결합도를 완전히 없애지 못했고 뷰와 컨트롤러는 비교적 더 높은 결합도를 가지고 있기
때문에 진정한 의미에서의 뷰와 비지니스 로직의 분리는 어려웠다. 더구나 모호한 패턴의 개념에 따라 사람들
마다 개발하는 방식에 약간의 차이가 있었다.

이 상황에서 켄트백과 함께 객체지향이 세계에 엄청난 영향을 끼친(GoF와 함께 존경하는) 리팩토링의 히어로
마틴 파울러가 MVP 패턴을 내놓았다.


먼저 MVC패턴에 대해 살펴보자.
MVC는 Model View Controller의 약어로 역시나 3부분으로 구성되어 있다.
각각의 기능을 따져보기로 하자.
뷰는 사용자에게 보여지는 가장 상위 레이어이다. 데이터를 모델로부터 가져와서 사용자에게 보여준다.
컨트롤러는 이벤트의 처리를 담당하고 모델에게 메시지를 보내는 기능을 한다.
모델은 가장 핵심적인 부분으로, 데이터의 처리를 담당한다. 비지니스 로직이라고도 하며 프로젝트가
끝나도 재사용성이 높은 부분이다.

위의 설명만으로는 부족한것 같아서 MFC나 WPF에서 시리얼 통신을 하는 프로그램을 만든다고 가정해 보자.
일단 뷰는 시리얼 통신에서의 데이터를 보여주는 리스트컨트롤이나 버튼 콤보박스같은 인터페이스이다. MFC에서
다이얼로그 기반으로 만들었다면 뷰는 다이얼로그와 다이얼로그에 올려진 공용 컨트롤들이다. WPF라면 XAML로
만든 윈도우가 뷰의 역할을 담당한다.

버튼이나 콤보박스의 이벤트 핸들러가 컨트롤러에 해당하는데 MFC(MDI나 SID는 이미 MVC패턴이다.)에서는 보통
다이얼로그 안에 이벤트 핸들러를 등록하는데 OnPaint와 같은 뷰의 기능을 하는 클래스와 같다는 점에서 뷰와 컨트롤러
의 구분이 약간은 모호하다. WPF라면 XAML로 만든 윈도우마다 컨트롤러 기능을 하는 클래스가 붙어있다.

모델은 시리얼 포트에 접속하고 받은 데이터를 관리하는 클래스라고 할 수 있다.

각각의 관계는 컨트롤러가 뷰와 모델을 가지고 상호 작용하는 경우와, 뷰와 컨트롤러(같은 클래스)가 모델을 멤버로 가지는
경우가 있을 수 있다. 또한 컨트롤러와 뷰가 옵저버를 상속받아서 모델에서 옵저버의 레퍼런스를 통해서 뷰와 컨트롤러를
가지고 있는 경우도 있다. 해석하는 사람에 따라 MVC 패턴을 약간씩 다르게 이해하고 사용한다. 이부분이 MVC패턴이
모호해지는 부분이다. 하지만 비지니스 로직과 뷰의 분리를 이뤄낼 수 있다면 MVC패턴의 목적에 부합한다고 할 수 있다.
웹 언어에서 ASP.net이나 Struct도 MVC패턴을 사용하지만 확실히 모르는 관계로 언급하지 않아야겠다.

다음은 가장 중요한 흐름이다.
사용자가 버튼을 눌렀다고 가정 했을때 컨트롤러는 이를 모델에 알린다. 그러면 모델 내부에서 메시지에 따른 상태변화를
하고 상황에 따라 데이터가 변하기도 한다. 그다음 컨트롤러가 뷰에 통지를 하면(모델이 통지를 해 줄수도 있다.) 뷰는
모델에게 데이터를 요청해서 사용자에게 보여준다.
개인적으로는 모델에서 뷰에게 통지하는 방법을 많이 사용하는데, 모델이 뷰들을 옵저버로 가질 수도 있다. MFC에서는
옵저버를 사용하지 않고 뷰(윈도우면 모두 HWND를 가지고 있다.)의 핸들을 얻어서 SendMessage()를 통해 업데이트
하는 방법을 선호한다. 모델에서 뷰를 가질때 옵저버를 상속받거나, 모델에 SendOwnerHwnd(HWND hOwner)메소드를
만들어서 사용하면 뷰와 모델의 결합도를 굉장히(중요!!) 낮출 수 있다. 뷰가 윈도우의 종류가 아니라면 옵저버를 상속받게
해서 update()를 구현해서 사용하면 좋다. SendMessage()나 PostMessage()를 이용하면 비동기 적으로 업데이트를 처리할
수 있다.
다시 시리얼 통신을 예로 들어, 시리얼 포트를 감지하는 스레드에서 데이터를 읽었다고 가정해보자.

스레드에서 이벤트가 발생한것을 뷰에 알리고 뷰에서는 이 데이터를 요청한다. 액티브와 패시브 방법 모두 적절하게 사용
하기를 바란다. 그것보다 왜 StarUML에는 시퀀스에서 화살표가 두개밖에 없는지....
윈도우에 비지니스 로직을 전부 때려박아서 나중에 프로젝트가 바뀌면 재사용도 못하는 소스를 만들어 내지는 말자. 이런
상황에서 MVC나 MVP패턴이 아주 유용하게 사용될 것이다.
MVP패턴은 시간 날때 다시 포스팅 해야 겠다.