Post

Template Method Pattern 정리

Template Method Pattern 정리

상황

컀피와 홍차λ₯Ό λŠμ΄λŠ” 과정은 μƒλ‹Ήνžˆ μœ μ‚¬ν•˜λ‹€. ν•˜μ§€λ§Œ, μ»€ν”ΌλŠ” 원두λ₯Ό μš°λ €λ‚΄κ³  ν™μ°¨λŠ” μžŽμ„ μš°λ €λ‚Έλ‹€.

λ‚˜λ¨Έμ§€ 방식, β€œλ¬Όμ„ λŠμΈλ‹€β€, β€œμ»΅μ— λ”°λ₯Έλ‹€β€λŠ” μΌμΉ˜ν•œλ‹€. 그리고 무엇가λ₯Ό μš°λ €λ‚΄κ³ , ν† ν•‘(ν™μ°¨λŠ” 레λͺ¬, μ»€ν”ΌλŠ” 섀타)을 μΆ”κ°€ν•˜λŠ” 것도 μœ μ‚¬ν•˜λ‹€. 이런 μ‹μœΌλ‘œ 같은 단계λ₯Ό λ”°λ₯΄λŠ” 객체가 수 없이 λ§Žλ‹€λ©΄, ν…œν”Œλ¦Ώ λ©”μ†Œλ“œ νŒ¨ν„΄μ„ 톡해 μ€‘λ³΅λœ μ½”λ“œλ₯Ό μ œκ±°ν•  수 μžˆλ‹€.

Template Method Pattern μ΄λž€?

ν…œν”Œλ¦Ώ λ©”μ„œλ“œλŠ” λΆ€λͺ¨ ν΄λž˜μŠ€μ—μ„œ μ•Œκ³ λ¦¬μ¦˜μ˜ 단계λ₯Ό μ •μ˜ν•œλ‹€. ν•˜μœ„ ν΄λž˜μŠ€λ“€μ΄ μ•Œκ³ λ¦¬μ¦˜μ˜ νŠΉμ • 단계듀을 μ˜€λ²„λΌμ΄λ“œ(μž¬μ •μ˜)ν•  수 μžˆλ„λ‘ ν•˜λŠ” 행동 λ””μžμΈΒ νŒ¨ν„΄μ΄λ‹€.

λ‘œμ§μ„ 단계 λ³„λ‘œ λ‚˜λˆ μ•Ό ν•˜λŠ” μƒν™©μ—μ„œ μ μš©ν•œλ‹€.

1
λ‹¨κ³„λ³„λ‘œ λ‚˜λˆˆ λ‘œμ§λ“€μ΄ μ•žμœΌλ‘œ μˆ˜μ •λ  κ°€λŠ₯성이 μžˆμ„ 경우 더 νš¨μœ¨μ μ΄λ‹€.

https://refactoring.guru/ko/design-patterns/template-method

