개발자 준비/디자인패턴 & 아키텍쳐

어뎁터 패턴 & 파사드패턴

osul_world 2021. 12. 29. 20:35
728x90

어뎁터 패턴 & 파사드패턴


어뎁터 패턴

C-type 충전기를 아이폰에 꽃아 충전을 하려면 C-type을 8-pin으로 바꿔주는 어뎁터 잭이 필요하다.

이처럼 어떤 클래스의 인터페이스를 클라이언트가 쓰고자하는 다른 인터페이스로 변환하여 호환성 문제를 해결하는것을 어뎁터 패턴이라고 한다.

같이 쓸수없는 클래스들을 같이 쓸수있도록 함

 

클라이언트나 어떤 클래스가 비슷한 구조의 여러 클래스를 사용해야 하지만 이 여러 클래스들이 각기 다른 인터페이스를 사용하는경우 어뎁터를 만들어 사용함

 

어뎁터 패턴 구조

image

클래스 어댑터는 보통 다중 상속을 이용하여 구현하기 때문에 자바에서는 사용할 수 없기 때문에 객체 어댑터로 설명한다.

아래 예제를 보고 나면 클래스 어댑터의 구조가 눈에 보일것이다.

하지만 자바에서도 adaptee를 상속받고 필요한 새 인터페이스를 제공하는 형태로 클래스 어댑터 형태로 구현 가능

image

클래스 어뎁터를 보면 상속으로 구현 but. 자바는 다중상속이 불가함

 

//Target or Adaptee 
public interface Duck {
          public void quack();
          public void fly();
 }

public class MallardDuck implements Duck {
          @Override
          public void quack() {
                   System.out.println("Quack");
          }
          @Override
          public void fly() {
                   System.out.println("flying");
          }

 }
//====================================================
//Target or Adaptee
public interface Turkey {
          public void gobble();
          public void fly();
 }


public class WildTurkey implements Turkey{
          @Override
          public void gobble() {
                   System.out.println("Gobble gobble");
          }  
          @Override
          public void fly() {
                   System.out.println("I'm flying a short distance");
          }
 }

이렇게 서로다른 인터페이스를 가진 구현 클래스 WildTurkey 와 MallardDuck이 있다.

 

클라이언트는 Turkey인터페이스를 Duck 인터페이스로 쓰고싶다.

Turkey인터페이스를 Duck 인터페이스로 변환하는 어뎁터를 만들어보자.

 

//어뎁터: Target: Duck , Adaptee: Turkey
public class TurkeyAdapter implements Duck {
          Turkey turkey; //has-a Turkey interface: adaptee

          public TurkeyAdapter(Turkey turkey) { //Di concrete class
                   this.turkey = turkey;
          }

          @Override
          public void quack(){ 
                   turkey.gobble(); //사용에 맞게 변환
          }

          @Override
          public void fly() {
                   turkey.fly(); //사용에 맞게 변환
          }
 }

 

클라이언트

 public class DuckTestDrive {

          public static void main(String[] args) {
                  Duck duck = new MallardDuck(); //duck
                  Turkey turkey = new WildTurkey(); //turkey 

                  Duck turkeyAdapter = new TurkeyAdapter(turkey); //turkey->duck

                  use(duck);
                  use(turkeyAdapter);
          }

          public static void use(Duck duck){ //Duck 인터페이스로 turkey 객체를 사용할수있다.
                   duck.quack();
                   duck.fly();
          }
 }

클라이언트는 Turkey인터페이스를 Duck 인터페이스로 쓸수있게 되었다.

 

어뎁터 종류

만능 어댑터: 한 클래스에 대한 여러 개의 다른 인터페이스를 제공하여 주는 adapter

두 방향 어댑터: 새 인터페이스(target)뿐만 아니라 기존 인터페이스(adaptee)도 함께 제공

public class TurkeyAdapter implements Duck, Turkey {
//새 인터페이스 변환
//기존 인터페이스 사용
}

 

정리

장점 • 어댑터 클래스는 SRP에 충실한 클래스 • 어댑터는 OCP를 제공하는 한 가지 방법임. 기존 클래스를 수정하지 않고 서비스 제공

단점 • 경우에 따라 어댑터를 만들기보다 어댑티를 바꾸는 것이 간단할 수 있음. 보통 어댑티와 클라이언 트를 모두 수정하기 힘들거나 적절하지 않을 때 사용하는 패턴임

 

파사드 패턴

파사드 패턴 구조

image

왼쪽과 같이 클라이언트들이 시스템과 복잡한 의존관계를 맺고있을때 , 오른쪽 처럼 시스템의 복잡한 구조를 아우르는 상위타입 인터페이스를 파사드라고한다.

여러 종류의 파사드를 만들어 목적에 따라 제공할 수도 있음

복잡한 시스템에 대한 단순화된 인터페이스를 제공해야 할 때 사용한다.

시스템이 변경되더라도 클라이언트와 관계를 변경할 필요가 없고 파사드만 수정하면된다.

클라이언트가 내부 복잡한 로직을 몰라도 시스템을 쉽게 사용할수있도록 한다.

보통 싱글톤으로 구현된다.

 

728x90