[출처] http://www.imaso.co.kr/?doc=bbs/gnuboard.php&bo_table=article&wr_id=35826

 

MVC 역사

 

MVC 자체는 오랜 역사를 가지고 있다. Triage Reenskaug가 제록스 팔로 알토(Xerox Palo Alto)리서치 센터에서

스몰토크(Smalltalk)와 관련된 그룹에 참여하는 동안 고안한 것이 MVC 패턴이다. 1978년 MVC와 관련된 첫 번째 문서가 완성됐는데,

MVC 패턴을 ‘Thing Model View Editor’패턴으로 불렀다. 하지만 오래지 않아 이름을 ‘Model View Controller’로 바꿔 부르게 됐다.

창안한 사람이 스몰토크와 관련된 일을 하고 있어선지 MVC 패턴은 가장 먼저 스몰토크-80의 클래스 라이브러리의 일환으로

활용됐으며 그래픽 유저 인터페이스(GUI)를 만들기 위한 설계패턴으로도 이용됐다.

 

하지만 MVC가 가장 적극적으로 사용되기 시작한 것은 웹 애플리케이션들이 활성화 되는 시점이었다.

웹이라는 환경 자체가 짧은 시간에 많은 변화를 이끌어냈고 이를 위한 기술과 함께 문제점도 함께 도출됐다.

웹 분야에서는 짧은 시간에 많은 기능들을 구현하는 것이 비즈니스 경쟁력과 직결됐지만

체계적인 문제해결에 대한 필요성이 요구되면서 이때부터 MVC가 적극적으로 도입하기 시작한 것이다.

MVC 패턴은 Ruby on Rails, Merb, .NET, Java, PHP 등 다양한 언어로 구현돼 그 유용성을 입증하고 있다.

 

 

MVC 패턴이란?

MVC는 모델(Model), 뷰(View), 컨트롤러(Controller)로 나누어지는 구조로 소프트웨어를 설계하는 패턴이다.

 

 

                    <그림 1> MVC 패턴의 구성요소

 

  1) Model  

      모델은 애플리케이션의 유효성 검증이나 비즈니스로직 그리고 데이터에 대한 모든 설계사항을 포함하고 있다.

 

  2) View 

     MVC에서의 뷰를 쉽게 설명하면 사용자 인터페이스라고 이해해도 좋다. (웹 프로그래밍의 경우 뷰를 통해서 HTML이 생성된다.)

  3) Controller

     뷰와 모델 사이에서 데이터나 로직의 흐름을 제어하는 역할을 한다.

 

MVC 패턴에서 구성요소인 모델, 뷰, 컨트롤러는 서로 연관돼 작업을 수행하지만, 각각의 역할구분은 명확히 나눠져 있으며

서로의 역할에 대해서 독립성도 확실하게 보장한다. 다시 말해, 잘 설계된 모델 안에는 필요한 기능들이 대부분 구현돼 있고

이를 잘 보여주기 위해 뷰를 설계하며 모델과 뷰를 통제하기 위해서 컨트롤러가 설계된다.

MVC 패턴으로 잘 설계된 애플리케이션은 어떠한 핵심 로직도 건드리지 않고 해당 애플리케이션을 재설계 할 수 있는 장점이 있다.

또 잘 정의된 요구사항이 있다면 모델, 뷰, 컨트롤러를 각기 다른 사람이 한 번에 개발할 수 있다. 

예를 들어 어떤 애플리케이션을 HTML기반의 웹 애플리케이션으로 개발하고 있다가

갑자기 Silverlight를 이용한 RIA기반으로 요구사항이 바뀌어 전환해야 할 경우,

일반적인 방법으로 설계했다면 엄청난 코드의 수정이 요구된다.

 

하지만 MVC 패턴으로 작성된 코드라면 뷰 부분만 Silverlight에 맞추어서 재작성하면 된다.

 

이와 같이 MVC는 외부의 변화에 대해서 비교적 유연하게 반응할 수 있기 때문에 가장 널리 사용되는 패턴 중에 하나가 됐다.

물론 MVC 모델이 유연하기 때문에 각광 받고 있지만 단순히 유연함이 모든 장점은 아니다.

소프트웨어가 복잡해지면 복잡해질수록 소프트웨어 품질에 대한 관리가 필요하다.

일반적으로 제품을 제조하는 공장의 경우도 완성된 제품을 테스트해서 불량 여부를 가려내듯

소프트웨어에서 품질관리를 위한 가장 기본은 바로 테스트라고 할 수 있다.

 

