글 검색

공개된 글의 제목과 본문을 검색합니다.

    닫기 Esc

    템플릿 메소드 패턴#

    템플릿 메소드 패턴은 알고리즘의 골격을 정의합니다.

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

    후크 활용하기#

    후크가 있으면 해당 메소드를 오버라이드 할 수 있고, 그냥 넘어갈 수도 있음

    java
    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");
    		}
    }
    • prepareRecipe() 메소드를 통해서 제조법이 동일하다는 사실을 알 수 있음

    prepareRecipe 메소드 추상화 하기#

    java
    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("레몬을 추가하는 중");
    		}
    }
    • 물을 끓인다와 만들어진 음료를 겁에 따른다는 동일한 행동이기 때문에 추상화 가능
    • 우려내는 행위와 추가하는 행위는 동일하기 때문에 추상화 해서 서브클래스에게 구현을 위임
    • 알고리즘이 한 군데 모여있으므로 한 부분만 고치면 됨
    전체 글 둘러보기