템플릿 메서드 패턴과 전략 패턴에 대해 알아보다 보니 템플릿 콜백에 대해서도 알고 싶어졌다. 템플릿 콜백 패턴은 GOF의 디자인 패턴은 아니지만 스프링에서 많이 사용되는 디자인 패턴이다.
프로그래밍에서 콜백 or 콜애프터 함수는 다른 코드의 인수로서 넘겨주는 실행 가능한 코드를 말한다. 콜백을 넘겨받는 코드는 이 콜백을 필요에 따라 즉시 실행할 수도 있고, 나중에 실행할 수 있다.
쉽게 말하면 콜백은 코드가 호출은 되는데 코드를 넘겨준 곳의 뒤에서 실행된다는 의미이다.
위에서 언급했듯이 템플릿 콜백 패턴은 GOF의 디자인 패턴은 아니다. 이는 전략 패턴에서 템플릿과 콜백 부분이 강조된 패턴이라고 이해하면 된다.
스프링에서는 다양한 콜백 패턴이 사용되고 있는데 예를 들어 JdbcTemplate, RestTemplate, TransactionTemplate, RedisTemplate 등의 템플릿을 응용하여 사용한다.
템플릿 콜백 패턴과 전략 패턴 모두 특정 부분의 로직을 분리하여 유연성을 높이는 패턴이지만 템플릿 콜백 패턴은 일반적으로 익명 함수나 람다를 활용하여 콜백 함수를 주입하지만 전략 패턴은 전략을 정의하는 인터페이스를 통해 구체적인 전략을 주입한다.
public interface TeamCallback<T> {
T call();
}
위의 코드는 외부에서 콜백 함수를 정의하는 것을 보여준다. 템플릿에서는 이 콜백 인터페이스를 주입받아 실행시할 때 call 메서드를 재정의하여 사용하면 된다.
이제 템플릿을 구현해보자.
public class TeamTemplate {
public <T> T execute(TeamCallback<T> teamCallback) {
long startTime = System.currentTimeMillis();
// 비즈니스 로직
T result = teamCallback.call();
long endTime = System.currentTimeMillis();
System.out.println("수행 시간 : " + (endTime - startTime) + "ms");
return result;
}
}
템플릿에 보면 execute 메서드는 콜백 함수를 가진 인터페이스를 파라미터로 주입받는다. 이렇게 됨으로써 execute 메서드는 공통적인 로직을 수행하고, 실제 비즈니스 로직은 call 메서드를 호출하여 수행한다.
@Test
void 템플릿_콜백_패턴() {
TeamTemplate teamTemplate = new TeamTemplate();
// 익명 클래스
teamTemplate.execute(new TeamCallback() {
@Override
public List<Team> call() {
return teamRepository.findAll();
}
});
// 람다식
teamTemplate.execute(() -> teamRepository.findAll());
}
클라이언트가 템플릿 콜백 패턴을 사용하는 테스트 코드이다. 사용자는 템플릿 객체를 생성하고 템플릿의 execute 메서드에 콜백 함수를 재정의하여 넘겨주어 코들 실행하도록 한다. 이렇게 콜백 함수를 익명 클래스나 람다식을 이용하여 주입하는 것이 이 템플릿 콜백 패턴의 핵심이다.
템플릿 메서드 패턴, 전략 패턴, 템플릿 콜백 패턴 모두 변하는 코드와 변하지 않는 코드를 분리할 수 있었다. 이중 템플릿 콜백 패턴이 가장 코드의 양이 적고 유연성이 좋다고 할 수 있다. 전략 패턴은 전략 객체를 인자로 받아 피룡한 시점에 해당 전략을 호출하지만 템플릿 콜백 패턴은 콜백 함수를 인자로 받고 이를 익명 함수나 람다식으로 구현하기 때문에 코드를 간결하게 작성할 수 있다.