๐ก ํ ํ๋ฆฟ ๋ฉ์๋ ํจํด (template method pattern)
๋ฉ์๋์์ ์๊ณ ๋ฆฌ์ฆ์ ๊ณจ๊ฒฉ์ ์ ์ํ๋ค.
์๊ณ ๋ฆฌ์ฆ์ ์ฌ๋ฌ ๋จ๊ณ ์ค ์ผ๋ถ๋ ์๋ธํด๋์ค์์ ๊ตฌํํ ์ ์๋ค.
ํ ํ๋ฆฟ ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ฉด ์๊ณ ๋ฆฌ์ฆ์ ๊ตฌ์กฐ๋ ๊ทธ๋๋ก ์ ์งํ๋ฉด์ ์๋ธํด๋์ค์์ ํน์ ๋จ๊ณ๋ฅผ ์ฌ์ ์ํ ์ ์๋ค.
์์ ) ์ปคํผ์ ํฐ์ ์ถ์ถ ๊ณผ์
์ปคํผ ์ถ์ถ ๊ณผ์ | ํฐ ์ถ์ถ ๊ณผ์ |
1. ๋ฌผ์ ๋์ธ๋ค. 2. ์ปคํผ๋ฅผ ์ฐ๋ ค๋ธ๋ค. 3. ์ปต์ ๋ฐ๋ฅธ๋ค. 4. ์คํ ๋ฐ ์ฐ์ ๋ฅผ ์ฒจ๊ฐํ๋ค. |
1. ๋ฌผ์ ๋์ธ๋ค. 2. ํฐ๋ฅผ ์ฐ๋ ค๋ธ๋ค. 3. ์ปต์ ๋ฐ๋ฅธ๋ค. 4. ๋ ๋ชฌ์ ์ฒจ๊ฐํ๋ค |
์ผ๋ จ์ ๊ณผ์ ์ด ๊ฑฐ์ ๋์ผํ๋ค. ์ฐจ์ด๊ฐ ์๋ ๋ถ๋ถ๋ง ๊ฐ์กฐ ํ์ ํด๋ณด์๋ค.
๊ณตํต๋๋ ๋ถ๋ถ์ ์ถ์ํ (abstract) ์์ผ ํด๋์ค๋ฅผ ๋ง๋ค์ด ๋ณด์.
// ์ถ์ํด๋์ค (abstract)
public abstract class CaffeineBeverage {
final void prepareRecipe() {
boilWater(); // 1. ๋ฌผ์ ๋์ธ๋ค.
brew(); // 2. ๋๋ ๋ฌผ์ ์ฐ๋ ค๋ธ๋ค.
pourInCup(); // 3. ์ปต์ ๋ฐ๋ฅธ๋ค.
addCondiments(); // 4. ํฅ์ ๋ฃ๋ฅผ ์ฒจ๊ฐํ๋ค.
}
// ๋ณํ๋ ๋ถ๋ถ์ ๊ฐ ํด๋์ค์์ ์ฌ์ ์ํ๋ค.
abstract void brew();
abstract void addCondiments();
void boilWater() {
System.out.println("๋ฌผ์ ๋์ธ๋ค.");
}
void pourInCup() {
System.out.println("์ปต์ ๋ฐ๋ฅธ๋ค.");
}
}
์ ์ถ์ํด๋์ค๋ฅผ ํ์ฅํ์ฌ Coffee, Tea ํด๋์ค๋ฅผ ์์ฑํ๋ค.
// Coffee ํด๋์ค
public class Coffee extends CaffeineBeverage {
@Override
public void brew() {
System.out.println("์ปคํผ๋ฅผ ์ถ์ถํ๋ค.");
}
@Override
public void addCondiments() {
System.out.println("์คํ, ์ฐ์ ๋ฅผ ์ฒจ๊ฐํ๋ค.");
}
}
// Tea ํด๋์ค
public class Tea extends CaffeineBeverage {
@Override
public void brew() {
System.out.println("ํฐ๋ฅผ ์ฐ๋ ค๋ธ๋ค.");
}
@Override
public void addCondiments() {
System.out.println("๋ ๋ชฌ์ ์ฒจ๊ฐํ๋ค.");
}
}
์ถ๋ ฅํด๋ณด๊ธฐ
public class CaffeineBeverageTest {
@Test
void coffeeBrew() {
CaffeineBeverage coffee = new Coffee();
coffee.prepareRecipe();
}
@Test
void teaBrew() {
CaffeineBeverage tea = new Tea();
tea.prepareRecipe();
}
}
์ถ๋ ฅ๊ฒฐ๊ณผ
1. coffeeBrew() ์ถ๋ ฅ
๋ฌผ์ ๋์ธ๋ค.
์ปคํผ๋ฅผ ์ถ์ถํ๋ค.
์ปต์ ๋ฐ๋ฅธ๋ค.
์คํ, ์ฐ์ ๋ฅผ ์ฒจ๊ฐํ๋ค.
2. teaBrew() ์ถ๋ ฅ
๋ฌผ์ ๋์ธ๋ค.
ํฐ๋ฅผ ์ฐ๋ ค๋ธ๋ค.
์ปต์ ๋ฐ๋ฅธ๋ค.
๋ ๋ชฌ์ ์ฒจ๊ฐํ๋ค.
Template Method ๋ก ์ป์ ์ ์์๋ ๊ฒ
๋ณํ๋ ๊ฒ๊ณผ ๋ณํ์ง ์๋ ๊ฒ์ ๋ถ๋ฆฌํ ์ ์๋ค.
- CaffeineBevarage ํด๋์ค์์ ์์ ์ ์ฒ๋ฆฌ, ์๊ณ ๋ฆฌ์ฆ์ ๋ ์ ํ๋ค.
- CaffeineBevarage ๋๋ถ์ ์๋ธํด๋์ค์์ ์ฝ๋๊ฐ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
- ์๊ณ ๋ฆฌ์ฆ์ด ํ ํ๋ฆฟ ํ๋์ ์กด์ฌํ๋ฏ๋ก ํ ๋ถ๋ถ๋ง ๊ณ ์น๋ฉด ๋๋ค.
- ๋ค๋ฅธ ์๋ฃ๋ ์ฝ๊ฒ ์ถ๊ฐ๊ฐ๋ฅํ Framework๋ฅผ ์ ๊ณตํ๋ค.
- ์๊ณ ๋ฆฌ์ฆ์ ํ ํ๋ฆฟ์ ์กด์ฌํ๋ฉฐ, ์๋ธํด๋์ค์์๋ ๊ตฌํ๋ง ํ๋ค.
Template Method์ Hook
ํํฌ(hooks)๋, ์ถ์ํด๋์ค์์ ์ ์ธ๋๋ ๋ฉ์๋์ด๊ธด ํ์ง๋ง ๊ธฐ๋ณธ์ ์ธ ๋ด์ฉ๋ง ๊ตฌํ๋์ด ์๊ฑฐ๋ ์๋ฌด ์ฝ๋๋ ๋ค์ด์์ง ์์ ๋ฉ์๋์ด๋ค. ์๋ธํด๋์ค๋ ์ค๋ฒ๋ผ์ด๋ํ์ฌ ๋ค์ํ ์์น์ ์๊ณ ๋ฆฌ์ฆ์ ์ ์ฉํ ์ ์๊ฒ ํด์ค๋ค.
// ์ถ์ํด๋์ค์ hook ์ถ๊ฐ
public abstract class CaffeinBeverage {
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
// hook
if(customerWantsCondiments()){
addCondiments();
}
}
abstract void brew();
abstract void addCondiments();
void boilWater() {
System.out.println("๋ฌผ์ ๋์ธ๋ค.");
}
void pourInCup() {
System.out.println("์ปต์ ๋ฐ๋ฅธ๋ค.");
}
// ์ด ๋ฉ์๋๋ ์๋ธํด๋์ค์์ ํ์์๋ฐ๋ผ ์ค๋ฒ๋ผ์ด๋ํ์ฌ ์ฌ์ฉ๊ฐ๋ฅ
boolean customerWantsCondiments() {
// hook : ์๋ฌด๊ฒ๋ ์ ์๋์์ง ์๊ณ ํ์์๋ฐ๋ผ ์ฌ์ฉ ๊ฐ๋ฅ
return true;
}
}
ํ ๋ฆฌ์ฐ๋ ์์น๊ณผ ํ ํ๋ฆฟ ๋ฉ์๋ ํจํด
๐ ํ ๋ฆฌ์ฐ๋ ์์น
๋จผ์ ์ฐ๋ฝํ์ง ๋ง์ธ์. ์ ํฌ๊ฐ ์ฐ๋ฝ๋๋ฆฌ๊ฒ ์ต๋๋ค.
ํ ํ๋ฆฟ ๋ฉ์๋ ํจํด์, ์์กด์ฑ ๋ถํจ(dependency rot)๋ฅผ ๋ฐฉ์งํ ์ ์๋ค.
์์กด์ฑ ๋ถํจ๋?
์ด๋ค ๊ณ ์์ค ๊ตฌ์ฑ์์๊ฐ ์ ์์ค ๊ตฌ์ฑ์์์ ์์กดํ๊ณ , ๊ทธ ์ ์์ค ๊ตฌ์ฑ์์๋ ๋ค์ ๊ณ ์์ค ๊ตฌ์ฑ์์์ ์์กดํ๊ณ , ๊ทธ ๊ณ ์์ค ๊ตฌ์ฑ์์๋ ๋ค์ ๋ ๋ค๋ฅธ ๊ตฌ์ฑ์์์ ์์กดํ๊ณ ... ์ด๋ ๊ฒ ์์กด์ฑ์ด ๋ณต์กํ๊ฒ ๊ผฌ์ธ ์ํ๋ฅผ ๋งํ๋ค.
ํ ๋ฆฌ์ฐ๋ ์์น์ ์ ์์ค ๊ตฌ์ฑ์์์์ ์์คํ ์ ์ ์ ํ ์ ์์ง๋ง, ์ธ์ ์ด๋ค์์ผ๋ก ๊ทธ ๊ตฌ์ฑ์์๋ฅผ ์ฌ์ฉํ ์ง๋ ๊ณ ์์ค ๊ตฌ์ฑ์์์์ ๊ฒฐ์ ํ๊ฒ ๋๋ค. ์ฆ, ์ ์์ค ๊ตฌ์ฑ์์๋ ์ปดํจํ ์ด์ ์ ์ฐธ์ฌํ ์๋ ์์ง๋ง ์ ๋ ๊ณ ์์ค ๊ตฌ์ฑ์์๋ฅผ ์ง์ ํธ์ถํ๋ฉด ์๋๋ค๋ ๊ฒ์ด๋ค.
UML Class Diagram
GOF ๋์์ธ ํจํด์ ์ ์
ํ ํ๋ฆฟ ๋ฉ์๋ ๋์์ธ ํจํด์ ๋ชฉ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
"์์ ์์ ์๊ณ ๋ฆฌ์ฆ์ ๊ณจ๊ฒฉ์ ์ ์ํ๊ณ ์ผ๋ถ ๋จ๊ณ๋ฅผ ํ์ ํด๋์ค๋ก ์ฐ๊ธฐํฉ๋๋ค. ํ ํ๋ฆฟ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ํ์ ํด๋์ค๊ฐ ์๊ณ ๋ฆฌ์ฆ์ ๊ตฌ์กฐ๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ๋ ์๊ณ ๋ฆฌ์ฆ์ ํน์ ๋จ๊ณ๋ฅผ ์ฌ์ ์ํ ์ ์์ต๋๋ค."
์ฆ, ๋ถ๋ชจ ํด๋์ค์ ๋ก์ง์ ๊ตฌ์กฐ๋ฅผ ํ ํ๋ฆฟ์ผ๋ก ์ ์ํ๊ณ , ๋ณ๊ฒฝ๋๋ ๋ก์ง์ ์์ ํด๋์ค์ ์ ์ํ๋ ๊ฒ์ด๋ค.
์ด๋ก์จ ์์ ํด๋์ค๊ฐ ์๊ณ ๋ฆฌ์ฆ์ ์ ์ฒด ๊ตฌ์กฐ๋ฅผ ๋ณ๊ฒฝํ์ง์๊ณ ๋ณ๊ฒฝ์ด ๋๋ ํน์ ๋ก์ง๋ง ์ฌ์ ์ํ ์ ์๋ค.
์์๊ณผ ์ค๋ฒ๋ผ์ด๋ฉ์ ์ด์ฉํ ๋คํ์ฑ์ ํ์ฉํ๋ ๊ฒ์ด๋ค.
ํ ํ๋ฆฟ ๋ฉ์๋ ํจํด์ด ๊ฐ์ง๋ ๋ฌธ์
ํ ํ๋ฆฟ ๋ฉ์๋ ํจํด์ ์์์ ์ฌ์ฉํ๋ค. ์ฆ, ์์์ ๋จ์ ์ ๋ชจ๋ ๊ฐ์ง๋ค.
์์(ํ์) ํด๋์ค๊ฐ ๋ถ๋ชจ(์์) ํด๋์ค์ ์ปดํ์ผ ์์ ์ ๊ฐํ๊ฒ ๊ฒฐํฉ๋๋ ๋ฌธ์ ๊ฐ ์๋ค. ์์กด๊ด๊ณ์ ๋ํ ๋ฌธ์ ์ธ๋ฐ, ํ์ ํด๋์ค๋ ์์ ํด๋์ค์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ง ์๋๋ฐ๋ ๋ถ๋ชจ ํด๋์ค๋ฅผ ์์ ๋ฐ๊ณ ์๋ค.
์์ ๋ฐ๋ ๋ค๋ ๊ฒ์ ์์กดํ๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค. ์ฌ์ฉํ๋ ์ฌ์ฉํ์ง์๋ ๋ถ๋ชจ ํด๋์ค๋ฅผ ๊ฐํ๊ฒ ์์กดํ๋ค.
๋ถ๋ชจ ํด๋์ค์ ์ฌ์ฉํ์ง ์๋ ๊ธฐ๋ฅ์ด ์๋๋ฐ๋ ๋ถ๋ชจ ํด๋์ค์ ์์กดํ๋ ๊ฒ์ด ์ข์ ์ค๊ณ์ผ๊น?
์๊ฐํด๋ณด๋ฉด ๋ถ๋ชจ ํด๋์ค๋ฅผ ์์ ํ๋ฉด ์์ ํด๋์ค์๋ ์ํฅ์ ๋ผ์น๋ค. ์ฌ์ฉํ์ง ์๋ ๊ธฐ๋ฅ ๋๋ฌธ์ ์ํฅ์ ๋ฐ์ ์ ์๋ ๊ฒ์ด๋ค. ์ด๋ ์ข์ ์ค๊ณ๋ผ ๋ณผ ์ ์๋ค.
๋, ์์์ ์ฌ์ฉํ๊ธฐ๋๋ฌธ์ ๋ณ๋์ ์๋ธ ํด๋์ค๋ ์ต๋ช ๋ด๋ถ ํด๋์ค๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค๋ ๊ฒ์ด๋ค.
ํ๋๊ฐ ์ ๋๋ฉด ๊ด์ฐฎ์์ง ๋ชฐ๋ผ๋ ๊ทธ ์๊ฐ ๋ง๋ค๋ฉด ๋งค์ฐ ๋ณต์กํด์ง๋ค.
ํ ํ๋ฆฟ ๋ฉ์๋ ํจํด๊ณผ ๋น์ทํ ์ญํ ์ ํ๋ฉด์ ์์์ ๋จ์ ์ ์ ๊ฑฐํ ์ ์๋ ๋์์ธ ํจํด์ด ์ ๋ต ํจํด (Strategy Pattern, ์คํธ๋ํฐ์ง ํจํด) ์ด๋ค.
์ฐธ๊ณ
ํค๋ ํผ์คํธ ๋์์ธ ํจํด (Head First Design Patterns) - ์๋ฆญ ํ๋ฆฌ๋จผ,์๋ฆฌ์๋ฒ ์ค ๋กญ์จ,์ผ์ด์ ์์๋ผ,๋ฒํธ ๋ฒ ์ด์ธ