728x90
어댑터 패턴
- 구조적 패턴 카테고리
- 서로 호환성이 없는 인터페이스 / 클래스 들을 연결시켜 동작 할 수 있게 도와준다.
적용 사례
- 외부 라이브러리 (Auth, Payment, Media)
- 외부 라이브러리를 사용중인데 현제 시스템상 맞지않아서 업데이트가 필요할때, 외부 라이브러리 클래스나 인터페이스에 직접적으로접근 못하는 상황일때 어댑터를 사용하여 중간에 작업을 변환한다
- 레거시 시스템 부분 확장
- 기존 시스템을 부분적으로 확장해야하는데 인터페이스나 클래스가 앱 전역에서 사용되는 비중이 클때 비용문제를 생각하여 어댑터 클래스를 부분적으로 만들어주고 호환 안되는 부분만 어댑터 클래스를 사용하여 변경한다
구성 요소
- 클라이언트
- 인터페이스
- 서비스/외부요소
- 어댑터
코드
interface ISmartDevice{
connect(): boolean;
device: string;
}
export default ISmartDevice
class TV implements ISmartDevice {
private _device: string;
constructor(){
this._device = 'TV';
}
connect(){
if(this.device){
console.log(`connecting.. ${this.device}`)
return true
}
return false
}
get device(){
return this._device;
}
}
export default TV
class Speaker implements ISmartDevice {
private _device: string;
constructor(){
this._device = 'Speaker';
}
connect(){
if(this.device){
console.log(`connecting.. ${this.device}`)
return true
}
return false
}
get device(){
return this._device;
}
}
export default Speaker
class SmartHomeClient {
addConnection(device: ISmartDevice){
try{
device.connet();
console.log(`연결 완료 : ${device.device}`)
} catch {
console.log(`에러 : ${device.constructor.name} 연결에 실패하였습니다.`)
}
}
}
const smartHomeClient = new SmartHomeClient();
smartHomeClient.addConnection(new TV());
smartHomeClient.addConnection(new Speaker());
기존의 TV
클래스와 Speaker
클래스는 인터페이스가 맞게 작성되었기에 잘 동작하게 된다. 하지만 추가적으로 Monitor
클래스를 기존 시스템에 추가하려고한다. 해당 클래스는 다음과 같다
interface IMonitor {
makeConnection(): string;
getDeviceName(): string;
}
class Monitor implements IMonitor{
private _device: string;
constructor(){
this._device = 'Monitor';
}
makeConnection(){
console.log(`연결중.. ${this.getDeviceName()}`)
}
getDeviceName(){
return this._device;
}
}
export default Monitor
연결 하려고하는 메서드 이름도 다르고 구현 방식도 다르게 되어있다. 그래서 현 상황에서는 호환이 되지않아 오류가 발생한다.
이럴때 어탭터 클래스를 사용하여 변환하게 해준다 어댑터 클래스는 아래와 같다
class MonitorAdaptor implements ISmartDevice{
private _target;
constructor(target: Monitor){
// 모니터 클래스를 전달받아서 참조한다.
this._target = target
}
connect(){
// 변환 작업
this._target.makeConnection();
return true
}
get device(){
// 변환 작업
return this._target.getDeviceName();
}
}
맞지않는 클래스를 받아서 인터페이스에 맞게 구현해준다. 하지만 실제 동작은 Monitor
객체의 동작을 하게 된다. 이제 다시 클라이언트 코드로 가면
class SmartHomeClient {
addConnection(device: ISmartDevice){
try{
device.connet();
console.log(`연결 완료 : ${device.device}`)
} catch {
console.log(`에러 : ${device.constructor.name} 연결에 실패하였습니다.`)
}
}
}
const smartHomeClient = new SmartHomeClient();
smartHomeClient.addConnection(new TV());
smartHomeClient.addConnection(new Speaker());
// 모니터클래스를 직접 넣는게 아니라 모니터 어댑터 클래스를 넣어준다.
smartHomeClient.addConnection(new MonitorAdaptor(new Monitor));
어댑터 패턴을 활용하면 기존 클라이언트 로직이나 인터페이스를 크게 변경하지 않고 별도의 심플한 어댑터 클래스를만들어서 외부 서비스가 기존 서비스에 이미 존재하는 것 처럼 보이게 하고 최소한의 의존성으로 잘 동작하게 만들어줍니다.
728x90
'디자인패턴' 카테고리의 다른 글
디자인패턴 - 전략패턴 (0) | 2024.02.18 |
---|---|
디자인패턴 - 프록시 패턴 (0) | 2024.02.18 |
디자인패턴 - 퍼사드패턴 (0) | 2024.02.17 |
디자인패턴 - 팩토리 메서드 패턴, 추상 팩토리 패턴 (0) | 2024.02.16 |
디자인패턴 - 싱글톤(Singleton) 패턴 (1) | 2024.02.15 |
댓글