월요일날 일어나서 Java 공부하고 피곤하면 자거나 유튜브 본다.
화요일날 일어나서 CS 공부하고 컴퓨터 게임한다.
수요일은...
-어느 취준생의 루틴-
위 취준생은 각 요일마다 비슷한 하루 일과를 보낸다.
기상 -> 무언가 공부 -> 놀기(졸리면 패스)
물론 월요일 루틴, 화요일 루틴 클래스를 추상화 없이 만들 수 있다.
하지만 지금까지 OOP와 디자인 패턴을 공부한 짬밥이 있지 않은가.
이번 시간에는 템플릿 메소드 패턴에 대해 공부하여 예제에 적용해보자.
템플릿 메소드 패턴은 알고리즘의 골격을 정의한다.
알고리즘의 일부 단계는 서브클래스에서 구현할 수 있으며 구조를 그대로 유지하면서 서브클래스에서 재정의할 수도 있다.
코드를 살펴보자.
public abstract class Routine {
final void carryOut() {
wakeUp();
study();
if (!sleepy()) {
play();
}
}
void wakeUp() {
System.out.println("기상");
}
abstract void study();
abstract void play();
boolean sleepy() {
return false;
}
}
각 요일의 일과는 기상
-> 공부
-> 놀기
로 진행된다.
기상
은 무슨 요일이든 동일하다.공부
는 요일마다 다르다.놀기
또한 요일마다 다르며 월요일은 피곤하기 때문에 생략할 수도 있다.그렇다면 추상 클래스 Routine
으로 wakeUp()
은 구현하고 study()
, play()
는 추상 메소드로 남겨 놓으면 될 것 같다.
하루 일과의 순서는 매번 동일하기 때문에 carryOut()
을 final으로 구현하여 서브클래스에서 재정의 불가하게 만들었다.
여기서
sleepy()
는 hook이라는 템플릿 메소드의 감초같은 녀석이다.
hook은 필요에 따라서 재정의 해주면 된다.
예제에서 월요일은 피곤하면 잔다고 했으니, 사용자에게 피곤한지 입력 받아 피곤하다면play()
를 생략하도록 구현할 수 있을 것이다.
화요일은 항상 놀기 때문에 재정의를 안해주면 그만이다.
그럼 이제 월요일과 화요일의 일과를 구현해보자.
public class MondayRoutine extends Routine {
@Override
void study() {
System.out.println("월요일은 역시 Java 공부지!");
}
@Override
void play() {
System.out.println("주말에 실컷 놀았으니 유튜브 조금만 보다 자자.");
}
@Override
boolean sleepy() {
String answer = getUserInput();
boolean ret;
switch (answer) {
case "y":
ret = true;
break;
case "error":
System.out.println("error");
ret = false;
break;
default:
ret = false;
break;
}
return ret;
}
private String getUserInput() {
System.out.print("공부하느라 피곤한가요? (y / 나머지) : ");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
return br.readLine();
} catch (IOException e) {
return "error";
}
}
}
우선 월요일이다.
월요일엔 Java 공부, 유튜브를 조금만 보며 놀지만 피곤하면 자야되니 hook을 사용자에게 피곤한지 입력 받게 오버라이딩했다.
public class TuesdayRoutine extends Routine {
@Override
void study() {
System.out.println("화요일은 CS 공부 하는 날.");
}
@Override
void play() {
System.out.println("화요일이니 컴퓨터 게임을 해볼까~");
}
}
화요일엔 CS 공부하고 컴퓨터 게임을 하는 날이다.
psvm과 출력을 살펴보자.
public class Main {
public static void main(String[] args) {
MondayRoutine mondayRoutine = new MondayRoutine();
TuesdayRoutine tuesdayRoutine = new TuesdayRoutine();
mondayRoutine.carryOut();
System.out.println();
tuesdayRoutine.carryOut();
}
}
템플릿 메소드 패턴을 사용하면서 서브클래스의 역할이 줄어들었다.
서브클래스는 단순히 짜여있는 템플릿에서 필요한 일부 단계만 구현하거나 재정의했기 때문이다.
따라서 템플릿 메소드 패턴은 중복 코드를 줄이고 핵심 로직의 관리를 줄일 수 있다는 장점이 있지만, 알고리즘의 일부를 슈퍼클래스에서 구현한 메소드에 의존해야한다는 단점이 있다. (상속보다 구성을!)
모든 소스코드는 여기에서 확인할 수 있다.