포스트

[Structural Pattern] 퍼사드 패턴 (Facade Pattern)

Design Pattern / Structural Pattern

퍼사드 패턴의 정의와 해당 디자인 패턴의 예제 코드를 통한 이해 및 설명 정리

개념

  • 사용하기 복잡한 클래스 라이브러리에 대해 사용하기 편하게 간편한 인터페이스(API)를 구성하기 위한 구조 패턴

    • 예를 들면, 교제를 보고 필기노트에 재정리를 하듯이 클래스를 재정리하는 행위로 보면 됨
  • 프로그램이 업데이트를 하면서 버전이 올라갈수록 많은 클래스들이 만들어져 점점 복잡해지는 상황에 놓이게 되는데, 이러한 거대한 솔루션을 구성하려면 상호 관련된 많은 클래스들을 적절히 제어해야 할 필요성이 있으며, 이때 이 처리를 개별적으로 제어하는 것이 아닌 일종의 ‘창구’를 준비하여 중계할 수 있도록 구성하는 과정

    facade_exmaple

    고객은 복잡한 절차 지식없이 고객센터(창구)에 요구만 하면 결과를 얻음

  • 정리하면, 퍼사드 패턴은 복잡하게 얽혀있는 것을 정리해서 사용하기 편한 인터페이스를 고객에게 제공한다고 보면 되며, 고객은 복잡한 시스템을 알 필요없이 시스템의 외부에 대해서 단순한 인터페이스를 이용하기만 하면 됨

패턴 구조

facade

  • Facade

    • SubSystem 기능을 편리하게 사용할 수 있도록 하기 위해 여러 시스템과 상호 작용하는 복잡한 로직을 재정리해서 높은 레벨의 인터페이스를 구성

    • Facade 역할은 SubSystem의 많은 역할에 대해 ‘단순한 창구’가 됨

    • ClientSubSystem이 서로 긴밀하게 연결되지 않도록 함

    • 반드시 한 개만 존재해야 한다는 규칙은 없으며, 연관되지 않은 기능이 있다면 얼마든지 Facade를 별도로 분리해서 사용할 수 있음

      • 다른 Facade에서 사용할 수도 있으며, Client에서 직접 접근도 가능
  • SubSystem

    • 수십 가지의 라이브러리 혹은 클래스들
  • Client

    • SubSystem에 직접 접근하는 대신 Facade를 사용

예제 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// DBMS에 저장된 데이터를 나타내는 클래스
class Row {
  private name: string;
  private birthday: string;
  private email: string;

  constructor(name: string, birthday: string, email: string) {
    this.name = name;
    this.birthday = birthday;
    this.email = email;
  }

  public getName(): string {
    return this.name;
  }

  public getBirthday(): string {
    return this.birthday;
  }

  public getEmail(): string {
    return this.email;
  }
}

class DBMS {
  private db = new Map<string, Row>();

  public put(name: string, row: Row): void {
    this.db.set(name, row);
    // Java 코드에서는 put
  }

  // DB에 쿼리를 날려 결과를 받아오는 메소드
  public query(name: string) {
    try {
      setTimeout(() => {}, 1000);
    } catch (e) {}

    return this.db.get(name.toLowerCase());
  }
}

class Caches {
  private caches = new Map<string, Row>();

  public put(row: Row): void {
    this.caches.set(row.getName(), row);
  }

  public get(name: string) {
    return this.caches.get(name);
  }
}

class Message {
  private row: Row;

  constructor(row: Row) {
    this.row = row;
  }

  public makeName(): string {
    return 'Name : "' + this.row.getName() + '"';
  }

  public makeBirthday(): string {
    return "Birthday : " + this.row.getBirthday();
  }

  public makeEmail(): string {
    return "Email : " + this.row.getEmail();
  }
}

export { Caches, DBMS, Message, Row };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import { Caches, DBMS, Message, Row } from "./libraries";

export class Facade {
  private dbms: DBMS = new DBMS();
  private caches: Caches = new Caches();

  /**
   * 1. 생성 & 등록
   */
  public insert(): void {
    this.dbms.put(
      "한형진",
      new Row("한형진", "1996-12-10", "han1210_36@naver.com")
    );
    this.dbms.put(
      "홍길동",
      new Row("홍길동", "1890-08-14", "honggildong@naver.com")
    );
    this.dbms.put(
      "임꺽정",
      new Row("임꺽정", "1820-11-02", "han1210_36@naver.com")
    );
  }

  /**
   * 1. 캐시에 row가 없다면 DB에 해당 데이터를 조회하고 row에 저장 후, 캐시에 저장
   * 2. DB에 이름으로 조회된 값이 있으면 정상적으로 값 출력
   * 3. 캐시, DB에 조회된 값이 없다면 에러 문구 출력
   */
  public run(name: string): void {
    let row = this.caches.get(name);

    if (!row) {
      row = this.dbms.query(name);

      if (row) {
        this.caches.put(row);
      }
    }

    if (row) {
      const message: Message = new Message(row);

      console.log(message.makeName());
      console.log(message.makeBirthday());
      console.log(message.makeEmail());
    } else {
      console.log(name + "의 데이터가 DB에 존재하지 않습니다.");
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { Facade } from "./facade";

class Client {
  public main(name: string, _args?: string[]): void {
    const facade: Facade = new Facade();

    facade.insert();
    facade.run(name);
  }
}

const client_hhj = new Client();
const name_hhj = "한형진";
client_hhj.main(name_hhj);
console.log("");

// Name : "한형진"
// Birthday : 1996-12-10
// Email : han1210_36@naver.com

const client_hgd = new Client();
const name_hgd = "홍길동";
client_hgd.main(name_hgd);
console.log("");

// Name : "홍길동"
// Birthday : 1890-08-14
// Email : honggildong@naver.com

const client_nobody = new Client();
const name_nobody = "누군가";
client_nobody.main(name_nobody);
console.log("");

// 누군가의 데이터가 DB에 존재하지 않습니다.

참고한 출처 사이트

Refactoring GURU

Inpa Dev Blog (디자인 패턴)

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.