Programming Languange/디자인 패턴

디자인 패턴 (Design Patterns) - 어댑터 패턴

타자치는 문돌이

어댑터 패턴(Adapter Pattern)은 호환되지 않는 인터페이스를 가진 객체들이 협업할 수 있도록 도와준다.

A 프로그램은 파일을 hwp 파일로 제공한다. 그러나 B 프로그램은 hwp 파일이 아닌 docx 파일만 열 수 있다. 이런 경우, hwp 파일을 docx로 변환하는 어댑터를 구현하고, B 프로그램이 어댑터가 변환한 파일을 사용하도록 할 수 있다.

구현

어댑터 패턴은

  • Client
  • Client Interface
  • Service
  • Adapter
    로 구성된다.

Client는 기존의 프로그램이다.
Client Interface는 다른 클래스들이 Client와 작업하도록 따라야 하는 프로토콜이다.
Service는 Client가 사용하고 싶은데, 호환되지 않아 사용하지 못하는 클래스이다.
Adapter는 Service 객체를 래핑해, Client의 호출을 받아 Service가 이해할 수 있도록 변환한다.

Client Interface

// Client interface
class Animal
{
public:
    virtual void makeSound() const = 0;
    virtual ~Animal() {}
};

Animal Interface를 상속받는 동물 클래스들은 makeSound를 통해 소리를 낸다.

Service

// Service class
class Dog
{
public:
    void bark() const
    {
    std::cout << "Wild dog is barking" << std::endl;
    }
};

외부에서 가져온 새 Service인 Dog 클래스는 makeSound 함수가 아닌 bark 함수를 사용한다.

Adapter Class

// Adapter class
class DogAdapter : public Animal
{
private:
    Dog *dog;
public:
    DogAdapter(Dog *dog) : Dog(dog) {}
    void makeSound() const override
    {
    Dog->bark();
    }
};

DogAdaptermakeSound를 쓰면 bark를 호출해 Service인 Dog를 수정하지 않아도 문제없이 사용하도록 한다.

Client (예시)

// Client code
int main()
{
    Dog* dog = new Dog();

    Animal* dogAdapter = new DogAdapter(dog);

    dogAdapter->makeSound();

    ...    
    return 0;
}

장점

  • 단일 책임 원칙을 구현한다. Client의 로직과 변환을 분리한다.
  • 개방/폐쇄 원칙을 구현한다. 기존의 Client 코드 수정 없이 새 Service를 추가할 수 있다.

단점

  • 코드가 복잡해진다. 때로는 Service Class를 변형하는 것이 더 간단할 수 있다.

 

디자인 패턴 (Design Patterns) - Index