행동패턴 중 하나인 템플릿 메서드 패턴을 알아봅시다.
의도
템플릿 메서드 패턴은 부모 클래스에서 알고리즘의 골격을 정의하지만, 해당 알고리즘의 구조를 변경하지 않고 자식 클래스들이 알고리즘의 특정 단계들을 오버라이드 할 수 있도록 하는 행동 디자인 패턴입니다.
추상클래스인 부모를 두고 메인 로직을 작성한 뒤 로직 속에 있는 세부 단계들을 자식 클래스들이 오버라이드 하는 형태입니다.
문제
템플릿 메서드 패턴을 쓰게 되면 어떤 문제를 해결할 수 있을지 알아봅시다.
예를 들어서 소셜 네트워크를 통해 메신저를 제공하는 서비스가 있다고 합시다.
처음에는 트위터 서비스를 통해 메세지 전송 기능을 사용하였습니다.
메세지 전송은 로그인 -> 메세지 전송 -> 로그아웃 순의 로직이 있습니다.
시간이 흘러 페이스북 서비스를 추가하려고 합니다.
기존 로직 변경없이 페이스북을 추가하고 싶습니다.
메세지 전송 로직은 그대로 둔채 트위터 대신 페이스북으로도 변경하고 싶습니다.
해결책
템플릿 메서드 패턴은 알고리즘을 일련의 단계들로 나누고, 이러한 단계들을 메서드들로 변환한 뒤 단일 템플릿 메서드 내부에 이러한 메서드들에 대한 일련의 호출(메서드)들을 넣으라고 제안합니다. 이러한 단계(메서드)들은 추상 메서드이거나 디폴트 메서드 구현을 가질 것입니다. 알고리즘을 사용하기 위해 클라이언트는 자신의 자식 클래스를 제공해야하고 모든 추상 메서드를 구현하고 디폴트 메서드를 오버라이드 해야합니다.
예시
public abstract class Network {
protected String username;
protected String password;
public Network(String username, String password) {
this.username = username;
this.password = password;
}
public boolean post(String message) {
if (login()) {
boolean result = sendMessage(message);
logout();
return result;
}
return false;
}
abstract boolean login();
abstract boolean sendMessage(String message);
abstract void logout();
}
Network라는 추상 클래스를 만들었습니다.
post()라는 템플릿 메서드를 만들었습니다. 템플릿 메서드는 메세지 전송이라는 알고리즘을 구현하고 있습니다. 템플릿 메서드 안에는 알고리즘에 필요한 단계들로 나눠져 있습니다. 클라이언트는 필요한 단계(추상 메서드)들을 구현해야합니다.
public class FaceBook extends Network {
public FaceBook(String username, String password) {
super(username, password);
}
@Override
boolean login() {
if (this.username.equals("user") && this.password.equals("1234")) {
System.out.println("페이스북 로그인 성공!");
return true;
}
return false;
}
@Override
boolean sendMessage(String message) {
System.out.println(message + "를 보냈습니다!");
return true;
}
@Override
void logout() {
System.out.println("user를 로그아웃합니다!");
}
}
public class Twitter extends Network {
public Twitter(String username, String password) {
super(username, password);
}
@Override
boolean login() {
if (this.username.equals("user") && this.password.equals("1234")) {
System.out.println("트위터 로그인 성공!");
return true;
}
return false;
}
@Override
boolean sendMessage(String message) {
System.out.println(message + "를 보냈습니다!");
return true;
}
@Override
void logout() {
System.out.println("user를 로그아웃합니다!");
}
}
페이스북(클라이언트) 을 만들어 필요한 단계(메서드)들을 구현했습니다.
똑같이 트위터도 추상 클래스인 Networt를 상속받아 필요한 단계들을 구현했습니다.
public class Demo {
public static void main(String[] args) {
Network network = null;
network = new FaceBook("user", "1234");
network.post("안녕 페이스북?");
System.out.println("----------------------");
network = new Twitter("user", "1234");
network.post("안녕 트위터?");
}
}
서비스에서 페이스북으로 서비스를 생성하여 post해보고 트위터로 서비스를 생성하여 post를 해보겠습니다.

장점
- 클라이언트들이 대규모 알고리즘의 특정 부분만 오버라이드하여 알고리즘의 다른 부분에 발생하는 변경에 영향을 덜 받도록 함
- 클라이언트에서 중복되는 코드를 부모 클래스로 가져올 수 있음
단점
- 일부 클라이언트들은 알고리즘의 제공된 골격에 의해 제한될 수 있음(특정 알고리즘에만 적합한 클라이언트..)
- 자식 클래스를 통해 디폴트 단계 구현을 오버라이드?하여 리스코프 치환 원칙을 위반할 수 있음(자식 객체가 부모 객체를 대체할 수 없음)
- 템플릿 메서드들은 단계가 많을수록 유지하기 어려운 경향이 있음
'리팩토링 > 디자인패턴' 카테고리의 다른 글
| [디자인패턴] 상태패턴 (3) | 2023.01.01 |
|---|---|
| [디자인 패턴] 데코레이터 패턴 (3) | 2022.12.26 |
| [디자인패턴] 퍼사드 패턴 (1) | 2022.11.26 |
| [디자인패턴] 어댑터 패턴 (1) | 2022.11.14 |
| [디자인패턴] 팩토리 메서드 패턴, 추상 팩토리 패턴 (1) | 2022.10.30 |