////
Search

8장 - 템플릿 메소드 패턴

Created
2022/09/03 11:30
Tags
디자인패턴

템플릿 메소드 패턴

템플릿 메소드 패턴은 알고리즘의 골격을 정의합니다.
템플릿 메소드를 사용하면 알고리즘의 일부 탄계를 서브클래스에서 구현가능
알고리즘의 구조는 그대로 유지하면서 알고리즘의 특정 단계를 서브클래스에서 재정의 가능
후크는 추상 클래스에서 선언되지만 기본적인 내용만 구현되어 있거나 아무 코드도 들어있지 않은 메소드
서브클래스는 다양한 위치에서 알고리즘에 끼어들 수 있음
물론 그냥 무시하고 넘어갈 수 있음

후크 활용하기

후크가 있으면 해당 메소드를 오버라이드 할 수 있고, 그냥 넘어갈 수도 있음
public abstract class CaffeineBeverageWithHook { final void prepareRecipe() { boilWater(); brew(); pourInCup(); // 후크 메서드를 통해서 작동 가능 if (customerWantsCondiments()) { addCondiments(); } } abstract void brew(); abstract void addCondiments(); void boilWater() { System.out.println("Boiling water"); } void pourInCup() { System.out.println("Pouring into cup"); } boolean customerWantsCondiments() { return true; } }
Java
복사
public class CoffeeWithHook extends CaffeineBeverageWithHook { public void brew() { System.out.println("필터로 커피를 우려내는 중"); } public void addCondiments() { System.out.println("우유와 설탕을 추가하는 중"); } public boolean customerWantsCondiments() { String answer = getUserInput(); if (answer.toLowerCase().startsWith("y")) { return true; } else { return false; } } private String getUserInput() { String answer = null; System.out.print("커피에 우유와 설탕을 넣을까요? (y/n)? "); BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); try { answer = in.readLine(); } catch (IOException ioe) { System.err.println("IO 오류"); } if (answer == null) { return "no"; } return answer; } }
Java
복사

할리우드 원칙

먼저 연락하지 마세요. 저희가 연락 드리겠습니다.
할리우드 원칙을 활용하면 의존성 부패를 방지할 수 있음
어떤 고수준 구성 요소가 저수준 구성요소에 의존하고, 그 저수준 구성요소는 다시 고수준 구성요소에 의존하고, 그 고수준 구성요소… 무한 반복
의존성이 복잡하게 꼬여 있는 상황을 의존성이 부패했다고 부름
이렇게 의존성이 부패했다면 시스템 디자인이 어떤 식으로 되어 있는지 아무도 알아볼 수 없음
저수준 구성요소가 시스템에 접속할 수 있지만 언제, 어떻게 그 구성 요소를 사용하지는 고수준 구성 요소가 결정함

할리우드 원칙과 템플릿 메소드 패턴

스타버즈 카페에서의 예시

커피를 만드는 방법과 홍차를 만드는 방법이 거의 동일함
public class Coffee { void prepareRecipe() { boilWater(); brewCoffeeGrinds(); pourInCup(); addSugarAndMilk(); } public void boilWater() { System.out.println("Boiling water"); } public void brewCoffeeGrinds() { System.out.println("Dripping Coffee through filter"); } public void pourInCup() { System.out.println("Pouring into cup"); } public void addSugarAndMilk() { System.out.println("Adding Sugar and Milk"); } }
Java
복사
public class Tea { void prepareRecipe() { boilWater(); steepTeaBag(); pourInCup(); addLemon(); } public void boilWater() { System.out.println("Boiling water"); } public void steepTeaBag() { System.out.println("Steeping the tea"); } public void addLemon() { System.out.println("Adding Lemon"); } public void pourInCup() { System.out.println("Pouring into cup"); } }
Java
복사
prepareRecipe() 메소드를 통해서 제조법이 동일하다는 사실을 알 수 있음

prepareRecipe 메소드 추상화 하기

public abstract class CaffeineBeverage { final void prepareRecipe() { boilWater(); brew(); pourInCup(); addCondiments(); } abstract void brew(); abstract void addCondiments(); void boilWater() { System.out.println("물 끊이는 중"); } void pourInCup() { System.out.println("컵에 따르는 중"); } }
Java
복사
public class Coffee extends CaffeineBeverage { public void brew() { System.out.println("필터로 커피를 우려내는 중"); } public void addCondiments() { System.out.println("설탕과 우유를 추가하는 중"); } }
Java
복사
public class Tea extends CaffeineBeverage { public void brew() { System.out.println("찻잎을 우려내는 중"); } public void addCondiments() { System.out.println("레몬을 추가하는 중"); } }
Java
복사
물을 끓인다와 만들어진 음료를 겁에 따른다는 동일한 행동이기 때문에 추상화 가능
우려내는 행위와 추가하는 행위는 동일하기 때문에 추상화 해서 서브클래스에게 구현을 위임
알고리즘이 한 군데 모여있으므로 한 부분만 고치면 됨