특히 소프트웨어 개발에서 TDD(Test Driven Development)란 이름으로 테스트의 중요성이 더욱 부각되고 있는 시점에서

MVC처럼 명확한 구조는 테스트를 좀 더 쉽게 할 수 있으며, 테스트 과정을 통해 좀 더 쉽게 오류를 찾을 수 있게 해준다.

블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,

패턴이란 특정 컨텍스트(패턴이 적용되는 상황. 반복적으로 일어날 수 있는 상황) 내에서 주어진 문제

(해당 컨텍스트 내에서 이루고자 하는 목적 또는 제약조건)에 대한

해결책(일련의 제약조건 내에서 목적을 달성할 수 있는 일반적인 디자인)이다.

"어떤 컨텍스트 내에서 일련의 제약조건에 의해 영향을 받을 수 있는 문제에 봉착했다면,

그 제약조건 내에서 목적을 달성하기 위한 해결책을 찾아낼 수 있는 디자인을 적용한다."

1. 범주별 분류

 생성 관련 패턴 (싱글턴, 추상 팩토리, 팩토리 메소드, 빌더, 프로토타입)
    객체 인스턴스 생성을 위한 패턴으로, 클라이언트와 그 클라이언트에서 생성해야 할 객체 인스턴스 사이의 연결을 끊어주는 패턴.

 행동 관련 패턴 (템플릿 메소드, 커맨드, 어터레이터, 옵저버, 스테이트, 스트래티지)
   클래스와 객체들의 상호작용 하는 방법 및 역할을 분담하는 방법관 관련된 패턴.

 구조 관련 패턴 (데코레이터, 컴포지트, 프록시, 퍼사드, 어댑터)
   클래스 및 객체들을 구성을 통새허 더 큰 구조로 만들수 있게 해주는 것과 관련된 패턴.

2. 클래스, 객체 분류

■  클래스 패턴 (템플릿 메소드, 팩토리 메소드, 어댑터)
    클래스 사이의 관계가 상속을 통해서 어떤 식으로 정의되는지를 다룬다. 클래스 패턴에서는 컴파일시에 관계가 결정.

■  객체 패턴 (Composite, Decorator, Proxy, Strategy, Bridge, Facade, Command, iterator, Observer, Prototype, State,

                     Factory, Singleton)

    객체 사이의 관계를 다루며, 객체 사이의 관계는 보통 구성을 통새허 정의. 객체 패턴에서는 일반적으로 실행중에 관계가 생성되기

    때문에 더 동적이고 유연함.

3. 패턴으로 생각하기

■  최대한 단순하게
    "이 문제에 어떤 패턴을 적용할까?"가 아닌 "어떻게 하면 단순하게 해결할 수 있을까?"에 초점.
     가장 단순하고 유연한 디자인을 만들기 위해서 패턴을 사용해야 한다면 그때 패턴을 적용하면 된다.

■  디자인 패턴은 만병 통치약이 아니다
    패턴을 사용할 때는 그 패턴을 사용했을 때 설계한 디자인의 다른 부분에 미칠수 있는 영향과 결과에 대해 주의 깊게 생각해 봐야 한다.

■  패턴이 필요한 경우
    구상중인 디자인상에 적용이 적합하다 확신이 들 경우.
    시스템의 어떤 부분이 변경될 것이라고 예측할 수 있는 경우.

■  리팩터링과 패턴
    행동이 아닌 구조를 개선하는데 목적.

■  패턴 제거
    시스템이 점점 복잡해지면서 처음에 기대했던 유연성이 전혀 발휘되지 않게 되는 경우 패턴을 과감하게 제거해 버리는게

    최선책일 수 있다. 즉, 패턴을 사용하지 않은 간단한 해결책이 더 나을 것 같다 싶을 때 패턴을 제거하면 된다.

 필요한 경우에만 적용하라
   지금 당장 변화에 대처하기 위한 디자인을 만들어야 한다면 패턴을 적용해서 그 변화에 적응해야 한다.

   하지만 꼭 필요하지 않음에도 불구하고 괜히 패턴을 추가하는 것은 피해야 한다.

   괜히 시스템만 복잡해지고 사용률도 현저히 낮거나 없을 수 있다.

