오늘은 디자인 패턴 중 하나인 어댑터 패턴에 대해 알아보자!
어댑터 패턴이란?
어댑터 패턴은 한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환한다.
즉, 어댑터를 이용하면 인터페이스 호환성 문제로 같이 쓸 수 없는 클래스들을 연결해서 사용할 수 있다.
어댑터 패턴이 왜 필요할까?
어댑터 디자인 패턴을 사용하는 경우 서로 호환되지 않는 인터페이스를 사용하는 클라이언트를 그대로 활용할 수 있다.
인터페이스를 변환해주는 어댑터만 만들면 되기 때문이다! 이를 통해 클라이언트와 구현된 인터페이스를 분리할 수 있고, 나중에 인터페이스가 바뀌더라도 변경 내역이 어댑터에 캡슐화되기 때문에 클라이언트는 바뀔 필요가 없어진다.
언제 사용할 수 있을까?
- 기존 클래스를 사용하고 싶은데 인터페이스가 맞지 않을 때
- 이미 만든 것을 재사용하고 싶은데 재사용 가능한 라이브러리를 수정할 수 없을 때
어댑터 패턴의 역할
- 어떤 인터페이스를 클라이언트에서 요구하는 형태의 인터페이스에 적응 시켜주는 역할
- 한 인터페이스를 다른 인터페이스로 변환시키기 위한 역할
주요 객체
- Target : 인터페이스를 정의하는 클래스
- Client : Target 인터페이스를 만족하는 객체와 동작할 대상
- Adaptee : 인터페이스의 적응이 필요한 기존 클래스, 쉽게 말해 호환되지 않는 클래스
- Adapter : Target 인터페이스에서 Adaptee 인터페이스를 적용시키는 클래스
어댑터 패턴의 예시
Target : Interface 정의
public interface LightningPhone {
void recharge();
void useLightning();
}
public interface MicroUSBPhone {
void recharge();
void useMicroUSB();
}
Adaptee 정의
public class Iphone implements LightningPhone {
private boolean connector = false;
public void recharge() {
if (connector) {
System.out.println("Recharge Started");
System.out.println("Recharge finished");
} else {
System.out.println("Connect Lightning first");
}
}
public void useLightning() {
connector = true;
System.out.println("Lightning connected");
}
}
public class Android implements MicroUSBPhone {
private boolean connector = false;
public void recharge() {
if (connector) {
System.out.println("Recharge Started");
System.out.println("Recharge finished");
} else {
System.out.println("Connect MicroUSB first");
}
}
public void useMicroUSB() {
connector = true;
System.out.println("MicroUSB connected");
}
}
Adapter 정의
public class LightningToMicroUSBAdapter implements MicroUSBPhone {
private LightningPhone lightningPhone;
public LightningToMicroUSBAdapter(LightningPhone lightningPhone) {
this.lightningPhone = lightningPhone;
}
public void recharge() {
lightningPhone.recharge();
}
public void useMicroUSB() {
System.out.println("MicroUSB connected");
lightningPhone.useLightning();
}
}
Client 정의
public void rechargeMicroUSBPhone(MicroUSBPhone phone) {
phone.useMicroUSB();
phone.recharge();
}
public void rechargeLightningPhone(LightningPhone phone) {
phone.useLightning();
phone.recharge();
}
public static void main(String[] args) {
Android android = new Android();
Iphone iphone = new Iphone();
LightningToMicroUSBAdapter adapter = new LightningToMicroUSBAdapter(iphone);
System.out.println("Recharging android with MicroUSB");
rechargeMicroUSBPhone(android);
System.out.println("Recharging iphone with Lightning");
rechargeLightningPhone(iphone);
System.out.println("Recharging iphone with MicroUSB");
rechargeMicroUSBPhone(adapter);
}
- 결과
Recharging android with MicroUSB
MicroUSB connected
Recharge Started
Recharge finished
Recharging iphone with Lighting
Lightning connected
Recharge Started
Recharge finished
Recharging iphone with MicroUSB
MicroUSB connected
Lightning connected
Recharge Started
Recharge finished
어댑터 패턴의 장단점
장점
- 기존 코드를 변경하지 않아도 된다.
- 기존 코드를 변경하지 않기 때문에 클래스 재활용성을 증가시킬 수 있다.
단점
- 구성요소를 위해 클래스를 증가시켜야하기 때문에 복잡도가 증가한다.
- 클래스 Adapter의 경우 상속을 사용하기 때문에 유연하지 못하다.
- 객체 Adapter의 경우 대부분의 코드를 다시 작성해야 하므로 효율적이지 못하다.
'📒 기술 또는 개념 > 🎨 Design Pattern' 카테고리의 다른 글
[Design Pattern] 팩토리(Factory) 패턴에 대해 (0) | 2023.10.25 |
---|---|
[Design Pattern] 빌더(Builder) 패턴에 대해 (0) | 2023.10.24 |
[Design Pattern] 싱글톤(Singleton) 패턴에 대해 (0) | 2023.10.23 |