4.    The Builder Pattern

사용자 삽입 이미지

앞에서 이미Factory패턴이 아규먼트에서 생성 메소드에 전달되는 데이터의 내용에 따라 몇 가지의 서로 다른 서브 클래스들 중 한 가지를 반환하는 것을 알아보았다.그러나 사용자가 원하는 내용은 단순히 연산 알고리즘이 아닌,사용자가 표현해야 하는 데이터의 내용에 따라 달라지는 전체 사용자 인터페이스일 경우도 있을 것 이다.이것에 대한 전형적인 예에는 전자 우편 주소록이 있다.아마도 사용자들은 자신의 주소록에 특정 그룹이나 개인별로 작성된 데이터들을 갖고 있을 것이다.그리고 개인별이나 화면별로 이름과 성,회사명,전자 우편 주소,전화 번호를 기록할 공간을 확보할 수 있도록 해당 주소록의 출력 내용을 변경하고 싶을 것이다.

 

반면 특정 그룹별 주소 페이지를 출력하는 경우에는 해당 그룹의 이름,분류목적,구성원 리스트와 해당 구성원별로 전자 우편 주소를 나타내고 싶을 것이다.사용자는 특정 인물의 이름을 클릭하여 해당 인물에 대한 정보를 출력하거나 특정 그룹의 이름을 클릭하여 해당 그룹에 대한 정보를 얻게 된다.여기에서 모든 전자 우편 주소가Address객체에 저장되어People클래스와Group클래스가 위의 그림과 같이 파생된다고 가정해 보자 클릭하는Address객체의 종류에 따라 해당 객체의 성격에 맞춘 서로 다른 출력 결과를 보려고 할 것이다.이것을 단지Factory패턴이라는 용어로 제한하기는 무리이다.왜냐하면 반환된 객체들이 단순히 기본 출력 객체의 상속 대상이 아닌 출력 객체의 서로 다른 조합으로 구성된 완전히 다른 사용자 인터페이스이기 때문이다. Builder패턴은 데이터의 내용에 따라 여러 가지 방식으로 많은 수의 객체들을 조합한다.게다가 자바 언어는 출력 메소드에서 데이터를 추출하여 말끔하게 객체화 할 수 있는 몇 가지 언어 중 하나이기 때문에Builder패턴을 구현하는데 이상적인 도구이다.

 

구조

사용자 삽입 이미지

 

역할

사용자 삽입 이미지
      Builder의 역할

Builder는 인스턴스를 작성하기 위한 인터페이스(API)를 결정하는 역할을 수행합니다.인스턴스의 각 부분을 만들기 위한 메소드와 마지막 결과를 얻기 위한 메소드가 준비됩니다.

 

사용자 삽입 이미지
      ConcreteBuilder의 역할

ConcreteBuilderBuilder의 인터페이스(API)를 구현하고 있는 클래스입니다.실제로 인스턴스를 작성할 때 호출되는 메소드가 여기에 정의됩니다.

 

사용자 삽입 이미지
      Director의 역할

DirectorBuilder의 인스터스(API)를 사용해서 인스턴스를 생성합니다. ConcreteBuilder에 의존한 프로그래밍은 하지 않습니다. ConcreteBuilder역할과 상관없이 올바로 기능하도록Builder의 메소드만 사용합니다.

 

 

의도

반환된 객체들이 단순히 기본 출력 객체의 상속 대상이 아닌 출력 객체의 서로 다른 조합으로 구성된 완전히 다른 사용자 인터페이스 일 때 사용

 

적용시기

Builder패턴은 다수의 메소드와 객체로 구성된 클래스를 반환한다는 점에서Abstract Factory v패턴과 약간 비슷하다.그러나Abstract Factory패턴이 해당 그룹에 대한 클래스나 관련된 클래스를 반환하는 반면, Builder패턴은 제시된 데이터의 내용에 따라 단계별로 복잡한 객체를 생성한다는 것이 가장 큰 차이다.

 

