상현에 하루하루
개발자의 하루

퍼사드 패턴

( 업데이트: )

퍼사드 패턴(외관 패턴)은 객체지향 프로그래밍 분야에서 자주 쓰인다.

퍼사드는 클래스 라이브러리 같은 어떤 소프트웨어의 다른 커다란 코드 부분에 대한 간략화된 인터페이스를 제공하는 객체이다.

  • 퍼사드는 소프트웨어 라이브러리를 쉽게 사용할 수 있게 해준다. 또한 퍼사드는 소프트웨어 라이브러리를 쉽게 이해할 수 있게 해준다. 퍼사드는 공통적인 작업에 대해 코드를 좀 더 읽기 쉽게 해준다.
  • 퍼사드는 라이브러리를 사용하는 코드들을 좀 더 읽기 쉽게 해준다.
  • 퍼사드는 라이브러리 바깥쪽의 코드가 라이브러리의 안쪽 코드에 의존하는 일을 감소시켜준다. 대부분의 바깥쪽 코드가 퍼사드를 이용하기 떄문에 시스템을 개발하는 데 있어 유연성이 향상된다.
  • 퍼사드는 좋게 작성되지 않은 API의 집합을 하나의 좋게 작성된 API로 감싸준다.

래퍼(wrapper)가 특정 인터페이스를 주눗해야 하며, 폴리모픽 기능을 지원해야 할 경우에는 어댑터 패턴을 쓴다. 단지, 쉽고 단순한 인터페이스를 이용하고 싶을 경우에는 퍼사드를 쓴다.

사용

퍼사드의 목적은 하위 시스템이나 툴킷을 클라이언트가 쉽게 사용할 수 있도록 하는 고급 인터페이스(속성 및 메서드)를 제공하는 것입니다.

서버의 다중 계층 웹 응용 프로그램에는 서비스 계층에 대한 클라이언트인 프레젠테이션 게층이 있는 경우가 많습니다. 이 두 계층 간의 통신은 잘 정의된 API를 통해 이루어집니다. 이 API 또는 외관은 비즈니스 개체의 복잡성과 프레젠테이션 계층에서 상호 작용을 숨깁니다.

퍼사드가 사용되는 또 다른 영역은 리팩토링입니다. 클라이언트가 걱정하지 안하도 되는 혼란스럽거나 지저분한 레거시 객체 집합이 있다고 가정합니다. 이 코드를 퍼사드 뒤에 숨길 수 있습니다. 퍼사드는 필요한 것만 노출하고 더 깨끗하고 사용하기 쉬운 인터페이스를 제공합니다.

퍼사드는 종종 다른 디자인 패턴과 결합됩니다. 퍼사드 자체는 종종 싱글톤 팩토리로 구현됩니다.


예제를 활용한 이해

ex1

퍼사드 패턴은 객체에 대한 인터페이스를 제공한다. 메서드를 짧게 유지하고 하나의 메서드가 너무 많은 일을 하지 않도록 해야 하는 것이 설게상 좋은 습관

stopPropagation();
preventDefault();

두 개의 메서드가 있을 때, 다른 목적이지만 함께 호출되어야 한다. 이럴 때 함께 호출하는 퍼사드 메서드를 생성하는 것이 좋다.

var myevent = {
    ...
    stop: function(e) {
        e.preventDefault();
        e.stopPropagation();
    }
}Code language: JavaScript (javascript)

이는 설계 변경과 리팩터링 수고를 덜어준다. 객체의 API역할을 하는 퍼사드를 생성해 적용할 수 있다. 기존 객체를 완전히 교체하기 전에 최신 코드가 새로운 API를 사용하면, 최종 교체할 때 변경폭을 줄일 수 있다.

ex2

집에서 영화를 본다고 가정해보자. 집에서 영화를 한 편 보기위해서는 여라기지 해야하는 일들이 있다.

  1. 스크린을 내린다
  2. 빔을 켠다
  3. 보고싶은 영화를 재생한다
  4. 팝콘을 튀긴다
  5. 맥주를 가져온다

이와 같은 일들을 해야하고, 이들의 작업을 프로그램으로 구성하면 대략 이런 모습이 될 것이다.

screen.down();
projector.on();
movie.play();
popcorn.pop();
beer.pop();Code language: CSS (css)

자, 이제 영화를 다 보았다. 역순으로 다시 진행해줘야 한다.

이럴때 간편하게 사용할 수 있는게 퍼사드 패턴이다.

class PlayMovie {
    constructor ({ screen, projector, movie, popcorn, beeer }) {
        this.screen = screen;
        this.projector = projector;
        this.movie = movie;
        this.popcorn = popcorn;
        this.beer = beer;
    }

    play() {
        screen.down();
        projector.on();
        movie.play();
        popcorn.pop();
        beer.pop();
    }

    stop() {
        screen.up();
        projector.off();
        movie.stop();
        popcorn.off();
        beer.off();
    }
}

const screen = new Screen();
const projector = new Projector();
const movie = new Movie();
const popcorn = new Popcorn();
const beer = new Beer();

const playMovie = new PlayMovie({ screen, projector, movie, popcorn, beeer });
playMovie.play();
playMovie.stop();Code language: JavaScript (javascript)

play()stop()으로 간단하게 처리할 수 있다.

어떠한 시스템에서 일련의 복잡한 작업을 단순화하고 통합한 클래스를 만들어 퍼사드 패턴을 완성하였다. 이러한 패턴은 클라이언트와 서비스시스템이 서로 긴밀하게 연결되지 않아도 되고, 최소 지식 원칙을 지키는데에도 도움을 준다.

ex3

Mortgage객체는 예제 코드에서 퍼사드입니다. 단 하나의 메소드를 사용하여 클라이언트에 간단한 인터페이스를 제공합니다 applyFor.. 이 간단한 API는 아래에 상단한 복잡성이 있습니다.

신청자의 이름은 Mortgage 생성자 함수로 전달됩니다. 그런 다음 applyFor 요청된 대출 금액으로 메서드가 호출됩니다. 내부적으로 이 방법은 복잡하고 처리하는 데 시간이 걸릴 수 있는 3개의 개별 하위 시스템에서 서비스를 사용합니다 Bank Credit Background

여러 기준 (은행 명세서, 신용 보고서 및 범죄 배경)에 따라 신청자는 요청된 대출에 대해 승인 또는 거부 됩니다.

const Mortgage = function (name) {
    this.name = name;
}

Mortgage.prototype = {
    applyFor: function (amount) {
        // 하위 시스템
        let result = "approved";
        if (!new Bank().verify(this.name, amount)) {
            result = "denied";
        } else if (!new Credit().get(this.name)) {
            result = "denied";
        } else if (!new Background().check(this.name)) {
            result = "denied";
        }
        return `${this.name} has been ${result} for a ${amount} mortgage`;
    }
}

const Bank = function () {
    this.verify = function (name, amount) {
        // 복잡한 로직
        return true;
    }
}

const Credit = function () {
    this.get = function (name) {
        // 복잡한 로직
        return true;
    }
}

const Background = function () {
    this.check = function (name) {
        // 복잡한 로직
        return true;
    }
}

function run() {
    const mortgage = new Mortgage("Joan Templeton");
    const result = mortgage.applyFor("$100,000");

    console.log(result);
}Code language: JavaScript (javascript)