해당 포스팅은 한빛 미디어 헤드퍼스트 디자인 패턴(에릭 프리먼, 엘리자베스 롭슨 저)를 통해 공부한 내용을 정리한 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
좋은 프로그래머는 자기 두뇌를 사용한다. 그러나 좋은 가이드라인은 모든 케이스를 고려해야만 하는 노력을 줄여준다.
(Francis Glassborow, 개발자)
Coffee 클래스와 Tea 클래스 만들기
- 커피와 홍차 만드는 방법은 비슷.
- 비슷한 클래스는 공통된 부분을 추상화해서 베이스 클래스로 만들면 좋은 방법
- 추상화 클래스 적용.
- Coffee 클래스에서도 Tea 클래스에서도 추상화 가능한 메소드를 추가
- brewCoffeeGrinds(), steepTeaBag() 의 역할이 비슷
- addSugarAndMilk(), addLemon()의 역할이 비슷
- 각각 brew()와 addCondiments()로 추상화
- 일반화를 최대한 적용. ⇒ CaffeinBeverage 클래스에 반영
- 일부 메서드를 서브 클래스에 의존 ⇒ 각각의 brew()와 addCondiments()를 추상화
Template Method Pattern
- prepareRecipe()는 템플릿 메소드
- 메소드이자 카페인 음료수를 만드는 알고리즘의 템플릿
- 이전 코드
- 음료 코드 각자가 알고리즘 수행.
- 중복, 분산 코드가 많음.
- 알고리즘이 바뀌면 수정해야 할 부분이 여러군데임.
- 템플릿 메소드 적용 코드
- 알고리즘을 CaffeineBeverage가 독점
- 서브 클래스에서 코드를 재사용 가능.
- 다른 음료도 쉽게 추가할 수 있는 알고리즘 제공. => 알고리즘의 템플릿 만들기
💡 템플릿 메소드
알고리즘의 골격을 정의. 템플릿 메소드를 사용하면 알고리즘의 일부 단계를 서브 클래스에서 구현할 수 있으며, 알고리즘의 구조는 그대로 유지하면서 알고리즘의 특정 단계를 서브 클래스에서 재정의.
Example
public abstract class CaffeineBeverage {
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
abstract void brew();
abstract void addCondiments();
public void pourInCup() {
System.out.println("컵에 따르는 중");
}
public void boilWater() {
System.out.println("물 끓이는 중");
}
}
public class Coffee extends CaffeineBeverage{
@Override
public void brew() {
System.out.println("필터로 커피 우려내는 중");
}
@Override
public void addCondiments() {
System.out.println("설탕과 우유를 추가하는 중");
}
}
public class Tea extends CaffeineBeverage{
@Override
public void brew() {
System.out.println("찻잎을 우려내는 중");
}
@Override
public void addCondiments() {
System.out.println("레몬을 추가하는 중");
}
}
hook
- 기본적으로 아무것도 하지 않는 구상 메소드를 정의.
- 서브 클래스에서 오버라이드할 수도 있고 아닐 수도 있음.
- 서브 클래스에서 메소드를 커스텀해서 사용할 수 있음.
public class CoffeeWithHook extends CaffeineBeverageWithHook {
public void brew() {
System.out.println("Dripping Coffee through filter");
}
public void addCondiments() {
System.out.println("Adding Sugar and Milk");
}
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("Would you like milk and sugar with your coffee (y/n)? ");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
answer = in.readLine();
} catch (IOException ioe) {
System.err.println("IO error trying to read your answer");
}
if (answer == null) {
return "no";
}
return answer;
}
}
고찰
- 제공해야만 하는 기능 ⇒ 추상 메소드
- 서브 클래스 전용 커스텀 ⇒ 후크
- 추상 메소드가 너무 많아지는 문제.
- 템플릿 메소드를 만들 때에 이 점을 염두.
- 모든 단계가 필수가 아니므로 후크 사용
할리우드 원칙
먼저 연락 X. 연락 주겠어
- 할리우드 원칙을 사용하면 dependency rot를 방지.
- 의존성 부패 ⇒ 고수준 구성요소와 저수준 구성요소가 서로서로 의존하는 형태.
할리우드 원칙과 템플릿 메소드 패턴
- CaffeineBeverage 클래스는 고수준 구성요소
- Tea, Coffee(구상 클래스)가 고수준 구성요소를 호출하지 않음.
프레임 워크를 만드는데 적절한 패턴
- Arrays.sort() 에서 사용되는 패턴
- 서브 클래스를 구현하기 위해서 Comparable 인터페이스 제공을 통해 compareTo() 구현하도록 유도
- JFrame 클래스에서 사용
- paint() 함수가 후크
'기타 > 디자인패턴' 카테고리의 다른 글
[Design Pattern] State Pattern (0) | 2024.06.09 |
---|---|
[Design Pattern] Iterator Pattern & Composite Pattern (0) | 2024.06.09 |
[Design Pattern] Adapter Pattern (0) | 2024.06.04 |
[Design Pattern] Command Pattern (2) | 2024.06.03 |
[Design Pattern] Singleton Pattern (0) | 2024.05.31 |