티스토리 뷰


1. 퍼사드 패턴이란?

클래스 라이브러리 같은 어떤 소프트웨어의 다른 커다란 코드 부분에 대한 간략화된 인터페이스를 제공하는 객체. (출처 : 위키백과)


일련의 사용 방법이 복잡한 클래스들을 묶어 단순화된 인터페이스를 구현해서 사용하기 쉽게 만들 수 있는 패턴입니다.

실제로 구현을 해 놓은 것을 보면 확인할 수 있겠지만, 매우 단순한 패턴입니다. 하지만, 이 퍼사드 패턴의 특징으로 인해 서브시스템의 연결성이 줄어들 수 있고, 최소지식원칙을 지키는데 큰 도움이 됩니다.

그림으로 보면 매우 쉽게 퍼사드 패턴에 대해 이해할 수 있습니다.

복잡한 서브시스템 클래스를 퍼사드 클래스가 묶어 가지고 있어 클라이언트 쪽에서는 서브시스템들의 복잡한 동작을 생각할 필요 없이 퍼사드 클래스에 명령만 하면 원하는 동작을 실행시킬 수 있는 패턴입니다.




2. 구현

예제에는 수많은 클래스가 있지만, 간단한 구현을 위해서 클래스 수를 세개로 줄였습니다.

집에 전자동 홈시어터가 있습니다. 이 전자동 홈씨어터에 씨디플레이어, 프로젝터, 스크린이 연결되어 있습니다.

수동으로 각 객체에 접근해서 각각 켜고, 끌 수 있는 기능을 가지고 있습니다. 하지만, 사실상 영화를 보는 것이 주 목적이기 때문에 영화를 볼 때 필요한 동작들을 한 데 모아 퍼사드 클래스에서 구현해 보았습니다.


<CCDPlayer.h>

1
2
3
4
5
6
7
class CCDPlayer {
public:
    CCDPlayer();
    ~CCDPlayer();
    void On() { printf("CDPlayer On\n"); }
    void Off() { printf("CDPlayer Off\n"); }
};
cs

<CProjector.h>

1
2
3
4
5
6
7
8
class CProjector {
public:
    CProjector();
    ~CProjector();
    
    void On() { printf("Projector On\n"); }
    void Off() { printf("Projector Off\n"); }
};
cs

<CScreen.h>

1
2
3
4
5
6
7
8
class CScreen {
public:
    CScreen();
    ~CScreen();
    
    void On() { printf("Screen is going down.\n"); }
    void Off() { printf("Screen is going Up\n"); }
};
cs


홈시어터에 연결된 세 서브시스템입니다.

각각 On, Off시 각자의 기능을 실행하고, 종료할 수 있습니다.

이를 하나하나 조작해도 되지만, 사실 영화를 본다면, 이 세 기능을 단 한번의 호출로 모두 켤 수 있다면, 훨씬 편할 것입니다.

이를 위해 퍼사드 클래스를 구현합니다.


<CFacade.h>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CFacade {
public:
    CFacade(CCDPlayer *cdPlayer, CProjector *projector, CScreen *screen) :
    mCDPlayer(cdPlayer),
    mProjector(projector),
    mScreen(screen) {};
 
    void PlayMovie();
    void StopMovie();
 
private:
    CCDPlayer *mCDPlayer;
    CProjector *mProjector;
    CScreen *mScreen;
};
cs


퍼사드는 세 서브시스템의 객체를 가지고 있고, PlayMovie, StopMovie 두 가지의 기능을 통해 영화를 켜고 끌 수 있습니다.


<CFacade.cpp>

1
2
3
4
5
6
7
8
9
10
11
12
13
void CFacade::PlayMovie()
{
    mCDPlayer->On();
    mProjector->On();
    mScreen->On();
}
 
void CFacade::StopMovie()
{
    mScreen->Off();
    mProjector->Off();
    mCDPlayer->Off();
}
cs

영화를 틀려면 모든 기능을 On을 해야하고, 영화를 끄려면 모든 기능을 꺼야겠죠?


구현이 끝났습니다.

이를 메인에서 실행시켜본다면,


<main.cpp>

1
2
3
4
5
6
7
8
9
10
int main() {
    CCDPlayer *cdPlayer = new CCDPlayer();
    CProjector *projector = new CProjector();
    CScreen *screen = new CScreen();
 
    CFacade *facade = new CFacade(cdPlayer, projector, screen);
 
    facade->PlayMovie();
    facade->StopMovie();
}
cs


<실행 화면>


이렇게 PlayMovie() ,StopMovie()  로 세 객체의 모든 기능을 동작시켜 서브시스템의 동작을 단순화시킬 수 있는 것이 퍼사드 패턴의 큰 장점입니다.




3. 최소 지식 원칙

최소 지식 원칙 : 객체 사이의 상호작용은 아주 가까운 '친구' 사이에만 허용하는 것이 좋다. (출처 : 헤드퍼스트 디자인패턴)


시스템을 디자인 할 때 어떤 객체든 그 객체와 상호작용을 하는 클래스의 개수에 주의해서 디자인을 해야 합니다.

이 원칙을 잘 따르지 못했을 경우, 여러 클래스가 복잡하게 얽혀서 잘 디자인 했다면 고치지 않아도 될 코드까지 줄줄이 고쳐야 하는 상황이 생길 수 있습니다. 관리도 어렵고, 남들이 이해하기도 여러운 불안정한 시스템이 될 수 있습니다.


1) 영향을 미쳐야 하는 객체

 ① 객체 자체

 ② 메소드에 매개변수로 전달된 객체

 ③ ②에서 생성하거나 인스턴스를 만든 객체

 ④ ③의 객체에 속하는 구성요소


어떤 메소드를 호출한 결과로 리턴받는 객체에 있는 메소드를 호출하는 것도 위의 원칙과 어긋나는 행위입니다. 

결국 다른 객체의 일부에 대해 요청을 하는 것이고, 그럴 경우 알게 되는 객체가 늘어나게 되는 셈입니다.

이 때 친구를 줄이는 좋은 방법은, 그 객체가 우리가 원하는 값을 리턴할 수 있도록 해야 합니다.

<CHomeTheater.h>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class CHomeTheater
{
public:
    CCDPlayer *mCDPlayer;
    bool bConnected;
    
    void PlayMovie(CProjector *projector)
    {
        // 구성요소의 함수호출 가능
        mCDPlayer->On();
 
        // 객체 내 메소드 호출 가능
        SetConnected();
        
        // 함수 내에서 선언한 객체에 대한 함수호출 가능
        CScreen *screen = new CScreen();
        screen->On();
        
        // 매개변수로 전달된 객체의 메소드는 호출해도 됨
        projector->On();
        
    }
    
    void SetConnected() { bConnected = true; }
};
cs


홈씨어터에서 제시하는 네 가지 경우가 최소 지식원칙에 위배되지 않는 함수 호출입니다.


2) 퍼사드 패턴과 최소지식원칙과의 관계

퍼사드 패턴을 구현하게 되면 클라이언트 입장에서는 퍼사드 클래스만 관계 형성이 되어 있어 새로운 서브시스템이 추가 되어도 클라이언트에는 영향이 가지 않습니다. 즉 클라이언트 객체를 통해 굳이 필요없는 객체에 접근하지 않기 때문에 퍼사드 패턴을 통해 최소지식원칙을 지킬 수 있습니다.


최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함