어댑터라는 것은 우리 주변에서도 흔히 볼 수 있다. 대표적으로 110V 전용 가전 제품에 220V 어댑터를 끼워 사용하는 것이다.
어댑터를 보면 어댑터 패턴이 무엇인지 대충 감이 올 수도 있겠다.
이 패턴을 사용할만 한 경우를 만들어보면,
"포토뷰어 엔진을 판매하는 회사 A가 있다. 이 A 회사의 엔진이 우리 회사의 포토뷰어 엔진보다 성능이 좋다는 결과를 통보 받았다. 그래서 나는 우리 회사의 포토 뷰어 엔진을 교체 하기 위해 A라는 회사에 엔진을 요청했고 엔진 명세서를 받아봤다."
즉 '나'는 성능의 향상을 위해 포토 뷰어 엔진을 기존의 엔진에서 A 업체가 제공하는 엔진으로 바꿔야만 하는 상황이다.
이제 명세표를 보면 A엔진과 기존 엔진의 구조를 살표보자.
/* 내가 쓰는 엔진 명세 (MyLib) */
class MyLib
{
public:
void printPhoto(String fileName) { ... }
void printPhotoList(String[] listName) { ... }
void deletePhoto(String fileName) { ... }
void addPhoto(String fileName) { ... }
}
/* A 엔진 명세 (ALib) */
class ALib
{
public:
void printPhoto(String fileName) { ... }
void deletePhoto(String fileName) { ... }
void addPhoto(String fileName) { ... }
}
엔진이 완전히 같다면 좋을텐데 미묘하게 다른 구석이 있다. 차이가 있는 것은 제공 받은 엔진에서 printPhotoList() 가 없다는 것이다. 어쨋든 엔진 교체를 위해 코드 분석에 들어가보자. 아래 코드는 기존 엔진을 사용한 코드이다. 기존 엔진의 이름은 MyLib 이다.
/* 기존 코드 */
int main()
{
MyLib lib = new MyLib();
String photoList = { "abc.jpg" , "def.jpg" };
lib.printPhotoList(photoList);
lib.printPhoto("abc.jpg");
lib.deletePhoto("abc.jpg");
lib.addPhoto("aaa.jpg");
}
자, 이제 함수명이 동일하니 한번 엔진을 바꿔보자.
/* 바뀐 코드 Ver.1 */
int main()
{
ALib lib = new ALib(); // change
String photoList = { "abc.jpg" , "def.jpg" };
for(int i = 0 ; i < photoList.length; i++) // for문 추가됨
{
lib.printPhoto(photoList[i]);
}
lib.printPhoto("abc.jpg");
lib.deletePhoto("abc.jpg");
lib.addPhoto("aaa.jpg");
}
이제 프로그램은 잘 돌아갈거라고 생각이 되지만, 기본 로직에 변경이 생겼다. 바로 전에 없었던 for()이 들어가게 된 것이다. 물론 이 코드를 더 이상의 유지 보수를 하지 않을 예정이라면 이대로 놔둬도 상관없겠지만, 프로그램을 만들면 무조건 유지 보수를 해야하기 때문에 이렇게 두는 것은 좋지 않은 방법이다.
따라서 기본 로직을 그대로 이용할 수 있게끔 어댑터 패턴을 사용해보자.
class IPhotoEngine
{
public:
virtual void printPhoto(String fileName) = 0;
virtual void printPhotoList(String[] listName) = 0;
virtual void deletePhoto(String fileName) = 0;
virtual void addPhoto(String fileName) = 0;
}
인터페이스 클래스를 만들었다. 이제 어댑터 클래스를 만들어보자.
class ALibAdapter : public IPhotoEngine
{
private:
ALib lib;
public:
ALibAdapter( ALib lib )
{
this.lib = lib;
}
void printPhoto(String fileName)
{
lib.printPhoto( fileName );
}
void printPhotoList(String[] listName)
{
for(int i = 0 ; i < listName.length; i++)
{
lib.printPhoto( listName[i] );
}
}
void deletePhoto(String fileName)
{
lib.deletePhoto( fileName );
}
void addPhoto(String fileName)
{
lib.addPhoto( fileName );
}
}
이제 이 클래스를 사용해 보자.
/* 바뀐 코드 Ver.2 */
int main()
{
ALib alib = new ALib();
PhotoEngine lib = new ALibAdapter( alib );
String photoList = { "abc.jpg" , "def.jpg" };
lib.printPhotoList(photoList);
lib.printPhoto("abc.jpg");
lib.deletePhoto("abc.jpg");
lib.addPhoto("aaa.jpg");
}
물론 ALib가 아닌 다른 엔진을 사용할 때에도 마찬가지로 IPhotoEngine 인터페이스를 포함한 어댑터 클래스를 만들기만 하면 언제든 로직을 재사용할 수 있다.
이것이 바로 어댑터 패턴을 사용하는 목적이기도 하다.
만약 기존엔진을 다시 써야하는 상황이 올때를 대비해서 기존 엔진의 어댑터 클래스를 만들어보자.
class MyLibAdapter : public PhotoEngine
{
private:
MyLib lib;
public:
MyLibAdapter( MyLib lib )
{
this.lib = lib;
}
void printPhoto(String fileName)
{
lib.printPhoto( fileName );
}
void printPhotoList(String[] listName)
{
lib.printPhotoList( listName );
}
void deletePhoto(String fileName)
{
lib.deletePhoto( fileName );
}
void addPhoto(String fileName)
{
lib.addPhoto( fileName );
}
}
그리고 간단하게 기존 엔진을 사용하도록 바꾸면 된다.
/* 바뀐 코드 Ver.3 */
int main()
{
MyLib myLib = new myLib();
PhotoEngine lib = new MyLibAdapter( myLib );
String photoList = { "abc.jpg" , "def.jpg" };
lib.printPhotoList(photoList);
lib.printPhoto("abc.jpg");
lib.deletePhoto("abc.jpg");
lib.addPhoto("aaa.jpg");
}
출처 : http://jdm.kr/blog/11