어댑터 패턴은 다른 인터페이스를 사용해도 대상 객체를 사용할 수 있도록 객체를 약간 조정합니다.
이런 방법으로 다른 인터페이스를 사용해도 객체의 함수에 접근할 수 있도록 합니다.
class OurSpec {
method1(): void {
console.info('method1');
}
}
interface ShareSpec {
method2(): void;
}
class AdapterSpec implements ShareSpec {
private readonly ourSpec: OurSpec;
constructor(ourSpec: OurSpec) {
this.ourSpec = ourSpec;
}
method2(): void {
this.ourSpec.method1();
}
}
const spec = new AdapterSpec(new OurSpec());
spec.method2(); // "method1"
어댑터 패턴의 대표적인 구현 방식은 역시나 합성인 것 같습니다. 상속을 사용할 수도 있긴 합니다만, 사실 별 차이는 없습니다.
위 코드의 상황은 이렇습니다. 우리는 구현할 때 OurSpec 이라는 스펙에 맞춰서 method1 을 개발했습니다.
하지만 다른 팀 혹은 외부 클라이언트에선 ShareSpec 을 구현한 method2 가 필요한 것이죠.
이럴때 객체 합성을 통해 인터페이스를 지원하는 Adapter 에 특정 인터페이스를 지원하지 않는 객체를 집어 넣어 사용하는 방법입니다.
위의 예시 코드는 이러한 방법을 나타낸 것이구요. 예시가 너무 간단해서 OurSpec 을 그냥 ShareSpec 을 구현하게끔 변경하는게 낫지 않느냐? 라고 할 수도 있지만, 이것또한 상황에 따라 다를 수 있을 것 같습니다.
위의 예시는 너무 간단하지만 예를 들어 이것이 하나의 라이브러리라고 할 때, 이것을 새로운 스펙에 맞게 전부 변경하는 일은 기존 코드의 수정을 너무도 많이 하게 됩니다. 이럴땐 차라리 위처럼 합성을 통해 적게 수정을 가져가는 것이 괜찮은 방법일 수 있습니다.
혹은 외부 라이브러리라서 인터페이스를 바꾸고 싶어도 바꿀 수 없는 경우에도 고려해볼 수 있을 것 같습니다.(생각보다 실무에선 이런 상황이 꽤 있는 것 같네요)
어댑터 패턴을 사용하면 기존 코드의 변경을 최소화할 수 있고 재사용성을 증가시킬 수 있습니다.
다만 아무래도 복잡성이 증가하고 잘 관리되지 않을 경우 상당히 커다란 기술 부채로 이어질 수 있을 것 같습니다.
'Backend > 디자인 패턴' 카테고리의 다른 글
Template Pattern (템플릿 패턴) (0) | 2022.10.29 |
---|---|
Strategy Pattern (전략 패턴) (0) | 2022.10.24 |
Decorator Pattern (데코레이터 패턴) (0) | 2022.10.01 |
Proxy Pattern (프록시 패턴) (0) | 2022.09.25 |
Revealing Constructor Pattern (공개 생성자 패턴) (0) | 2022.09.18 |