
하나의 상황을 가정해보자.
학교 선생님이 반 아이들을 방학 동안 특급 우등생으로 관리하기 위해,
매일 일과표를 작성하여 제출하라고 공지했다.
아이들은 매일 시간대별로 계획표를 작성하여 선생님께 전달해야 한다.
... 매일 일과표를 작성하라니.
불만이 가득한 나는 씩씩거리면서도 어쩔 수 없이 일과표를 작성하기 시작한다.
하지만 규칙적인 생활을 유지하는게 모토인 나는,
작성하다보니 특정 시간대를 제외하고는 매일 같은 나날을 보내고 있었다!
[1일차]
08:00 ~ 09:00 : 기상 및 아침식사
09:00 ~ 10:00 : 아침 운동 및 세안
10:00 ~ 12:00 : 독서
12:00 ~ 13:00 : 점심식사
13:00 ~ 18:00 : 수학 공부 // ** 이 부분만 다르다 **
18:00 ~ 19:00 : 저녁 식사
19:00 ~ 21:00 : 자유시간
21:00 ~ 22:00 : 뉴스 시청
22:00 ~ 24:00 : 외국어 공부
24:00 ~ 취침
[1일차]
08:00 ~ 09:00 : 기상 및 아침식사
09:00 ~ 10:00 : 아침 운동 및 세안
10:00 ~ 12:00 : 독서
12:00 ~ 13:00 : 점심식사
13:00 ~ 18:00 : 영어 공부 // ** 이 부분만 다르다 **
18:00 ~ 19:00 : 저녁 식사
19:00 ~ 21:00 : 자유시간
21:00 ~ 22:00 : 뉴스 시청
22:00 ~ 24:00 : 외국어 공부
24:00 ~ 취침
낮에 어떤 공부를 할지만 다른데, 일과표는 전체를 작성해서 내라니!
씩씩거리던 나는 도저히 참을 수 없어 작성하던 일과표를 구겨서 던져버렸다.
뭔가 좋은 방법은 없을까?

이 상황에서 눈여겨보아야 할 것은,
나의 일과표를 변하지 않는 부분과 변하는 부분으로 나눌 수 있다는 것이다.
변하지 않는 부분을 고정해두고 변하는 부분만 수정해서 제출할 수 있다면
매일 일과표를 제출하라는 귀찮은 일도 어느정도 수긍이 가능할 것 같다.
이렇듯 개발을 하면서 객체마다 특정한 부분을 수행하는 작업이 고정되어 있다면
이것을 변하지 않는 부분으로 간주하고 이로부터 변하는 부분을 분리해냈을 때,
더욱 효율적으로 코딩을 할 수 있을 것 같다!

GoF에서는 템플릿 메서드 패턴의 정의를 다음과 같이 설명한다.
알고리즘의 골격을 정의하고 일부 단계를 하위 클래스로 연기한다.
하위 클래스는 알고리즘 자체의 구조를 변경하지 않고도 특정 단계를 재정의할 수 있다.
여기서 중요한 것은 하위 클래스라는 단어가 등장한다는 점이다.
... 그렇다!
템플릿 메서드 패턴에는 상속이 사용되고,
특정 단계를 재정의하는 것이 바로 오버라이딩이다!
이를 통해 우리는 다형성을 이용할 수 있을 것 같다.
그렇다면 어떻게 템플릿 메서드 패턴을 만들어볼 수 있을까?

abstract class Daily {
public void action() {
// 아침 일정
study();
// 저녁 일정
}
public abstract void study();
}
Daily 클래스는 하루 일과를 나타내는 클래스이다.
나는 점심에 어떤 공부를 할지만 다르기 때문에, 공부할 부분만 수정하면 된다.
어떤 공부를 할 지는 매일 다르기 때문에 구현해야할 메서드로 정의하여
하위 클래스로 구현 단계를 연기하고,
아침 일정과 저녁 일정은 알고리즘의 골격으로 고정한다.
class MathDaily extends Daily {
@Override
public void study() {
// 수학 공부
}
}
class EnglishDaily extends Daily {
@Override
public void study() {
// 영어 공부
}
}
MathDaily는 하루 일정 중 점심에 수학 공부를 하도록,
EnglishDaily는 하루 일정 중 점심에 영어 공부를 하도록 메서드를 오버라이딩하여
구현하려던 알고리즘의 특정 단계를 재정의하는 것이다.

Daily mathDaily = new MathDaily();
Daily englishDaily = new EnglishDaily();
mathDaily.action(); // 모든 일정은 같지만 수학 공부 일정만 다름
englishDaily.action(); // 모든 일정은 같지만 영여 공부 일정만 다름
다형성을 이용하여 MathDaily, EnglishDaily 객체를 생성하고 action()를 호출하면
아침과 저녁 일정은 고정되어 그대로 수행하지만,
점심 일정은 매번 다른 공부를 하는 구현한 자식 객체의 study() 메서드가 호출된다.
변하지 않는 부분과 변하는 부분을 분리한 후 다형성을 이용하여
변하는 부분만을 추상 메서드로 추출해 오버라이딩하도록 유도하면
클래스마다 수행해야 하는 작업을 반복 수행하지 않도록 만들어낼 수 있다.

Daily MathDaily = new Daily() {
@Override
public void study() {
// 수학 공부
}
};
템플릿 메서드 패턴은 변하는 부분을 정의하기 위해
매번 클래스를 생성해야 한다는 단점이 있다.
일과표의 경우 한달이 30일이라고 가정하면, 30개의 클래스를 생성해야 한다.
익명 클래스를 사용하면 클래스를 생성해야 하는 문제를 일부 극복할 수 있다.

매번 클래스를 생성해야 한다는 단점을 익명 클래스를 사용하여 극복한다고 하더라도
상속은 부모 클래스에 강하게 의존한다는 또 다른 단점이 존재한다.
이 때에는 상속이 아닌 구현을 통해 유연하게 대처할 수 있는
Strategy Pattern을 고려해보자.
알고리즘의 골격을 정의한 클래스 내부에
변하는 부분만을 인터페이스로 정의한 뒤 구현하여 사용하는 것이다.
마찬가지로 매번 인터페이스를 구현해야 하는 문제점은 익명 클래스로 극복하고
상속의 단점을 극복할 수 있는 디자인 패턴이다.

동일한 성질의 클래스를 설계하는 과정에서
반복적인 작업이 보이는 것은 생각보다 자주 발생하곤 한다.
개발자라면 반복하는 노가다 작업을 좋아하는 사람은 아무도 없을 것이라 생각한다.
이 때는 이상 현상을 감지하고,
변하는 부분과 변하지 않는 부분을 분리하여 변하는 부분만을 통제할 수 있는
다형성을 이용한 Template Method Pattern을 떠올려보자!