의도
- 클래스의 인터페이스를 사용자가 기대하는 인터페이스 형태로 적응시킴. 서로 일치하지 않는 인터페이스를 갖는 클래스들을 함께 동작시킴.
다른 이름
- 래퍼(Wrapper)
언제 쓰는가?
- 기존 클래스를 사용하고 싶은데 인터페이스가 맞지 않을 때.
- 아직 예측하지 못한 클래스나 실제 관련되지 않는 클래스들이 기존 클래스를 재사용하고자 하지만, 이미 정의된 재사용 가능한 클래스가 지금 요청하는 인터페이스를 꼭 정의하고 있지 않을 때. 다시 말해, 이미 만든 것을 재사용하고자 하나 이 재사용 가능한 라이브러리를 수정할 수 없을 때.
- [객체 적응자(object adapter)만 해당됨] 이미 존재하는 여러 개의 서브클래스를 사용해야 하는데, 이 서브클래스들의 상속을 통해서 이들의 인터페이스를 다 개조한다는 것이 현실성이 없을 때. 객체 적응자를 써서 부모 클래스의 인터페이스를 변형하는 것이 더 바람직함.
구조
- Target : 사용자가 사용할 응용 분야에 종속적인 인터페이스를 정의하는 클래스.
- Client : Target 인터페이스를 만족하는 객체와 동작할 대상.
- Adaptee : 인터페이스의 적응이 필요한 기존 인터페이스를 정의하는 클래스로서, 적응 대상자라고 함.
- Adapter : Target 인터페이스에 Adaptee의 인터페이스를 적응시키는 클래스.
협력 방법
- 사용자는 적응자에 해당하는 클래스의 인스턴스에게 연산을 호출, 적응자는 해당 요청을 수행하기 위해 적응대상자의 연산을 호출함.
결과
1. 클래스 적응자 vs 객체 적응자
- Adapter를 만들기 위해 Adaptee 클래스를 상속 받았을 때와 객체 합성을 통해 만들었을 때 장단점이 있음.
- 상속 받았을 경우, 특정 서브 클래스에 종속되므로 다른 서브 클래스에 접근하기가 어려워지나 함수의 재사용이나 오버라이딩을 통한 재구현이 가능해짐.
- 객체 합성을 통해 만들 경우, Adapter 클래스가 하나만 존재해도 수많은 Adaptee 클래스들과 동작할 수 있음. 대신 Adaptee 클래스들의 행동을 재정의하기가 어려워짐.
2.추가 고려 사항
- Adapter 클래스가 실제 적응 작업을 위해 들어가는 품이 얼마나 되나 ? : 적응 어떻게 시키는지에 따라 달라짐.시그니처가 다른 인터페이스를 적응시키는 것일수도, 단순히 연산의 이름을 바꾸는 것일 수도 있음. 작업량을 결정짓는 것은 Target 인터페이스와 Adaptee 간이 얼마만큼의 유사성을 갖는가 하는 부분.
- 대체 가능 적응자 : 클래스의 재사용성을 높이려면, 누가 이 클래스를 사용할지에 대한 생각을 최소화해야 함. 만약, 인터페이스의 변경이 필요하다면 이 내용을 담은 클래스를 만들면 됨. 표준화 된 인터페이스를 정의해야 한다는 부담을 덜 수 있음. 이런 인터페이스 개조를 담당하는 클래스를 대체 가능 적응자 라고 함.
- 양방향 적응자를 통한 투명성 제공 : 적응자의 잠재적인 문제는 적응자가 모든 사용자에게 투명하지 않다는 점. 적응된 객체는 Adaptee 인터페이스를 만족하지 않음. Adaptee 객체를 통해 Target을 사용해야 하는 사용자라면 적응된 객체를 사용할 수 없음. 다중 상속을 이용하여 양쪽 모두에게 맞는 연산을 제공할 수 있음.
구현
- 클래스 적응자 사용 시 : Adapter 클래스는 Target 클래스에서 public으로 상속받고, Adaptee는 private으로 상속받아야 함. Adaptee는 내부 구현에 필요한 것으로, Adaptee가 사용자에 알려질 필요 없음.
- 대체 가능 적응자
- 추상 연산 사용 : Adaptee의 가상 함수를 재정의하여 다양한 행동 정의 가능.
- 위임 객체 사용 : 위임 객체를 사용하여 다양한 전략 구사. 위임 전용 추상 클래스를 만들어 다양한 객체로 분화 가능.
- 매개변수화된 적응자 사용
예제 코드 ( 1 )
- 클래스 적응자의 예부터 먼저 확인해 보겠습니다.
- 마땅한 예시가 생각나지 않아 아래처럼 구성하였는데 이 패턴을 사용함의 본질은 객체의 인터페이스를 변경하는 것입니다. Destroy와 Sop 간의 연관성이 없다고 생각될 수도 있으나 그 점 참고하고 봐주시면 되겠습니다.
- 화장실 전용 휴지가 물에 젖으면 잘 파괴된다 라는 가정을 가집니다.
- 화장실 전용 휴지를 만드는 과정에서 휴지가 젖은 경우에 파괴된다라는 속성을 추가한 경우입니다.
#include "Adapter1.h"
int main()
{
ToiletTissue t_tissue;
t_tissue.Sop();
return 0;
}
- 화장실 휴지는 물에 젖었고, 파괴됨을 알립니다.
//Adapter1.h
#pragma once
#include <iostream>
class Tissue
{
public:
virtual void Sop()
{
std::cout << "Tissue가 물에 젖었습니다." << std::endl;
}
};
class Destructible
{
public:
void Destroy()
{
std::cout << "이 물체를 파괴합니다." << std::endl;
}
};
class ToiletTissue : public Tissue, private Destructible
{
public:
virtual void Sop() override
{
Tissue::Sop();
Destroy();
}
};
- 휴지가 물에 젖었음을 호출할 수 있게 Tissue는 public 상속, 파괴될 수 있는 속성은 내부에서만 사용할 것이기 때문에 private 상속으로 해주었습니다.
- 물에 젖는 순간 젖었음을 화면에 출력하고, 파괴됨도 화면에 출력합니다.
예제 코드 ( 2 )
- 위 예제 내용은 그대로 객체 적응자로 진행하겠습니다.
- 객체 적응자로 이 패턴을 사용하였을 경우의 장점인 다양한 서브클래스로 갈아낄 수 있다는 점에 중점을 두어 예제 작성했습니다.
#include "Adapter2.h"
int main()
{
ToiletTissue_V2 t_tissue1;
ToiletTissue_V2 t_tissue2;
Destructible_V2 destructible;
SoftDestructible soft_destructible;
t_tissue1.SetDestructible(&destructible);
t_tissue2.SetDestructible(&soft_destructible);
t_tissue1.Sop();
t_tissue2.Sop();
return 0;
}
- tissue1은 단순히 파괴되었고, tissue2는 부드럽게 파괴되었습니다. 어떤 destructible로 객체 합성을 했는지에 따라 다른 결과입니다.
#pragma once
#include <iostream>
class Tissue_V2
{
public:
virtual void Sop()
{
std::cout << "Tissue가 물에 젖었습니다." << std::endl;
}
};
class Destructible_V2
{
public:
virtual void Destroy()
{
std::cout << "이 물체를 파괴합니다." << std::endl;
}
};
class SoftDestructible : public Destructible_V2
{
public:
virtual void Destroy() override
{
std::cout << "부드럽게 ";
__super::Destroy();
}
};
class ToiletTissue_V2 : public Tissue_V2
{
public:
virtual void Sop() override
{
Tissue_V2::Sop();
destructible->Destroy();
}
void SetDestructible(Destructible_V2* destructible)
{
this->destructible = destructible;
}
private:
Destructible_V2* destructible;
};
- ToilletTissue_V2는 private 상속이 아닌 멤버변수로 destructible을 포함하고 있습니다.
- ToilletTissue_V2의 Sop 메서드를 보게 되면 descturctible의 Destroy 메서드를 호출하게 되고 이것은 destructible이 실제 어떤 인스턴스인지에 따라 다른 결과를 보이게 될 것입니다.
'디자인 패턴 > 구조' 카테고리의 다른 글
퍼사드(Facade) (1) | 2023.12.22 |
---|---|
장식자(Decorator) (0) | 2023.12.22 |
복합체(Composite) (2) | 2023.12.21 |
가교(Bridge) (2) | 2023.12.21 |
구조 패턴 (0) | 2023.12.20 |