Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

Adapter pattern

인터페이스가 일치하지 않는 클래스를 함께 운용해야 하는 경우에 사용할 수 있다. 비교적 간단한 패턴(:12)으로 각각의 class(:12)를 수정하지 않고 함께 운용할 수 있도록 해준다. 이 패턴에는 다음의 객체들이 존재한다.
  • Adaptee : 원하는 기능을 가지고 있는 객체
  • Client : Adaptee의 기능을 사용할려는 사용자 객체
  • Adapter : Client의 인터페이스를 가지고 Adaptee의 원하는 기능을 구현한 객체
Adapter pattern은 Object PatternClass pattern 두가지 방법으로 구현가능하다.

Object Pattern 버전

 pattern

Client는 Adaptee의 methodB를 사용하고 싶다. 그런데, Client와 Adapter모두 구현이 끝난 상태 - 혹은 라이브러리만 가지고 있거나 -로 클래스를 수정할 수 없다. 대신 중간에 Client와 호환되는 인터페이스를 가진 Adapter를 둔다. 이 호환되는 메서드를 client가 호출하면, Adapter는 Adaptee의 methodB를 호출하게 된다. 이렇게 해서 기존 클래스의 수정없이 Client에서 Adaptee의 기능을 이용할 수 있게 된다.

집합관계를 이용한 새로운 객체를 두는 방식으로, Object Pattern 이라고 한다.
  Client     Adapter      Adaptee 
 +-----+     +------+     +-----+
 |     |---> >      |---) )     |
 |     |---> >      |---) )     |
 +-----+     +------+     +-----+
 Adapter는 Client와 Adaptee에 호환되는 Interface(:12)를 모두 가지고 -집합- 있다.

디자인 패턴을 생성하는 방법중 객체 합성을 이용한 예라고 보면 될것 같다. 다른 한가지 방법은 클래스 합성인데, 아래에 설명한다.

Class Pattern 버전

C++의 다중상속을 이용하는 방법이다. 여기에서 Adapter는 Adaptee를 상속받아서 구현할 수 있다.

attachment:ClassAdapter.png

예제

와우를 좋아하니, 와우의 직업군으로 예제를 만들어 봤다. 와우(:12)에서 가장 중요한 직업이라고 하면 역시 파티의 리더이자 몸빵인 Fighter와 Fighter와 파티의 피를 책임져 주는 healer일 것이다. - 참고로 나는 천민 냥꾼. 그래도 부사령관이라는. 말퓨리온서버 드라고너를 찾아주세요.-

Fighter도 피가 없을때에는 붕대질로 피를 채울 수 있기는 한데, 힐러의 healing 마법에 비해서는 그 효율성이 대단히 떨어질 수 밖에 없다.

그래서 Fighter에게 힐러의 1 level 힐링 능력을 선사하기로 했다. 와우저의 입장에서는 Fighter에게 마법이 생소할 수 있겠지만, D&D룰 같은 경우에만 봐도 Fighter Class가 마법을 배우는 것을 금지하고 있지는 않다. 좀 효율이 떨어져서 그렇지..

이제 Fighter에게 힐러의 cure 능력을 줘야 하는데.. 음 이게 인터페이스가 다른게 좀 문제다. Adapter Pattern을 이용하면, 이 문제를 풀 수 있을 것 같다.

Object pattern 버전

이건 Object pattern 버전의 코드다.
#include <iostream>

using namespace std;

/*
 응급상자 클래스
 여기에는 붕대와 붕대감기를 위한 Operation이 포함되어 있을 것이다.
*/
class AidKit
{

};

class Fighter 
{
	private:
	public:
    // 원래 전사는 붕대를 이용해서 치료할 수 밖에 없었지만..
		virtual void cure(AidKit *) = 0;
		virtual void attack() = 0;
		virtual void defense() = 0;
		void myClass(){cout << "I'm fighter" << endl;}
};

class Healer
{
	public:
		void healing(int Level) {
			cout << "Level : " << Level << "Healing 시전" << endl;
		}
		void magic_attack();
		void magic_defense();
};

class AdvFighter : public Fighter
{
	private :
		Healer *heal;
		int healLevel; 
	public:
		AdvFighter(Healer *h) {
			heal = h;
			healLevel = 1;
		}
		void attack(){cout << "Attack !!!" << endl;};
		void defense(){cout << "Defense !!!" << endl;};
		void setHealLevel(int lev) {

		}
		// 레벨업 되면서, 힐러의 healing 마법을 쓸 수 있게 되었다.
		// 1 level 이지만 이것만 해도 감사 감사.
		// 기존의 붕대질 스킬은 그대로 둔채, 새로운 스킬을 추가해도 된다. 
		void cure(AidKit *)
		{
			heal->healing(healLevel);
		}
		void healing()
		{
			heal->healing(healLevel);
		}
		int getHealLevel()
		{
			return healLevel;
		}
};

int main(int argc, char **argv)
{
	Healer *myHealer;
	AidKit *myKit;
	AdvFighter *healFighter = new AdvFighter(myHealer);
	healFighter->myClass();
	healFighter->cure(myKit);
	healFighter->healing();
	healFighter->attack();
}

Class Pattern 버전

C++의 다중상속을 이용해서 구현했다.
// ...전략
class Fighter 
{
	private:
	public:
		virtual void cure(AidKit *) = 0;
		virtual void attack() = 0;
		virtual void defense() = 0;
		void myClass(){cout << "I'm Fighter" << endl;}
};

class Healer
{
	public:
		void healing(int Level) {
			cout << "Level : " << Level << "Healing 시전" << endl;
		}
		void magic_attack();
		void magic_defense();
};

class AdvFighter : public Fighter, private Healer
{
	private :
		int healLevel; 
	public:
		AdvFighter() {
			healLevel = 1;
		}
		void cure(AidKit *) {
			Healer::healing(healLevel);
		}
		void attack(){};
		void defense(){};
};

int main()
{
	AdvFighter *myFighter = new AdvFighter;
	AidKit *myKit;
	myFighter->myClass();
	myFighter->cure(myKit);
	return 0;
}

generic Adapter pattern

템플릿을 이용한 generic adapter pattern이건 따로 문서를 만들어서 정리해볼 생각임.