OOP

예시로 이해하는 템플릿 메소드(Template Method) 패턴

짜비 2021. 6. 27. 20:28

동일한 절차를 따르되, 일부 과정만 다른 코드를 짜는 경우가 있다.

예를 들어 인증을 처리할 때, DB 데이터를 사용하는 경우와 LDAP을 사용하는 경우를 생각해보자.

 

1) DB 데이터를 이용한 인증 처리

public class DbAuthenticator{
	public Auth authenticate(String id, String pw){
    	//사용자 정보로 인증 확인
    	User user = userDao.selectById(id);
        boolean auth = user.equalPassword(pw);
        //인증 실패 예외 처리
        if(!auth)
        	throw createException();
        //인증 성공시, 인증 정보 제공
        return new Auth(id, user.getName());
    }
	
    private AuthException createException(){
    	return new AuthException();
    }

}

2) LDAP을 이용한 인증 처리

public class LdapAuthenticator{
	public Auth authenticate(String id, String pw){
    	//사용자 정보로 인증 확인
     	boolean lauth = ldapClient.authenticate(id,pw);
        
        //인증 실패 예외 처리
        if(!auth)
        	throw createException();
        //인증 성공시, 인증 정보 제공
        LdapContext ctx = ldapClient.find(id);
        return new Auth(id, dtx.getAttribute("name"));
    }
	
    private AuthException createException(){
    	return new AuthException();
    }

}

두 코드의 주석에 주목해보자. 인증 절차가 동일함을 알 수 있다. 두 코드는 일부 구현에서만 차이가 난다. 이렇게 실행 절차/단계는 같지만 일부 구현이 다를 때 사용할 수 있는 패턴이 바로 템플릿 메소드 패턴이다.

 

 

중복되는 부분이 많은 위 코드를 다음과 같이 구분해보자.

- 실행 과정을 구현한 상위 클래스

- 실행 과정의 일부 단계를 구현한 하위 클래스

 

먼저 실행 과정을 구현한 상위클래스 코드다.

public abstract Authenticator {
	//template method
    public Auth authenticate(String id, String pw){
    	if(!doAuthenticate(id,pw))
        	throw createException();
        return createAuth(id);
    }
    
    protected abstract boolean doAuthenticate(String id, String pw);
    
    private RuntimeException createException(){
    	throw new AuthException();
    }
    
    protected abstract Auth createAuth(String id);
}

구현 차이가 없던 '인증 시도 - 예외 처리 - 인증 결과 반환'  실행 과정은 authenticate() 메소드에 담았다.

그리고 구현 차이가 있었던 코드는 doAuthenticate(), createAuth()로 구현하기 위해 추상 메소드로 남겨 두었다.

 

 

실행 과정의 일부 단계를 구현한 하위 클래스 예시로, LdapAuthenticator를 살펴보자.

public class LdapAuthenticator extends Authenticator {
	
    @Override
    protected boolean doAuthenticate(String id, String pw){
    	return ldapClient.authenticate(id,pw);
    }
    
    @Override
    protected Auth createAuth(String id){
		LdapContext ctx = ldapClient.find(id);
        return new Auth(id, ctx.getAttribute("name"));
	}
}

 

추상 메소드를 implement했다. 특이한 점으로 접근자를 protected로 했는데, 이는 실행 과정의 일부 단계인 추상 메소드가 템플릿 메소드에서만 호출되기 때문이다. 따라서 public이 아닌 protected로 설정했다.

 

만약 새로운 인증 방식이 추가된다면 어떻게 될까?

새로운 인증방식 또한 '인증 시도 - 예외 처리 - 인증 결과 반환'  실행 과정을 거칠 가능성이 높다. 따라서 구현이 달라지는 일부 단계만을 하위 클래스로 구현하고, 상위 클래스인 Authenticator는 수정하지 않아도 된다.

 

이처럼 템플릿 메소드 패턴을 이용하면, 전체 실행 과정이 동일하고 일부 단계 구현만 다른 코드를, 중복성을 최대한 제거한 채 작성할 수 있다.

 

 

코드 출처, 참고 도서 : 개발자가 반드시 정복해야 할 객체 지향과 디자인 패턴, 최범균 지음, 인투북스