본문 바로가기
프로그래밍 이야기/C++ 기초

[Design Pattern] Bridge

by Mulder5 2021. 2. 2.
반응형

MP3로 생각하기

다음과 같이 가상의 IPod이 있고 People은 이를 Play/Stop 할 수 있다. 

#include <iostream>
using namespace std;

class IPod
{
public:
    void Play() { cout << "Play MP3" << endl; }
    void Stop() { cout << "Stop MP3" << endl; }
};


class People
{
public:

    // 이 경우 사용자는 IPod만 사용할 수 있다.
    void UseMP3(IPod* p)
    {
        p->Play();
    }

};

int main()
{
    
}

그런데 새로운 MP3기기가 나오면 다른 것은 사용할 수 없다. 이를 확장하기 위해서 아래와 같이 Interface - IMP3를 만든다. 

확장하기

#include <iostream>
using namespace std;


struct IMP3
{
    virtual void Play() = 0;
    virtual void Stop() = 0;
    virtual ~IMP3() {}
};

class IPod : public IMP3
{
public:
    void Play() { cout << "Play MP3" << endl; }
    void Stop() { cout << "Stop MP3" << endl; }
};


class People
{
public:

    void UseMP3(IMP3* p)
    {
        p->Play();
    }
};

int main()
{
    
}

이렇게 되면 사용자는 IMP3를 상속받은 그 어떤 기기도 사용할 수 있다. 

그런데 People에 대한 IMP3에 대한 요구사항이 계속 추가된다면 어떻게 대응을 하면 좋을까? 가령 "1분 미리 듣기" 기능을 구현한다고 생각해보자. 다음과 같이 IMP3에 이러한 추가 요구사항에 대한 기능(PlayOneMin)을 추가하면 좋을까?

struct IMP3
{
    virtual void PlayOneMin() = 0;
    virtual void Play() = 0;
    virtual void Stop() = 0;
    virtual ~IMP3() {}
};

class IPod : public IMP3
{
public:
    void PlayOneMin() {}
    void Play() { cout << "Play MP3" << endl; }
    void Stop() { cout << "Stop MP3" << endl; }
};

그렇지 않다. 이럴경우에 인터페이스 자체가 바뀌어 버리므로 상속받은 기기마다 모두 PlayOneMin()이 필요하므로 업데이트가 너무 힘들어진다. 이를 위해서 조금 더 쉬운 업데이트가 가능하도록 만들어보자.

객체지향에서 변화에 빠르게 대응하기 위해서는 중간에 새로운 계층을 집어넣는다. 이렇게 중간에 계층을 집어넣는 것을 Bridge Pattern이라고 한다.

Bridge Pattern

구현과 추상화 개념을 분리해서 각각을 독립적으로 변형할 수 있게 한다. 

 

적용하기

#include <iostream>
using namespace std;

struct IMP3
{
    virtual void Play() = 0;
    virtual void Stop() = 0;
    virtual ~IMP3() {}
};

class IPod :  public IMP3
{
public:
    void Play() { cout << "Play MP3" << endl;}
    void Stop() { cout << "Stop MP3" << endl;}
};

class MP3
{
    IMP3* pImpl;
public:
    MP3()
    {
        pImpl = new IPod;
    }
    void Play() { pImpl->Play();}
    void Stop() { pImpl->Stop();}
    void PlayOneMinute()
    {
        pImpl->Play();
        //Sleep(1);
        pImpl->Stop();
    }
};

class People
{
public:
    void UseMP3(MP3* p )
    {
        p->Play();
        p->PlayOneMinute();
    }
};

int main()
{

}

 

사용자의 요구조건을 MP3가 중간에서 완충작용을 해줄 수 있게 되었다. 즉 업데이트가 더 편리하게 되었다. MP3의 모든 구현은 IMP3 클래스에 있고, 사용자는 MP3만 알면 된다. 반대로 IMP3가 바뀌어도 사용자는 몰라도 된다.

즉, 구현과 추상화 개념을 독립적으로 변형할 수 있다.

 

 

 

반응형