효과

1. Builder패턴은 구현 제품의 내부적인 표현 방식을 다양하게 변형할 수 있도록 한다.또한 해당 제품이 어떻게 조합되어 있는가에 대한 내용은 자세히 나타내지 않는다.

 

2.각각의 특정 빌더는 다른 요소들뿐만 아니라 프로그램의 나머지 부분과도 무관하다.이것은 모듈화를 높이며,상대적으로 단순한 다른 빌더들을 추가할 수 있게 한다.

 

3.데이터의 내용에 따라 각각의 빌더들이 단계별로 최종제품을 만들어나가기 때문에 개발자는 빌더가 생성하는 각각의 최종 결과물에 대한 제어를 강화하게 된다.

 

예제소스

사용자 삽입 이미지

 

다음은 예제소스이다.

public abstract class Builder {

   public abstract void makeTitle(String title);

   public abstract void makeString(String str);

   public abstract void makeItems(String[] items);

   public abstract Object getResult();

}

 

import java.io.*;

 

public class HTMLBuilder extends Builder {

 

   private String filename;

   private PrintWriter writer;

   

   public void makeTitle(String title) {

       filename = title + ".html";

       try {

           writer = new PrintWriter(new FileWriter(filename));

       } catch (IOException e) {

           e.printStackTrace();

       }

       writer.println("<html><head><title>" + title + "</title></head><body>");

       writer.println("<h1>" + title + "</h1>");

   }

   

   public void makeString(String str) {

       writer.println("<p>" + str + "</p>");

   }

   

   public void makeItems(String[] items) {

       writer.println("<ul>");

       for (int i = 0; i < items.length; i++) {

           writer.println("<li>" + items[i] + "</li>");

       }

       writer.println("</ul>");

   }

   

   public Object getResult() {

       writer.println("</body></html>");

       writer.close();

       return (new File(filename)).getAbsolutePath();

   }

}

 

public class TextBuilder extends Builder {

 

   private StringBuffer buffer = new StringBuffer();

   

   public void makeTitle(String title) {

       buffer.append("==============================\n");

       buffer.append("" + title + "\n");

       buffer.append("\n");

   }

   

   public void makeString(String str) {

       buffer.append('■' + str + "\n");

       buffer.append("\n");

   }

   

   public void makeItems(String[] items) {

       for (int i = 0; i < items.length; i++) {

           buffer.append("●" + items[i] + "\n");

       }

       buffer.append("\n");

   }

   

   public Object getResult() {

       buffer.append("==============================\n");

       return buffer.toString();

   }

}

 

public class Director {

   private Builder builder;

   public Director(Builder builder) {

       this.builder = builder;

   }

   

   public Object construct() {

       builder.makeTitle("Greeting");

       builder.makeString("아침과 낮에");

       builder.makeItems(new String[]{

           "좋은 아침입니다.",

           "안녕하세요",

       });

       builder.makeString("밤에");

       builder.makeItems(new String[]{

           "안녕하세요",

           "안녕히 주무세요",

           "안녕히 계세요",

       });

       return builder.getResult();

   }

}

 

public class mainClass {

 

   public static void main(String[] args) {

       if (args.length != 1) {

           System.out.println(") java mainClass [html or text]");

           System.exit(0);

       }

       mainClass main = new mainClass();

       main.exec(args[0]);

   }

   

   public Director getDirector(String mode) {

       if(mode.toUpperCase().equals("TEXT"))

           return new Director(new TextBuilder());

       else if(mode.toUpperCase().equals("HTML"))

           return new Director(new HTMLBuilder());

       else

           return null;

   }

   

   public void exec(String mode) {

       System.out.println(getDirector(mode).construct());

   }

   

}

 

관련패턴

사용자 삽입 이미지
      Template Method pattern

사용자 삽입 이미지
      Composite

사용자 삽입 이미지
      Facade


Posted by 영웅기삼
,