4. 패턴을 대하는 마음가짐

   초보자들은 언제나 패턴을 사용하는 경향이 있다. 그 과정에서 패턴을 쓰는 연습을 하면서 다양한 경험을 쌓을 수 있는 측면에서는

    좋다. 하지만 그러다 보면 반드시 그렇지만은 않다는 것을 배우게 된다. 어떤 디자인이든 될 수 있으면 단순하게 만들어야 한다는 것을

    터득하게 된다. 반드시 확장성이 필요한 경우에만 패턴을 써서 조금 복잡하게 만드는 것이 좋다.

    경험이 늘어 중급자 수준에 오르게 되면 어떤 상황에서 패턴이 필요하고 어떤 상황에서 패턴이 필요하지 않은지를 파악할 수 있다.

    여전히 잘 맞지 않는 패턴을 억지로 적용하려는 경향이 보이긴 하지만, 그 과정에서 정형적인 패턴이 적합하지 않은 상황에서는 패턴을

    적당히 변형시켜서 써야 한다는 것을 깨닫게 된다.

   달인의 경지에 오르면 패턴을 자연스럽게 구사할 수 있다. 더 이상 패턴을 사용하는 것에 얽매이지 않는다. 문제를 가장 효과적으로

    해결할 수 있는 해결책을 찾는데 주안점을 둘 뿐이다. 이는 객체지향 원칙들을 종합적으로 고려함이다. 자연스럽게 패턴이 필요한

    상황에 이르면 패턴을 적당히 변형시켜서 적용한다. 그리고 달인들은 유사한 패턴 사이의 관계를 확실히 파악하여 관련된 패턴들의

    용도 사이의 미묘한 차이점을 잘 이해하고 활용한다. 달인의 마음가짐은 초보자의 마음자짐이기도 하다. 디자인 과정에서 의사 결정을

    할 때 패턴에 대한 지식이 그리 큰 영향을 끼치지 않기 때문이다.

5. 주요 패턴 정리

블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,

서울특별시 종로 5가 왕복 8차선 도로에 교통사고가 발생했다는 신고가 관계기관에 접수되었다고 가정하자.

그럼 신고를 받은 관계기관은 신속히 해당 사고지점으로 출동할 것이다.

아마도, 사고 유형이 '교통사고' 이기 때문에, 병원, 소방서, 경찰 등의 관계기관이 출동할 것이다.

 

그리고 옵저버 패턴에 대해서 잘 모르는 상태에서, 이를 구현해 보면 아마 아래와 비슷할 것이다.

void 119()
{
    while ( NULL != (신고유형 = 사고접수()) )
    { 
        switch ( 신고유형 )
        {
        case 교통사고:
            Notify(경찰);
            Notify(소방서);
            Notify(병원);
            break;
        case 응급상황:
            Notify(병원);
            break;
        case 간첩신고:
            Notify(경찰);
            break;
        default:
            break;
        }
    }
}

지금도 깔끔해 보이지만, 옵저버 패턴을 사용하게 될 경우 더 깔끔해진다.

그리고 아래는 위에서 언급한 예제를 옵저버 패턴을 사용하여 구현한 예제 이다.

void 119()
{
    교통사고.registerObserver(경찰, 소방서, 병원);
    화재신고.registerObserver(소방서, 병원);
    간첩신고.registerObserver(경찰);
    응급신고.registerObserver(병원);

    while ( NULL != (신고유형 = 사고접수() )
    {
        Observers *observers = GetObservers(신고유형);
        foreach ( o in observers )
            o->Notify();
    }
}

즉, 옵저버 패턴은 한 객체의 상태가 바뀌면(혹은 관심 주제가 변경되면) 

그 객체에 의존하는 다른 객체들한테 연락이 가게됨으로서

자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의존성을 정의할 때

종종 사용되어지는 패턴이다. 

 

 

끝으로, 위에서 언급한 옵저버 패턴 예제에서 각각의 클래스들을 좀 더 구체화 시키면 아래와 같다.

 

class 소방서 : public CObserver {}

class 경찰 : public CObserver {}

class 병원 : public CObserver {}

 

class 교통사고 : public Subject {  private: std::vector<CObserver *> m_vObservers; }

class 화재신고 : public Subject {  private: std::vector<CObserver *> m_vObservers; }

 

여기서 주의깊게 살펴봐야 할 사항은 서로 다른 객체사이에 통신을 하기 위해서

Observer 라는 클래스를 사용하고 있다는 점이다. (느슨한 연결 + 역활분리)

 

[생각할 꺼리]

 

1. 옵저버 패턴에서 서로 다른 클래스 사이에서 통신을 위해서 사용하는 CObserver 클래스를

   사용하는 이유는 무엇일까?

블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,