[디자인 패턴] Chapter 15. Facade 패턴

3 분 소요

01. Facade 패턴

  • 객체 지향 프로그램은 많은 클래스와 객체들로 이루어지고, 서로 복잡한 관련을 맺고 있다
    • 이들을 모두 이해하고 제어하기가 힘들다
    • 이들을 제어하기 위한 ‘창구’ 역할을 담당하는 클래스를 만들어보자
  • facade: 건물의 정면(불어에서 따옴)

  • 복잡한 내부는 숨기고, 높은 레벨의 인터페이스(API)를 외부에 제공한다

02. 예제 프로그램

  • 사용자의 웹페이지를 작성하는 프로그램
  • Facade 패턴의 예를 보이기 위해서는 “복잡하게 얽혀 있는 많은 클래스”가 필요하다
    • 그러나, 본 예제에서는 3개의 클래스로 구성된 시스템을 생각한다
패키지 이름 해설
pagemaker Database 메일 주소로부터 사용자명을 얻는 클래스
pagemaker HtmlWriter HTML 파일을 작성하는 클래스
pagemaker PageMaker 메일 주소로부터 사용자의 웹 페이지를 작성하는 클래스
Anonymous Main 동작 테스트용 클래스

PageMaker가 Facade 역할(High-level API 제공)

  • 만들고자 하는 웹페이지

  • 클래스 다이어그램

  • 소스파일 디렉토리 구조

Database 클래스

  • 데이터베이스 명을 지정하면, 그것에 해당하는 Properties를 작성하는 클래스
  • getProperties(String dbname)
    • Properties 인스턴스를 생성한 후, dbname.txt 파일로부터 여러 가지 속성 값을 읽어 들여 이를 리턴하는 메소드
    • Properties 클래스
      • key와 value 쌍으로 되어 있는 속성의 집합을 유지하는 클래스
package pagemaker;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class Database {
  private Database() {
  }
  public static Properties getProperties(String dbname) {
    String filename = dbname + ".txt";
    Properties prop = new Properties();
    try {
      prop.load(new FileInputStream(filename));
    } catch (IOException e) {
      System.out.println("Warning: " + filename + "is not found.");
    }
    return prop;
  }
}

maildata.txt

  • 속성을 저장하고 있는 파일
  • 형식: key=value

HtmlWriter 클래스

  • 간단한 웹페이지를 작성하는 클래스
  • 생성자
    • Writer 타입의 인스턴스를 받아들여, 멤버 변수인 writer에 할당한다
    • title(): 헤더 및 타이틀에 대한 html 태그를 작성하는 메소드
    • paragraph(): 문단을 작성하는 메소드
    • link(): 하이퍼링크를 만드는 메소드
    • mailto(): 메일주소 링크를 만드는 메소드
    • close(): HTML 출력을 끝내는 메소드
    • 제약조건: title() 메소드가 제일 먼저 호출되어야 한다
      • 이 조건은, 창구가 되는 PageMaker 클래스에 표현되어 있다
package pagemaker;

import java.io.Writer;
import java.io.IOException;

public class HtmlWriter {
  private Writer writer;
  public HtmlWriter(Writer writer) {
    this.writer = writer;
  }
  public void title(String title) throws IOException {
    writer.write("<html>");
    writer.write("<head>");
    writer.write("<title>" + title  + "</title>");
    writer.write("<body>\n");
    writer.write("<h1>" + title + "</h1>\n");
  }
  public void paragraph(String msg) throws IOException {
    writer.write("<p>" + msg + "</p>\n");
  }
  public void link(String href, String caption) throws IOException {
    paragraph("<a href=\"" + href + "\">" + caption + "</a>");
  }
  public void mailto(String mailaddr, String username) throws IOException {
    link("mailto:" + mailaddr, username);
  }
  public void close() throws IOException {
    writer.write("</body>");
    writer.write("</html>\n");
    writer.close();
  }
}

