1. template method pattern이란?
간단하게 구현된 알고리즘의 직접적인 변경 없이(알고리즘의 구조 변경 없이) 서브클래스를 사용하여 일부를 재정의하여 사용할 수 있는 것을 의미한다.
<아래 음료를 만드는 클래스를 통해서 템플릿 메소드 패턴을 사용하는 경우를 살펴보자>
package smu_2;
public abstract class CaffeineBeverage{
public final void prepareRecipe() {//final로 레시피(알고리즘)를 고정시켜 놓는다. 오버라이딩을 금지시키기 위함
boilWater();
brew();
pourInCup();
addCondiments();
}
/*추상메소드를 사용해서 자식클래스내에서 필요한대로 구현하게 하기 위함
왜냐면 커피, 홍차 등 음료마다 커피를 끓이거나 홍차를 끓이거나 넣는
여러가지들이 다르기 때문에 추상클래스로 만들어서 미완성된 설계도를
제공하여 자손들이 설계완료 시키는 형식으로 진행한다.*/
public abstract void brew();
public abstract void addCondiments();
//공통으로 사용될 메소드는 그냥 구현해놓으면 된다.
public void boilWater() {
System.out.println("물을 끓이는 중입니다.");
}
public void pourInCup() {
System.out.println("음료를 컵에 담는 중입니다.");
}
}
2. 탬플릿 메소드 사용 시 이점
- 중복코드가 줄어든다.
- 유지보수가 용이해진다.
중복된 코드는 구현을 미리시켜두고 달라지는 부분은 상속받은 클래스에서 구현을 해주면 중복코드는 줄어들고 유지보수는 바뀌는 부분만 수정하면 되니 유지보수가 용이해지게 된다.
#오타 concretemethod임
package smu_2;
abstract class AbstractClass{
//무조건 final을 사용하란 것은 아니지만 알고리즘의 고정을 위함.
final void templateMethod() {
primitiveOperation1();
primitiveOperation1();
concreteOperation();
}
abstract void primitiveOperation1();
abstract void primitiveOperation2();
void concreteOperation() {
//구현 --> 위임하지 않는 부분을 말한다.
}
}
3. 다른 경우에 사용하는 템플릿 메소드 패턴(Feat. hook( ))
<hook의 일반적 예시>
package smu_2;
abstract class AbstractClass{
final void templateMethod() {
primitiveOperation1();
primitiveOperation1();
concreteOperation();
hook();
}
abstract void primitiveOperation1();
abstract void primitiveOperation2();
void concreteOperation() {
//구현 --> 위임하지 않는 부분을 말한다.
}
void hook() {} //기본적인 내용만 구현되어 있거나 아무 코드도 들어있지 않은 메소드
}
<Hook은 사용법에 따라서 우리가 알아서 고쳐 쓰면 된다.>
package smu_2;
public abstract class CaffeineBeverageWithHook{
public final void prepareRecipe() {//final로 레시피(알고리즘)를 고정시켜 놓는다. 오버라이딩을 금지시키기 위함
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
//사용자가 뭘 더 넣는다 하면 addCondiments를 한다.
addCondiments();
}
}
public abstract void brew();
public abstract void addCondiments();
public void boilWater() {
System.out.println("물을 끓이는 중입니다.");
}
public void pourInCup() {
System.out.println("음료를 컵에 담는 중입니다.");
}
boolean customerWantsCondiments() {
//Hook
return true;
}
}
<hook을 통해 서브클래스에서 알고리즘의 수정변경 없이 템플릿 메소드 패턴을 사용한 코드>
package smu_2;
import java.util.Scanner;
public abstract class CaffeineBeverageWithHook{
public final void prepareRecipe() {//final로 레시피(알고리즘)를 고정시켜 놓는다. 오버라이딩을 금지시키기 위함
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
//사용자가 뭘 더 넣는다 하면 addCondiments를 한다.
addCondiments();
}
}
public abstract void brew();
public abstract void addCondiments();
public void boilWater() {
System.out.println("물을 끓이는 중입니다.");
}
public void pourInCup() {
System.out.println("음료를 컵에 담는 중입니다.");
}
boolean customerWantsCondiments() {
//Hook
return true;
}
}
package smu_2;
import java.util.Scanner;
//상속
public class CoffeeWithHook extends CaffeineBeverageWithHook{
public void brew() {
System.out.println("필터로 커피를 우려내는 중");
}
public void addCondiments() {
System.out.println("우유와 설탕을 추가하는 중");
}
public boolean customerWantsCondiments() {
char answer = getUserInput();
//입력받은 값이 y -> True no -> False
return (answer == 'y') ? true:false;
}
public char getUserInput() {
String answer = null;
System.out.println("음료에 우유와 설탕을 추가하시겠습니까?");
Scanner sc = new Scanner(System.in);
answer = sc.next();
return answer.charAt(0);
}
}
package smu_2;
public class BeverageTestDrive {
public static void main(String[] args) {
CoffeeWithHook coffeeHook = new CoffeeWithHook();
System.out.print("음료 준비중...\n");
coffeeHook.prepareRecipe();
}
}
결과
음료 준비중...
물을 끓이는 중입니다.
필터로 커피를 우려내는 중
음료를 컵에 담는 중입니다.
y
우유와 설탕을 추가하는 중
음료 준비중...
물을 끓이는 중입니다.
필터로 커피를 우려내는 중
음료를 컵에 담는 중입니다.
n
4. 할리우드 원칙(Hollywood Principle)
- 템플릿 메소드 패턴을 이용하여 설계를 하면 할리우드 원칙이 적용된다.
-> 템플릿 메소드를 이용해서 프로그램을 설계하면서 "우리가 연락할 테니 먼저 연락하지 마" 라고 얘기하는 격
- 저수준(low level) 구성 요소에서 시스템에 접속할 수 있지만, 언제 어떤 식으로 그 구성요소들을 사용할지는 고수준 구성요소에서 결정한다. (저수준 - 서브클래스/ 고수준 - 알고리즘)
5. 템플릿 메소드 패턴의 활용 예
- 프레임워크를 만드는 데 아주 훌륭한 디자인 도구
- 프레임워크를 사용함으로써 작업이 처리되는 방식은 제어하면서, 프레임워크에서 처리하는 알고리즘의 각 단계는 그 프레임워크를 사용하는 사람 마음대로 지정이 가능하다.
- Array의 sort() 함수
- 스윙의 JFrame
- Applet
템플릿 메소드를 이용한 BubbleSort 구현
package 고객프;
import java.util.Arrays;
public class MainTest {
public static void main(String[] args) {
Person[] people = {
new Person(3000, "Dooly"),
new Person(30, "Ddochi"),
new Person(25, "Michol"),
new Person(20000, "Douner"),
new Person(3, "HeeDong")
};
System.out.println("\noriginal people");
for (Person p : people) {
System.out.println(p);
}
System.out.println("\nsort by Name");
NameSorter sorter = new NameSorter();
sorter.bubbleSort(people);
for (Person p : people) {
System.out.println(p);
}
System.out.println("\nsort by Age");
AgeSorter sorter2 = new AgeSorter();
sorter2.bubbleSort(people);
for (Person p : people) {
System.out.println(p);
}
}
}
package 고객프;
public class AgeSorter extends BubbleSorter{
public void bubbleSort(Person[] data) {
sort(data);
}
public int compareTo(Person a, Person b) {
if (a.getAge() > b.getAge()) return 1;
else if (a.getAge() < b.getAge()) return -1;
else return 0;
}
}
package 고객프;
public class NameSorter extends BubbleSorter{
public void bubbleSort(Person[] data) {
sort(data);
}
public int compareTo(Person a, Person b) {
return a.getName().compareTo(b.getName());
}
}
package 고객프;
public class Person implements Comparable<Person> {
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [age=" + age + ", name=" + name + "]";
}
@Override
public int compareTo(Person other) {
return this.getAge() - other.getAge();
}
}
<버블 정렬 알고리즘을 추사화 시키고, 그 중 이름과 나이를 비교하는 부분을 자식 클래스들로 위임하는 형태로 코드를 작성.>
package 고객프;
public abstract class BubbleSorter implements BubbleSorterComparable{
public void sort(Person[] data) {
for (int i = 0; i < data.length - 1; i++) {
for (int j = 0; j < data.length - 1; j++) {
if (compareTo(data[j],data[j+1]) > 0) {
Person temp = data[j];
data[j] = data[j + 1];
data[j + 1] = temp;
}
}
}
}
public abstract int compareTo(Person a, Person b);
}
package 고객프;
public interface BubbleSorterComparable {
//비교는 나이, 이름에 따라서 기준이 달라지기 때문에 interface로 만든다.
//returns > 0 if a > b
//returns < 0 if a < b
//return 0 if a==b
int compareTo(Person a, Person b);
}
'Java > 고급객체지향' 카테고리의 다른 글
고급객체지향 프로그래밍 - MVC 패턴(Model-view-Controller Pattern) (0) | 2021.12.12 |
---|---|
스테이트 패턴(State Pattern) (0) | 2021.12.12 |
고급객체지향 프로그래밍 - 커맨드 패턴(Command Pattern) (0) | 2021.12.12 |
고급객체지향 프로그래밍 - 퍼사드 패턴(Facade Pattern) (0) | 2021.12.12 |
고급객체지향 프로그래밍 - 어댑터 패턴(Adapter Pattern) (0) | 2021.12.12 |