어댑터 패턴

YaaaPyoung·2022년 4월 27일
0

디자인패턴

목록 보기
1/2
  • 기존 코드를 클라이언트가 사용하는 인터페이스의 구현체로 바꿔주는 패턴으로 어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다.

  • 위의 클래스 다이어그램에서 구현해야할 부분은 바로 Adapter이다. 타겟 인터페이스에 의존하고 있는 클라이언트 코드와 어댑티 부분을 우리가 변경할 수 없는 상황이라고 가정했을 때 클라이언트가 어댑티를 사용하게 하려면 어떻게 해야할까?

  • 클라이언트는 타겟 인터페이스에만 의존하고 있으니 어댑티와 타겟 인터페이스 사이를 이어주는 무언가, 즉 어댑터를 구현해야 한다. 어댑터를 타겟 인터페이스의 구현 클래스로 만들고 어댑티를 외부에서 주입받는 컴포지션 방식을 사용하도록 한다. 위의 클래스 다이어그램에서 어댑터가 어댑티에 의존하는 이유도 내부적으로 컴포지션 방식을 사용하기 때문이다.

  • 극단적인 예를 들어보자, 클라이언트 코드에서는 Car 타입의 참조변수로 accelerate()와 stop() 메소드를 호출해야한다고 가정하자.

    interface Car {
    	void accelerate();
    	void stop();
    }
    
    class Sonata implements Car {
    
    	@Override
    	public void accelerate() {
    		System.out.println("소나타 가속");
    	}
    
    	@Override
    	public void stop() {
    		System.out.println("소나타 제동");
    	}
    }
    
    class Example {
    
    	public static void main(String[] args) {
    		Car car = new Sonata();
    		car.accelerate();
    		car.stop();
    	}
    }
    [출력 결과]
    소나타 가속
    소나타 제동

    car 참조 변수는 Car 인터페이스 타입이다. 위에서 말했던 것처럼 클라이언트 코드를 변경할 수 없다고 가정할 때 (car 참조 변수의 타입을 변경할 수 없을 때) car 참조 변수를 사용해서 아래의 Airplane 인터페이스 구현체의 메소드를 호출하려면 어떻게 해야할까?

    interface Airplane {
    	void fly();
    	void landing();
    }
    
    class Airbus implements Airplane {
    	@Override
    	public void fly() {
    		System.out.println("에어버스 이륙");
    	}
    
    	@Override
    	public void landing() {
    		System.out.println("에어버스 착륙");
    	}
    }

    현재 Car car = ..... 로 선언되어있는 클라이언트 코드로 Airplane 인터페이스 메소드를 호출하는 것은 불가능하다. 하지만 타겟 인터페이스(Car 인터페이스)를 구현하는 어댑터 클래스를 새로 만들고 외부 주입을 통해 어댑티(Airplane 인터페이스의 구현체)를 컴포지션 방식으로 사용하면 클라이언트 코드를 변경하지 않고서 Airplane 인터페이스의 메소드를 호출하는 것이 가능하다.

    public class CarAdapter implements Car{
    
    	private Airplane airplane;
    
    	public CarAdapter(Airplane airplane) {
    		this.airplane = airplane;
    	}
    
    	@Override
    	public void accelerate() {
    		airplane.fly();
    	}
    
    	@Override
    	public void stop() {
    		airplane.landing();
    	}
    }
    
    class Example {
    
    	public static void main(String[] args) {
    		// Car car = new Sonata();
    		Car car = new CarAdapter(new Airbus());
    		car.accelerate();
    		car.stop();
    	}
    }
    [출력 결과]
    에어버스 이륙
    에어버스 착륙

    어댑터 패턴에서 눈여겨 봐야할 것은 OCP가 적용되어 있다는 것이다. 위의 클라이언트 코드를 변경하지 않고서도 구현을 갈아 끼울 수 있다. 그것이 가능한 이유는 클라이언트 코드가 인터페이스에 의존하고 있기 때문이다.

    위 예제는 어댑터 패턴을 통해 상호 연결(?)할 수 있다는 점을 부각시키기 위해 자동차와 비행기로 예시를 들었다.

0개의 댓글