[좜처: https://refactoring.guru/ko/design-patterns]

  1. ꡬ상 ν΄λž˜μŠ€λ“€μ€ λͺ¨λ“  단계듀을 μ˜€λ²„λΌμ΄λ“œν•  수 μžˆμ§€λ§Œ, 골격(단계)λ₯Ό λ‚˜νƒ€λ‚΄λŠ” templateMethod() ν•¨μˆ˜λŠ” μ˜€λ²„λΌμ΄λ“œ ν•  수 μ—†λ‹€. Javaμ—μ„œλŠ” μˆ˜μ •μ΄ λΆˆκ°€λŠ₯ν•˜κ²Œ final ν‚€μ›Œλ“œλ₯Ό μΆ”κ°€ν•œλ‹€.
  2. 각 단계듀은 μ™ΈλΆ€λŠ” 막고, μžμ‹λ“€λ§Œ ν™œμš©ν•  수 μžˆλ„λ‘ protected둜 μ„ μ–Έν•œλ‹€

μ˜ˆμ‹œ μ½”λ“œ

μ±…μ—μ„œλŠ” μ„€λͺ…ν•œ 컀피와 홍차λ₯Ό μ˜ˆμ‹œλ‘œ μ„€λͺ…ν•œλ‹€. 컀피, 홍차 λͺ¨λ‘ 카페인 μŒλ£ŒλΌλŠ” κ²ƒμ—μ„œ 곡톡점이 μžˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public abstract class CaffeineBeverage {
  
	final void prepareRecipe() {
		boilWater();
		brew();
		pourInCup();
		addCondiments();
	}
 
	abstract void brew();
  
	abstract void addCondiments();
 
	void boilWater() {
		System.out.println("Boiling water");
	}
  
	void pourInCup() {
		System.out.println("Pouring into cup");
	}
}

[컀피 클래슀]

1
2
3
4
5
6
7
8
public class Coffee extends CaffeineBeverage {
	public void brew() {
		System.out.println("Dripping Coffee through filter");
	}
	public void addCondiments() {
		System.out.println("Adding Sugar and Milk");
	}
}

[홍차 클래슀]

1
2
3
4
5
6
7
8
public class Tea extends CaffeineBeverage {
	public void brew() {
		System.out.println("Steeping the tea");
	}
	public void addCondiments() {
		System.out.println("Adding Lemon");
	}
}

Hook(ν›…)

λ§Œμ•½, Typeλ³„λ‘œ μ„ νƒμ μœΌλ‘œ 단계λ₯Ό μˆ˜ν–‰ν•΄μ•Ό ν•œλ‹€λ©΄, 예λ₯Ό λ“€λ©΄ 컀피인 경우 μ΄λ²ˆμ—” 우유λ₯Ό ν•„μˆ˜μ μœΌλ‘œ μΆ”κ°€ν•΄μ•Όν•œλ‹€κ³  ν•΄λ³΄μž. 그러면 λ§Œμ•½ CaffeineBeverage의 νƒ€μž…μ΄ Coffee라면 단계λ₯Ό λ‚˜νƒ€λ‚΄λŠ” λ©”μ„œλ“œμ— Hook을 λ§Œλ“€μ–΄λ†”μ•Ό ν•œλ‹€. μ™œλƒν•˜λ©΄ 단계λ₯Ό λ‚˜νƒ€λ‚΄λŠ” λ©”μ„œλ“œλŠ” final둜 ν•˜μœ„ν΄λž˜μŠ€μ—μ„œ μ˜€λ²„λΌμ΄λ”©ν•  수 μ—†λ‹€. 그렇기에 μ˜€λ²„λΌμ΄λ”© κ°€λŠ₯ν•˜κ²Œ 열어놔야 ν•˜λŠ”λ°, 그게 Hook method이닀.

μ•„λž˜μ˜ μ½”λ“œλ₯Ό ν™•μΈν•˜λ©΄ prepareRecipe() μ˜€λ²„λΌμ΄λ”©ν•  수 μ—†μ§€λ§Œ, customerWantsCondiments() 은 μ–Έμ œλ“  μ˜€λ²„λΌμ΄λ”©ν•  수 μžˆλ‹€. 그렇기에 λ§Œμ•½, 홍차라면 customerWantsCondiments()λ₯Ό μ˜€λ²„λΌμ΄λ”©ν•˜μ—¬ falseλ₯Ό λ°˜ν™˜ν•˜κ²Œ ν•˜λ©΄ 단계λ₯Ό μˆ˜μ •ν•  수 μžˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
final void prepareRecipe() {
		boilWater();
		brew();
		pourInCup();
		if (customerWantsCondiments()) {
			addCondiments();
		}
	}
... 
	boolean customerWantsCondiments() {
		return true;
	}

ν• λ¦¬μš°λ“œ 원칙

β€œμš°λ¦¬ν•œν…Œ μ—°λ½ν•˜μ§€ λ§ˆμ„Έμš”, μ•Œμ•„μ„œ μ—°λ½μ€„κ²Œμš”β€ λΌλŠ” μ›μΉ™μœΌλ‘œ κ³ μˆ˜μ€€μ˜ μš”μ†Œκ°€ μ €μˆ˜μ€€μ˜ μš”μ†Œμ—κ²Œ ν•΄μ•Όν•˜λŠ” 원칙이닀. 즉, μ €μˆ˜μ€€μ˜ μš”μ†Œκ°€ κ³ μˆ˜μ€€μ˜ μš”μ†Œλ₯Ό 연락(호좜)ν•˜μ§€ μ•Šκ³  κ³ μˆ˜μ€€μ΄ ν•„μš”ν•  λ•Œ μ €μˆ˜μ€€μ„ ν˜ΈμΆœν•œλ‹€.

Template method Pattern λ˜ν•œ, 이λ₯Ό μ€€μˆ˜ν•˜κ³  μžˆλ‹€. μƒμœ„ μš”μ†Œ(CaffeineBeverage)λŠ” ν•„μš”ν•  λ•Œ(μ˜€λ²„λΌμ΄λ”©)만 μ €μˆ˜μ€€μ˜ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜κ³ , λ°˜λŒ€λ‘œ μ €μˆ˜μ€€μ€ μƒμœ„ μš”μ†Œλ₯Ό ν˜ΈμΆœν•˜λŠ” 일이 μ—†λ‹€.

μ—¬κΈ°μ„œ μ €μˆ˜μ€€μ˜ μš”μ†Œκ°€ λ°˜λ“œμ‹œ κ³ μˆ˜μ€€μ˜ μš”μ†Œλ₯Ό ν˜ΈμΆœν•˜λ©΄ μ•ˆλ˜λŠ” 것이 μ•„λ‹ˆλ‹€. λ‹€λ§Œ, μˆœν™˜ μ˜μ‘΄μ„±μ΄ μƒκΈ°λŠ” 일은 λ°©μ§€ν•΄μ•Όν•œλ‹€.

Java ν”„λ ˆμž„μ›Œν¬ μ˜ˆμ‹œ

μžλ°”μ˜ ArrayListμ—μ„œλŠ” sortν•¨μˆ˜κ°€ μžˆλ‹€. sortλŠ” template method νŒ¨ν„΄μ„ μ‚¬μš©ν•˜κ³  μžˆλ‹€. ꡬ체적인 단계λ₯Ό μ •μ˜ν•΄λ‘κ³ , ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ 단지 λΉ„κ΅ν•˜λŠ” λ²•λ§Œ(CompareTo) μ •μ˜ν•΄μ£Όλ©΄ λœλ‹€. μ•„λž˜μ˜ μ½”λ“œλŠ” β€œμ„œλΈŒ ν΄λž˜μŠ€μ—μ„œ ν•˜λ‚˜μ˜ 단계λ₯Ό μ˜€λ²„λΌμ΄λ”©ν•œλ‹€β€λΌλŠ” Template method Pattern μ •μ˜μ— μ •ν™•ν•˜κ²Œ λΆ€ν•©ν•˜μ§€ μ•ŠλŠ”λ‹€. μ—¬κΈ°μ„  ArrayListκ°€ μ•„λ‹Œ ComparableλΌλŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό 톡해 μ—°κ²°λ˜μ–΄μžˆλ‹€.

μ±…μ—μ„œλŠ” μžλ°” κ°œλ°œμžκ°€, 배열은 μ„œλΈŒν΄λž˜μŠ€λ₯Ό λ§Œλ“€ 수 μ—†λ‹€λΌλŠ” μ œμ•½μ‘°κ±΄μ— μ˜ν•΄ λ‹€μŒκ³Ό 같은 방식을 μ„ νƒν–ˆμ„κ±°λΌκ³  ν•œλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Duck implements Comparable<Duck> {
	String name;
	int weight;
  
	public Duck(String name, int weight) {
		this.name = name;
		this.weight = weight;
	}
 
	public String toString() {
		return name + " weighs " + weight;
	}
  
	public int compareTo(Duck otherDuck) {
 
  
		if (this.weight < otherDuck.weight) {
			return -1;
		} else if (this.weight == otherDuck.weight) {
			return 0;
		} else { // this.weight > otherDuck.weight
			return 1;
		}
	}
}

[ν…ŒμŠ€νŠΈ μ½”λ“œ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main(String[] args) {
		Duck[] ducks = { 
						new Duck("Daffy", 8), 
						new Duck("Dewey", 2),
						new Duck("Howard", 7),
						new Duck("Louie", 2),
						new Duck("Donald", 10), 
						new Duck("Huey", 2)
		 };

		System.out.println("Before sorting:");
		display(ducks);

		Arrays.sort(ducks);
 
		System.out.println("\nAfter sorting:");
		display(ducks);
	}

[κ²°κ³Ό]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Before sorting:
Daffy weighs 8
Dewey weighs 2
Howard weighs 7
Louie weighs 2
Donald weighs 10
Huey weighs 2

After sorting:
Dewey weighs 2
Louie weighs 2
Huey weighs 2
Howard weighs 7
Daffy weighs 8
Donald weighs 10

λ‹€λ₯Έ νŒ¨ν„΄κ³Ό 비ꡐ

[Factory Method Pattern]

νŒ©ν† λ¦¬ λ©”μ„œλ“œ νŒ¨ν„΄μ€ νŠΉν™”λœ Template Method Pattern으둜 κΈ°λ³Έλ‹¨κ³„μ—μ„œ 객체λ₯Ό μƒμ„±ν•˜κ³  λ¦¬ν„΄ν•˜λŠ” Pattern이닀.

[Strategy Pattern]

μ „λž΅ νŒ¨ν„΄μ€ λͺ¨λ“  μ•Œκ³ λ¦¬μ¦˜μ΄ λ‹€ λͺ…μ‹œλ˜μ–΄μžˆλŠ” 반면, ν…œν”Œλ¦Ώ λ©”μ„œλ“œ νŒ¨ν„΄μ€ 단계가 λͺ…μ‹œλ˜μ–΄μžˆκ³  일뢀 λ‹¨κ³„λŠ” ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ μ˜€λ²„λΌμ΄λ”©ν•  수 μžˆλ‹€.

abstract와 Interface의 μ°¨μ΄λŠ”?

  • abstract : λΆ€λͺ¨μ˜ κΈ°λŠ₯을 μžμ‹μ—μ„œ ν™•μž₯μ‹œμΌœλ‚˜κ°€κ³  싢을 λ•Œ β†’ 상속(단 ν•œκ°œμ˜ 클래슀만 상속가λŠ₯)
  • interface : ν•΄λ‹Ή ν΄λž˜μŠ€κ°€ κ°€μ§„ ν•¨μˆ˜μ˜ κΈ°λŠ₯을 ν™œμš©ν•˜κ³  싢을 λ•Œ β†’ κ΅¬ν˜„(μ—¬λŸ¬ μΈν„°νŽ˜μ΄μŠ€λ„ κ΅¬ν˜„κ°€λŠ₯)

Javaμ—μ„œλŠ” 닀쀑 상속이 μ•ˆλœλ‹€. 상황에 맞게 ν™œμš©ν•˜μž!

This post is licensed under CC BY 4.0 by the author.