Adapter Pattern에 대해사 알아 보도록 하겠습니다.
해당 패턴을 알아 보기전에 한가지 문제점에 대해서 먼저 알고 넘어가야 합니다.
[상황]
1. [인사]를 출력하는 클래스가 존재
[추가 할 내용]
1. [닉네임]을 추가로 출력 필요
2. [닉네임]을 먼저 출력 하거나, 인사를 먼저 출력 할 수 있음
물론 [인사]를 출력하는 부분에서 [닉네임]을 받아서 함께 처리 하여도 됩니다.
하지만,
기존의 코드를 수정하고 싶지 않을 경우, 또는 하지 못하는 경우에 다음과 같은 방법을 사용합니다.
먼저 해당 부분은 2가지 방법이 존재하는데
interface 를 사용하는 상속으로만 해결 하는 방법과,
상속, 위임(포함)을 통한 방법이 있습니다.
물론 2가지 모두 Adapter Pattern 입니다.
코드를 확인하도록 하겠습니다.
namespace AdapterPatternEx1
{
// "안녕하세요."를 출력하는 클래스가 있습니다.
// 이 클래스를 AdapterPattern을 사용해 확장해 보도록 합시다.
public class HelloPrint
{
private string hello;
public HelloPrint()
{
hello = "안녕하세요.";
}
public void SayHello()
{
Debug.Log(hello);
}
}
// 먼저 interface를 활용한 방법입니다.
public interface StringPrint
{
void firstHello();
void lastHello();
}
// 기존에 Hello Print와 새로운 interface인 StringPrint를 모두 상속받습니다.
public class NamePrint : HelloPrint, StringPrint
{
string namePrint;
public NamePrint(string name)
{
namePrint = name;
}
public void lastHello()
{
Debug.Log(namePrint + ", ");
// 부모 클래스로써 상속받은 함수를 호출합니다.
SayHello();
}
public void firstHello()
{
// 부모 클래스로써 상속받은 함수를 호출합니다.
SayHello();
Debug.Log(namePrint);
}
}
// 실제로 사용하는 예제
public class AdapterClass : MonoBehaviour
{
// interface 를 생성 합니다.
StringPrint namePrint = new NamePrint("캡틴후크");
void Start()
{
// 원하는 기능을 출력합니다.
Debug.Log("firstHello call");
namePrint.firstHello();
Debug.Log("lastHello call");
namePrint.lastHello();
}
}
}
StringPrint라는 interface를 추가로 제작해서 기존의 기능을 두면서 원하는 기능을 추가하였습니다.
현재 단계에서는 interface를 사용하든 확장된 클래스를 사용 하던 큰 차이는 없으나,
사용자에게 좀더 명확함을 주기 위해서 interface를 사용하는 것을 추천합니다.
그리고 두번째 방법으로
상속, 위임을 통한 방법에 대해서 알아 보도록 하겠습니다.
namespace AdapterPatternEx2
{
// 역시나 "안녕하세요."를 출력하는 class가 존재합니다.
public class HelloPrint
{
private string hello;
public HelloPrint()
{
hello = "안녕하세요.";
}
public void SayHello()
{
Debug.Log(hello);
}
}
// 이번엔 가상 한수를 만들어 접근해 보도록 합시다.
public abstract class StringPrint
{
public abstract void lastHello();
public abstract void firstHello();
}
// StringPrint를 상속 받고
public class NamePrint : StringPrint
{
// 기존의 클래스를 포함하여 진행합니다.
HelloPrint helloPrint = new HelloPrint();
string namePrint;
public NamePrint(string name)
{
namePrint = name;
}
public override void lastHello()
{
Debug.Log(namePrint);
// 결과는 기존과 동일 하나, 이번엔 다음처럼 지정하여 사용합니다.
helloPrint.SayHello();
}
public override void firstHello()
{
// 결과는 기존과 동일 하나, 이번엔 다음처럼 지정하여 사용합니다.
helloPrint.SayHello();
Debug.Log(namePrint);
}
}
public class AdapterClass : MonoBehaviour
{
// StringPrint class로 하든 namePrint로 하던 현재로썬 큰 의미가 없습니다.
StringPrint namePrint = new NamePrint("캡틴후크");
void Start()
{
Debug.Log("firstHello call");
namePrint.firstHello();
Debug.Log("lastHello call");
namePrint.lastHello();
}
}
}
이렇게 Adapter Pattern을 사용해서 문제를 해결하는 방법에 대해서 알아 보았습니다.
Adapter Pattern에 대해서 정의를 내리면 책에서는 다음과 같이 이야기 합니다.
- Wrapper(감싸는) Pattern 이라고도 함
- 이미 작동 하고 있는 ( 문제가 없는, 충분히 테스트된 ) 코드를 수정하지 않고, 개조하기 위해서 사용.
- 구 버전과의 호환성을 제공 할 수 있음.
마지막으로 용어 적인 부분과 다이어 그램을 확인 하고 Adapter Pattern은 마무리 짓도록 하겠습니다.
용어적인 부분
- Target( 예제 코드의 Interface [StringPrint]나, 가상 클래스인 [StringPrint] class )
- Client( Main 실행 코드, 예제 코드의 [AdapterClass] class )
- Adaptee( 예제 코드의 [HelloPrint] class )
- Adapter( 예제 코드의 [NamePrint] class )
다이어그램으로 표현
인터페이스를 사용한 Adapter Pattern
위임(포함)을 사용한 Adapter Pattern
다음은 Template Method Pattern 에 대해서 알아 보도록 하겠습니다.
'프로그래밍 > 디자인패턴' 카테고리의 다른 글
Factory Mathod Pattern (0) | 2017.04.12 |
---|---|
Template Method Pattern (0) | 2016.06.30 |
Iterator Pattern (0) | 2016.05.04 |
UML의 기본 구성-시퀀스 다이어그램 (4) | 2016.05.02 |
UML의 기본 구성-클래스 다이어그램 (0) | 2016.05.02 |