템플릿 메서드 패턴에서는 자주 변경되는 점과 변경되지 않는 점을 부모와 자식 관계인 '상속 관계'로 해결한다. 하지만 단점으로 의존성이 높다.
전략 패턴(Strategy Pattern)
전략 패턴에서는 상속 관계를 '위임 관계'로 변경함으로써 의존성을 낮출 수 있다.
public class Context {
private final Strategy strategy;
public ContextV1(Strategy strategy) {
this.strategy = strategy;
}
public void execute(){
strategy.callLogic();
}
}
public interface Strategy {
void callLogic();
}
템플릿 콜백 패턴(Template Callback Pattern)
템플릿 콜백 패턴은 전략 패턴과 DI의 장점을 익명 내부 클래스 사용 전략과 결합해 독특하게 활용되는 패턴이다. 전략 패턴은 전략 알고리즘을 정해놓은 별도의 전략 클래스가 필요했지만, 템플릿 콜백 패턴은 별도의 전략 클래스 없이, 전략을 사용하는 메소드에 매개변수 값으로 전략 로직을 넘겨 실행하기 때문에 전략 객체를 일일이 만들 필요가 없다.
interface OperationStrategy {
int calculate(int x, int y);
}
//전략 패턴의 Context가 템플릿 역할
class OperationContext {
int calculate(int x, String operation, int y) {
System.out.println("연산 시작");
int result = execute(operation).calculate(x, y);
System.out.println("연산 종료");
return result;
}
// 익명 클래스를 Template 클래스 내에 아예 정의함으로써 클라이언트의 전략 주입 중복 코드를 줄임
// 연산 기호에 따라 OperationStrategy(전략) 구현 객체를 생성
private OperationStrategy execute(final String oper) {
return new OperationStrategy() {
public int calculate(int x, int y) {
int result = 0;
switch(oper) {
case "+" : result = x + y; break;
case "-" : result = x - y; break;
case "*" : result = x * y; break;
case "/" : result = x / y; break;
}
return result;
}
};
}
}
public class Client {
public static void main(String[] args) {
int x = 100;
int y = 20;
OperationContext cxt = new OperationContext();
//전략 패턴의 Strategy 부분이 CallBack 역할
int result = cxt.calculate(x, "+", y);
System.out.println(result); // 120
result = cxt.calculate(x, "-", y);
System.out.println(result); // 80
result = cxt.calculate(x, "*", y);
System.out.println(result); // 2000
result = cxt.calculate(x, "/", y);
System.out.println(result); // 5
}
}
//추가적으로 람다 패턴으로 리팩토링도 가능
인터페이스를 사용하지만, 실제 사용할 클래스를 직접 선언하기 때문에 결합도 증가하게 된다. 또한, Bean으로 등록되지 않아 싱글톤 객체가 되지 않게 된다. 하지만 무리하게 결합도를 낮추는 행위를 할 필요가 없다.
스프링의 JdbcTemplate
Spring이 제공하는 JdbcTemplate은 JDBC를 사용할 때 발생하는 대부분의 반복 작업을 템플릿 콜백 패턴을 사용해서 대신 처리해준다.
public interface JdbcCallback {
public PreparedStatement makePreparedStatement(Connection conn) throws SQLException;
}
//변하지 않는 부분 - 템플릿
public class JdbcTemplate {
private Connection getConnection(String url, String username, String password) throws SQLException{
return DriverManager.getConnection(url, username, password);
}
// SQL 쿼리 생성 및 실행
public void executeQuery(JdbcCallback callback, String url, String username, String password){
Connection conn = null;
PreparedStatement ps = null;
try {
conn = getConnection(url, username, password);
// 변하는 부분 - SQL 로직 수행 - 전략
ps = callback.setPreparedStatement(conn);
ResultSet result = ps.executeQuery();
//단순한 출력 로직
while (result.next()){
System.out.println(result.getString(1));
}
} catch (SQLException e){
e.printStackTrace();
} finally {
closeConnection(conn);
}
}
// DB 연결 끊기
private void closeConnection(Connection conn){
if (conn != null) {
try {
conn.close();
} catch (SQLException e){
e.printStackTrace();
}
}
}
}
3장에서는 템플릿 메소드 기법의 단점, 그리고 전략 패턴과 템플릿 콜백 패턴의 차이점에 대해서 다루고, 스프링에서 템플릿 기법이 적용된 예시를 살펴보았다.
추가적으로, 익명 클래스와 람다에 대해 조금 더 공부해야할 필요성을 느꼈다.
'Coding > 개발 서적' 카테고리의 다른 글
| [토비의 스프링 3.1 Vol 1] 06장. AOP (1) | 2025.04.16 |
|---|---|
| [Real MySQL 8.0 V1] 04장. 아키텍처 (0) | 2025.03.20 |
| [토비의 스프링 3.1 Vol 1] 05장. 서비스 추상화 (1) | 2025.03.11 |
| [토비의 스프링 3.1 Vol 1] 04장. 예외 (2) | 2025.02.27 |
| [토비의 스프링 3.1 Vol 1] 01장. 오브젝트와 의존 관계 (2) | 2025.01.23 |