2015년 9월 10일 목요일

클래스 디자인 패턴 8. Template Method Pattern_

1. 개념잡기
  1) 의미 및 구현방법
      구체적인 내용을 작성하는 클래스단 에서 공통적인 부분을
        위로 올리고(중복을 줄임), 특징있는 업무는 상속으로
        내려서 작성하는 방법.
      상속을 가르칠때 예제로 보여지는게 바로
        템플릿 메서드 패턴이다.
      보통 2개 이상 클래스에서 공통점이 발견되면 상위
        클래스로 올리고, 약간 다른점은 오버라이드로
        구현하는 선에서 작업이 이루어진다.

  2) 참고자료
http://choipattern.blogspot.kr/2013/08/template-method.html

팩토리 메서드 패턴 (위키)


2. 소스

1> 마실거 예제
  1) 먼저 커피와 녹차 클래스를 준비하고 테스트 코드를 준비한다.
 
package products;

public class CoffeeOfNeck {
 public void preparerecipe(){
  boilWater();
  brewCoffeeGrinds();
  pourInCup();
  addSugarAndMilk();
 }

 private void addSugarAndMilk() {
  System.out.println("설탕과 우유를 추가합니다.");
 }

 private void pourInCup() {
  System.out.println("컵에 따릅니다.");
 }

 private void brewCoffeeGrinds() {
  System.out.println("필터를 통해서 커피를 우려내는 중");
 }

 private void boilWater() {
  System.out.println("물을 끓입니다.");
 }
}

 
package products;

public class GreenTeaOfNeck {
 public void preparerecipe(){
  boilWater();
  steepteaBag();
  pourInCup();
  addLemon();
 }

 private void steepteaBag() {
  System.out.println("차를 우려내는중");
 }

 private void pourInCup() {
  System.out.println("컵에 따릅니다.");
 }

 private void addLemon() {
  System.out.println("레몬을 추가합니다.");
 }

 private void boilWater() {
  System.out.println("물을 끓입니다.");
 }
}

 
package testTemplate;

import products.CoffeeOfNeck;
import products.GreenTeaOfNeck;

public class TestUnit {
 public static void main(String[] args) {
  CoffeeOfNeck cof = new CoffeeOfNeck();
  GreenTeaOfNeck green = new GreenTeaOfNeck();
  cof.preparerecipe();
  System.out.println("-------------");
  green.preparerecipe();
 }
}


1차 결과 :
물을 끓입니다.
필터를 통해서 커피를 우려내는 중
컵에 따릅니다.
설탕과 우유를 추가합니다.
-------------
물을 끓입니다.
차를 우려내는중
컵에 따릅니다.
레몬을 추가합니다.



  2) 물 끓이는 거랑 컵에 따르는건 같은일이므로
       하나의 클래스를 만들어서(SomethingDrink)
       직접구현하고 나머지2개
       메서드는 명시만 해놓습니다 (abstract)
     실행 preparerecipe() 메서드는 새로 만든 클래스에만 넣고
       이제 커피와 차에서는 새로 만든 SomethingDrink 클래스를
       상속받아 각각 2개의 메서드만 상속합니다.
     preparerecipe() 메서드는 템플릿 메서드로서 하위 클래스가
       같은 순서로 작업을 진행하도록
       강제하는 역할을 담당합니다.
     해당 메서드로만 외부에서 접근하게끔 함으로서 순서가
       바뀌는 일이 없도록 강제합니다.

 
package template;

public abstract class SomethingDrink {
 public void preparerecipe(){
  boilWater();
  brew();
  pourInCup();
  addCondiments();
 }

 protected abstract void addCondiments();
 
 protected abstract void brew();
 
 protected void pourInCup() {
  System.out.println("컵에 따릅니다.");
 }

 protected void boilWater() {
  System.out.println("물을 끓입니다.");
 }
}

 
package products;

import template.SomethingDrink;

public class CoffeeOfNeck extends SomethingDrink{
 
 @Override
 protected  void addCondiments() {
  System.out.println("설탕과 우유를 추가합니다.");
 }
 
 @Override
 protected void brew() {
  System.out.println("필터를 통해서 커피를 우려내는 중");
 }
}

 
package products;

import template.SomethingDrink;

public class GreenTeaOfNeck extends SomethingDrink{

 @Override
 protected void addCondiments() {
  System.out.println("레몬을 추가합니다.");
 }

 @Override
 protected void brew() {
  System.out.println("차를 우려내는중");
 }
}



결과 :  1) 항목과 결과가 같음.
물을 끓입니다.
필터를 통해서 커피를 우려내는 중
컵에 따릅니다.
설탕과 우유를 추가합니다.
-------------
물을 끓입니다.
레몬을 추가합니다.
컵에 따릅니다.
차를 우려내는중

2> Java Design 예제
  1) 공통 구현부를 위로 올릴 Abstract 클래스를 생성

public abstract class AbstractDisplay {
public abstract void open();
public abstract void print();
public abstract void close();

public final void dispay(){
open();
for(int i=0; i<5; i++){
print();
}
close();
}
}

  2) 이를 상속받아 abstract 메서드를 구현한 클래스들을 추가

 
public class CharDisplay extends AbstractDisplay {
 private char ch;
 
 public CharDisplay(char ch) {
  this.ch = ch;
 }

 @Override
 public void open() {
  System.out.print("<<");
 }

 @Override
 public void print() {
  System.out.print(ch);
 }

 @Override
 public void close() {
  System.out.println(">>");
 }
}




public class StringDisplay extends AbstractDisplay {
private String string;
private int width;
public StringDisplay(String string) {
this.string = string;
this.width = string.getBytes().length;
}

@Override
public void open() {
printLine();
}

@Override
public void print() {
System.out.println("|"+string + "|");
}

@Override
public void close() {
printLine();
}

private void printLine() {
System.out.print("+");
for(int i=0; i<width; i++){
System.out.print("-");
}
System.out.println("+");
}
}


  3) 이를 테스트 하는 테스트 코드 작성

 
public class MainTest {
 public static void main(String[] args) {
  AbstractDisplay d1 = new CharDisplay('H');
  AbstractDisplay d2 = new StringDisplay("Hello, world.");
  AbstractDisplay d3 = new StringDisplay("How are you");
  
  d1.dispay();
  d2.dispay();
  d3.dispay();
 }
}


결과 : 
<<HHHHH>>
+-------------+
|Hello, world.|
|Hello, world.|
|Hello, world.|
|Hello, world.|
|Hello, world.|
+-------------+
+-----------+
|How are you|
|How are you|
|How are you|
|How are you|
|How are you|
+-----------+


3. 다이어그램

  3) 다이어그램
      역시 하단 링크를 참고바랍니다.
http://asuraiv.blogspot.kr/2014/07/template-method-pattern-1_9.html


4. 관련 패턴
  1) Factory Method
      같은 방향으로 instance를 생성에 응용한 예가
       Factory Method 패턴입니다.

  2) Stratege 패턴
      Template 를 구현후 구현 좀더 유연한 설계를 진행한게 바로
      비슷한 필요에서 시작한게 Stratege 패턴입니다. 여기서는
      다른 방법, 다른 방향으로 같은 기능을 구현합니다.
      좀더 잘게 쪼개서 확장성을 염두해둔 설계를 지향합니다.

댓글 없음:

댓글 쓰기