본문 바로가기

코드 디자인 패턴/java

[java & 디자인 패턴] Adapter 패턴 정리

기본 개념


  • 특정 인터페이스 기반의 클래스를 사용하다보면  호환되지 않은 다른 인터페이스의 클래스를 함께 사용해야 할 때가 있다. 이런 경우, 두 인터페이스를 수정하거나 클라이언트 측의 사용 코드를 수정해야할 수 있는데, 이는 기존에 잘 작동하던 코드에서 버그를 일으킬 수 있고 리팩토링 비용을 발생시킨다.
  • 어댑터 패턴은 이처럼 호환되지 않는 두 클래스 혹은 클라이언트 코드 간에 중간 역할을 하는 클래스를 삽입한다.
  • 이 패턴은 wrapper 패턴이라고도 하는데, 서로 다른 클래스나 인터페이스를 감싸서 새 클래스를 만드는 방식이기 때문이다.
  • 종류
    • 클래스 기반 어댑터 패턴(상속 사용)
    • 인스턴스 기반 어댑터 패턴(위임 사용)
  • 장점
    • 객체 지향 프로그래밍인 자바에서 안정적 클래스를 상속 및 구현하는 건 버그 안정성이나 생산성에서 중요하지만, 상속 방식의 한계가 있다. 어댑터는 이런 호환성의 문제를 해결
    • 기존 클래스 자체를 변형하지 않으므로, 새로운 버그 발생이 적고 생산성이 높다.
  • 단점
    • 어댑터가 많아지면 장기적으로 유지보수에 번거롭다.

 

구현


인스턴스 기반 어댑터 패턴

인스턴스 형식의 어댑터 객체를 사용해서 한 객체를 다른 객체와 호환되게 해주는 패턴이다.

 

예시

public interface IACharacter {
	public void run();
	public void sneak();
}

public class ACharacter implements IACharacter {

	private String name;

	public ACharacter(String name) {
		// TODO Auto-generated constructor stub
		this.name = name;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println(this.name + ". 기술 사용: 달리기!");
	}

	@Override
	public void sneak() {
		// TODO Auto-generated method stub
		System.out.println(this.name + ". 기술 사용: 숨기!");
	}

}

public interface IBCharacter {
	public void moveFaster();
	public void hide();
}

public class BCharacter implements IBCharacter {

	private String name;

	public BCharacter(String name) {
		// TODO Auto-generated constructor stub
		this.name = name;
	}

	@Override
	public void moveFaster() {
		// TODO Auto-generated method stub
		System.out.println(this.name + ". 기술 사용B: 달리기!");
	}

	@Override
	public void hide() {
		// TODO Auto-generated method stub
		System.out.println(this.name + ". 기술 사용B: 숨기!");
	}
}

public class Client {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		// ACharacter와 BCharacter은 메소드 사양이 다름
		ACharacter aCharacter = new ACharacter("char1");
		aCharacter.run();
		aCharacter.sneak();

		BCharacter bCharacter = new BCharacter("char2");
		bCharacter.moveFaster();
		bCharacter.hide();

		// 어댑터 인스턴스로 BCharacter를 ACharacter의 사양대로 사용
		AdapterBtoA adapterBtoA = new AdapterBtoA(bCharacter);
		adapterBtoA.run();
		adapterBtoA.sneak();

	}
}

 

클래스 기반 어댑터 패턴

어댑터 클래스와 인터페이스를 상속받아 어댑티 클래스의 메서드를 재정의하는 방법이다.

 

예시

public interface IACharacter {

	public void run();
	public void sneak();
}

public class ACharacter implements IACharacter {

	private String name;

	public ACharacter(String name) {
		// TODO Auto-generated constructor stub
		this.name = name;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println(this.name + ". 기술 사용: 달리기!");
	}

	@Override
	public void sneak() {
		// TODO Auto-generated method stub
		System.out.println(this.name + ". 기술 사용: 숨기!");
	}

}

public abstract class AbstractBCharacter {

	public abstract void moveFaster();
	public abstract void hide();
}

public class BCharacter extends AbstractBCharacter {

	private String name;

	public BCharacter(String name) {
		// TODO Auto-generated constructor stub
		this.name = name;
	}

	@Override
	public void moveFaster() {
		// TODO Auto-generated method stub
		System.out.println(this.name + ". 기술 사용B: 달리기!");
	}

	@Override
	public void hide() {
		// TODO Auto-generated method stub
		System.out.println(this.name + ". 기술 사용B: 숨기!");
	}


}

public class AdapterBtoA extends BCharacter implements IACharacter {

	public AdapterBtoA(String name) {
		super(name);
		// TODO Auto-generated constructor stub
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		this.moveFaster();
	}

	@Override
	public void sneak() {
		// TODO Auto-generated method stub
		this.hide();
	}

}

public class Client {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		// ACharacter와 BCharacter은 메소드 사양이 다름
		ACharacter aCharacter = new ACharacter("char1");
		aCharacter.run();
		aCharacter.sneak();

		BCharacter bCharacter = new BCharacter("char2");
		bCharacter.moveFaster();
		bCharacter.hide();

		// 어댑터 인스턴스로 BCharacter를 ACharacter의 사양대로 사용
		AdapterBtoA adapterBtoA = new AdapterBtoA("char3");
		adapterBtoA.run();
		adapterBtoA.sneak();

	}

}