PageMaker 클래스

  • Database 클래스와 HtmlWriter 클래스를 조합하여, 지정된 사용자의 웹 페이지를 작성하기 위한 클래스
  • makeWelcomePage(String mailaddr, String filename)
    • Database 클래스를 이용해서
      • “maildata.txt” 파일로부터 속성 집합을 얻은 후, 속성 중에서 입력 인자로 들어온 mailaddr를 key로 하여 해당 value를 얻는다
    • HtmlWriter 클래스의 메소드들을 이용해서
      • 입력 인자로 들어온 filename 파일에 HTML 문서를 작성한다
package pagemaker;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class PageMaker {
  private PageMaker() {
  }
  public static void makeWelcomePage(String mailaddr, String filename) {
    try {
      Properties mailprop = Database.getProperties("maildata");
      String username = mailprop.getProperty(mailaddr);
      HtmlWriter writer = new HtmlWriter(new FileWriter(filename));
      writer.title("Welcome to " + username + "'s page!");
      writer.paragraph("메일을 기다리고 있습니다.");
      writer.mailto(mailaddr, username);
      writer.close();
      System.out.println(filename + " is created for " + mailaddr + " (" + username + ")");
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

Main 클래스

  • pagemaker 패키지의 PageMaker 클래스를 이용해서, eliotjang2@gmail.com를 key로 한 value를 가지고 “welcome.html” 이라는 HTML 문서를 완성한다
  • Main 클래스는, Database나 HtmlWriter 클래스를 직접 이용하지 않고, high-level API를 제공하는 PageMaker의 메소드만을 사용하여 원하는 작업을 한다
import pagemaker.PageMaker;

public class Main {
  public static void main(String[] args) {
    PageMaker.makeWelcomePage("eliotjang2@gmail.com", "welcome.html");
  }
}

03. Facade(정면)의 역할

  • 시스템을 구성하는 많은 역할의 ‘간단한 창구’가 되는 역할을 한다
  • 높은 레벨에서 간단한 인터페이스를 시스템 외부에 제공한다
  • 예제에서는 PageMaker 클래스가 해당됨

  • 시스템을 구성하고 있는 그 밖의 많은 역할
    • Facade 역할로부터 호출되는, 시스템의 구성하는 많은 클래스들
    • 이들은, Facade 역할은 의식하지 않는다
    • 예제에서는, Database와 HtmlWriter 클래스가 해당됨
  • Client(의뢰자)의 역할
    • Facade 패턴을 이용하는 역할
    • 예제에서는, Main 클래스가 해당됨
  • 클래스 다이어그램

04. 독자의 사고를 넓혀주는 힌트

  • Facade 역할이 하는 일은 무엇일까
    • 복잡한 것을 단순하게 보여준다
      • 내부에서 작동하고 있는 많은 클래스들의 관계나 사용법을 의식하지 않도록 해 주는 역할
      • 외부에 보이는 API를 적게 해 주고 단순하게 해 준다
  • 재귀적인 Facade 패턴의 적용
    • 여러 패키지들이 있고, 패키지마다 Facade 역할이 정의되어 있다면, 이들 Facade 들에 대한 Facade 역할을 재귀적으로 정의할 수 있다

05. 관련 패턴

  • Abstract Factory 패턴 (8장)
  • Singleton 패턴 (5장)
  • Mediator 패턴 (16장)

06. 요약

  • 복잡한 시스템에 대한 간단한 창구의 역할을 하는 Facade 패턴

연습 문제

  • 15-1
    • 외부에서 절대로 Database 클래스나 HtmlWriter 클래스를 이용할 수 없도록 하려면, 어떻게 예제 프로그램을 변경해야 하는가?
  • 15-2
    • maildata.txt의 내용을 이용해서, 메일 주소 링크 만을 포함하는 파일을 만드는 makeLinkPage() 메소드를 PageMaker 클래스에 추가하기
      • 예: 그림 15-7, 15-8, 15-9

댓글남기기