도서 요약 / / 2023. 2. 19. 20:10

디자인 패턴 - 파사드(facade) 패턴

udemy 강좌(Java Design Patterns & SOLID Design Principles)를 정리한 내용이다.

https://www.udemy.com/course/design-patterns-in-java-concepts-hands-on-projects/learn/lecture/9604610?start=0#overview


파사드는 무엇인가?

파사드 디자인 패턴은 구조적 디자인 패턴이며 이해하기 쉽고 구현하기 쉬우며 특히 레거시 코드와 작업할 때 많은 도움이 된다.

  • 클라이언트는 서브시스템에서 결과를 가져오기 위해 많은 인터페이스와 클래스들과 상호 작용해야 한다. 그래서 클라이언트는 인터페이스&클래스와 강하게 결합되어 있다. 파사드가 이러한 문제를 해결해 준다.
  • 파사드는 서브시스템에 간단하고 통합된 인터페이스를 제공한다. 클라이언트는 동일한 결과를 얻기 위해 단지 파사드와만 상호통신을 한다.
  • 파사드는 다른 클래스로 향하는 하나의 메소드만을 나타내지는 않는다.

UML

파사드 구현

  • 파사드를 처리할 클래스를 생성하면서 시작
    • 서브시스템이 사용할 전반적인 유스케이스/작업들을 정의한다.
    • 각 유스케이스 혹은 작업을 노출할 메소드를 작성한다.
    • 이 메소드는 서브시스템의 다른 클래스와 동작하는 것을 신경써야 한다.

예제: UML

이 예제에서, 이메일 서브시스템을 만들 것이다. 서브시스템에서 실제 이메일을 발송하지는 않을 것이고 이메일 전송 시 일반적으로 사용할 클래스들을 나타낸다. 이 이메일 서브시스템는 Mailer, Email, EmailBuilder, Stationary와 같은 클래스가 있다.

만일 클라이언트에서 서브시스템에서 Facade가 없이 이메일을 전송하려면 클라이언트 코드는 이러한 모든 클래스와 차례로 상호통신해야만 할 것이다. 그리고 이것은 특정 코드가 이런 모든 클래스와 강하게 결합되어 있다는 것을 나타낸다.

이러한 문제를 해결하기 위해 유스케이스와 통신하는 단순한 메소드만을 가지는 EmailFacade를 만들 것이고 이메일 시스템에서 구현될 것이고 유스케이스가 이메일을 전송할 것이다. 이 메소드는 단순히 Order 클래스 객체만 받게 될 것이고 이메일이 잘 전송되었는지에 대해서만 알려줄 것이다.

클라이언트는 EmailFacade하고만 통신한다. 서브시스템 내부에서 어떻게 사용되고 있는지 알지 못한다.

Java 구현

public class Client {

    public static void main(String[] args) {
        Order order = new Order("101", 99.99);

        boolean result = sendOrderEmailWithoutFacade(order);

        System.out.println("Order Email "+ (result?"sent!":"NOT sent..."));

    }

    private static boolean sendOrderEmailWithoutFacade(Order order) {
        Template template = TemplateFactory.createTemplateFor(TemplateType.Email);
        Stationary stationary = StationaryFactory.createStationary();
        Email email = Email.getBuilder()
                      .withTemplate(template)
                      .withStationary(stationary)
                      .forObject(order)
                      .build();
        Mailer mailer = Mailer.getMailer();
        return mailer.send(email);
    }

}

우선 이메일을 전송하는 클라이언트 코드를 보자. 많은 클래스와 상호작용하는 클라이언트 메소드가 있다.
여기서 많은 클래스와 강하게 결합되어 있다는 사실을 알 수 있다.

이러한 문제를 해결하기 위해 EmailFacade를 구현해보자.

// Facade는 클라이언트 코드가 사용할 간단한 메소드이다.
public class EmailFacade {

    public boolean sendOrderEmail(Order order) {
        Template template = TemplateFactory.createTemplateFor(TemplateType.Email);
        Stationary stationary = StationaryFactory.createStationary();
        Email email = Email.getBuilder()
                      .withTemplate(template)
                      .withStationary(stationary)
                      .forObject(order)
                      .build();
        Mailer mailer = Mailer.getMailer();
        return mailer.send(email);
    }
}

이렇게 함으로써 클라이언트가 서브시스템을 사용하게 쉽게 만든다.

public class Client {

    public static void main(String[] args) {
        Order order = new Order("101", 99.99);
        EmailFacade facade = new EmailFacade();

        boolean result = facade.sendOrderEmail(order);

        System.out.println("Order Email "+ (result?"sent!":"NOT sent..."));

    }
}

클라이언트 코드를 보면 기존에 작성되었던 메소드는 삭제하고 EmailFacade를 통해 접근하게 한다.

이제 EmailFacade만 통신하고 있다는 사실을 알 수 있다.

구현 고려사항

  • 파사드는 서브시스템의 복잡도를 낮춰야 하고 사용 가능한 인터페이스만을 제공해야 한다.
  • 파사드에 대한 인터페이스 혹은 추상 클래스를 가질수도 있고 클라이언트는 다른 서브시스템 구현부를 호출하기 위해 다른 서브클래스를 사용할 수도 있다.
  • 파사드는 서브시스템에서 일반적인 클래스 사용을 대체하는 것이 아니다. 그것들(서브시스템)은 여전히 파사드 외부에서 사용될 수도 있다. 서브시스템 클래스를 구현할 때는 클라이언트에서 파사드를 사용한다고 가정해서는 안된다.

디자인 고려사항

  • 파사드는 의존성을 단순화시키기 위한 좋은 솔루션이다. 서브시스템 간 결합도를 낮춰준다.
  • 클라이언트 코드와 특정 서브시스템 클래스와의 결합도가 유일한 관심사이고 파사드에서 제공되는 단순함히 중요한 요소가 아니라면 파사드 대신 추상 팩토리 패턴을 사용할 수도 있다.

위험요소

  • 패턴 그 자체에 단점은 없지만 파사드가 필요하다는 것은 API 디자인을 다시 한번 살펴볼 필요가 있다는 것을 나타낸다.
  • 과용되거나 잘못 사용되고 설계된 API를 부적절하게 숨길 수도 있다. 일반적으로 잘못 사용되는 경우는 관련있는 메소드를 엮어서 사용하는 것이다. 그래서 그런 경우는 코드리뷰 시 검토될 수 있다.



반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유