[Design Pattern] Template Method Pattern
18 Jan 2018Template Method Pattern
실행 과정/단계는 동일한데 각 단계 중 일부의 구현이 다른 경우 사용할 수 있는 패턴
예시 상황
DB데이터와 LDAP을 이용해서 인증을 처리하는 클래스는 정보를 가져오는 부분의 구현만 다를 뿐 인증을 처리하는 과정은 완전히 동일할 수 있다.
DbAuthenticator
public class DbAuthenticator {
public Auth authenticate(String id, String pw) {
// 사용자 정보로 인증 확인
User user = userDao.selectById(id);
boolean auth = user.equalPassword(pw);
// 인증 실패 시 익셉션 발생
if (! auth)
throw new AuthException();
// 인증 성공시, 인증 정보 제공
return new Auth(id, user.getName());
}
}
LdapAuthenticator
public class LdapAuthenticator {
public Auth authenticate(String id, String pw) {
// 사용자 정보로 인증 확인
boolean auth = ldapClient.authenticate(pw);
// 인증 실패 시 익셉션 발생
if (! auth)
throw new AuthException();
// 인증 성공시, 인증 정보 제공
LdapContext ctx = ldapClient.find(id);
return new Auth(id, ctx.getAttribute("name"));
}
}
실행 과정을 구현한 상위 클래스와 실행 과정의 일부 단계를 구현한 하위 클래스로 구분할 수 있다.
DbAuthenticator와 LdapAuthenticator에서 동일했던 실행 과정을 템플릿 메서드(authenticate)로 구현하고 두 클래스에서 차이가 나는 부분은 하위 클래스에서 구현하도록 별도의 추상 메서드로 분리한다.
템플릿 메서드를 제공하는 Authenticator
public abstract class Authenticator {
// 템플릿 메서드
public Auth authenticate(String id, String pw) {
// 사용자 정보로 인증 확인
boolean auth = doAuthenticate(id, pw);
// 인증 실패 시 익셉션 발생
if (! auth) {
throw new AuthException();
}
// 인증 성공시, 인증 정보 제공
return createAuth(id);
}
// 하위 클래스에서 구현해야 할 부분을 추상 메서드로 분리한다.
protected abstract boolean doAuthenticate(String id, String pw);
protected abstract Auth createAuth(String id);
}
템플릿 메서드 패턴을 적용한 LdapAuthenticator의 구현
public class LdapAuthenticator extends Authenticator {
@Override
protected boolean doAuthenticate(String id, String pw) {
return ldapClient.authenticate(id, pw);
}
@Override
protected boolean createAuth(String id) {
LdapContext ctx = ldapClient.find(id);
return new Auth(id, ctx.getAttribute("name"));
}
}
템플릿 메서드와 전략 패턴의 조합
상속이 아닌 조립 방식으로 템플릿 메서드 패턴을 활용할 수 있다.
템플릿 메서드(TransactionTemplate.execute())는 파라미터로 전달받은 action의 메서드를 호출하고 있다. action으로 적절한 전략을 전달해서 원하는 기능을 구현할 수 있다.
public class TransactionTemplate {
// 템플릿 메서드
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
...
action.doInTransaction(status);
...
}
}
템플릿 메서드 사용
public class Client {
TransactionTemplate transactionTemplate = new TransactionTemplate();
transactionTemplate.execute(
new TransactionCallback<String>() {
public String doInTransaction(TransactionStatus status) {
...
}
}
);
}