Design Patterns

[디자인 패턴] 템플릿 콜백 패턴 (Template Callback Pattern)

jngsngjn 2025. 1. 30. 19:48

 템플릿 콜백 패턴이란?

  • 반복적으로 사용되는 로직을 템플릿 메서드로 정의하고, 변경이 필요한 부분을 콜백 함수(람다, 익명 클래스, 인터페이스 구현 등)로 전달하는 패턴이다.
  • 즉, 고정된 템플릿(공통 로직)과 유연한 콜백(변경될 로직)을 분리하여 재사용성을 높이는 패턴이다.
  • 전략 패턴과 유사하지만, 전략을 메서드 파라미터(콜백)로 받는다는 점에서 차이가 있다.
  • Spring Framework에서 JdbcTemplate, TransactionTemplate 등이 대표적인 예시이다.

핵심 개념

  • 템플릿 메서드
    • 공통적인 흐름을 담당하는 메서드
    • 변동되는 특정 부분을 콜백으로 위임
  • 콜백
    • 변경이 필요한 부분을 담당
    • 익명 클래스, 람다식, 인터페이스 구현체 등 다양한 방식으로 제공 가능

 장단점

장점

  • 코드 재사용성 증가: 반복되는 코드를 템플릿을 통해 재사용
  • 유연성 향상: 고정된 템플릿 내에서 콜백을 변경하여 다양한 동작 수행 가능

단점

  • 가독성 저하 가능: 콜백 코드가 많아지면 가독성이 떨어질 수 있음
  • 디버깅 어려움: 콜백이 익명 클래스, 람다식으로 전달되면 흐름을 추적하기 어려울 수 있음

 예제 코드: 파일 처리 시스템

1️⃣ 예제 시나리오

  • 파일을 읽는 기능은 필요하지만, 파일을 읽은 후 어떤 작업을 할지는 다를 수 있음
  • 이 경우, 파일 읽기 로직과 후처리 로직을 템플릿 콜백 패턴을 적용하여 분리할 수 있다.

2️⃣ 템플릿 (고정된 공통 로직)

// 템플릿 클래스: 파일을 한 줄씩 읽고, 후처리(콜백)를 실행하는 역할
public class FileProcessor {

    public void processFile(String filePath, FileCallback callback) {
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) { // 파일을 한 줄씩 읽음 (공통 로직)
                callback.process(line); // 콜백 실행 (변경 가능한 부분)
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

3️⃣ 콜백 인터페이스 (변경될 로직 정의)

// 콜백 인터페이스: 파일에서 읽을 데이터를 처리하는 역할
public interface FileCallback {
    void process(String line);
}

4️⃣ 사용 예제

public class AppMain {
    public static void main(String[] args) {
        FileProcessor processor = new FileProcessor();
        String filePath = "file/sample.txt"; // 테스트할 파일

        // ✅ 콜백1: 읽은 파일 내용을 모두 대문자로 변환
        processor.processFile(filePath, line ->
            System.out.println("대문자로 변환: " + line.toUpperCase())
        );

        // ✅ 콜백2: 파일의 단어 개수 세기
        processor.processFile(filePath, line -> {
            int wordCount = line.split("\\\\s+").length;
            System.out.println("단어 개수: " + wordCount);
        });

        // ✅ 콜백3: "특정 단어 포함 여부 확인" (예: "error" 찾기)
        processor.processFile(filePath, line -> {
            if (line.contains("error")) {
                System.out.println("에러 메시지 발견: " + line);
            }
        });
    }
}

5️⃣ 실행 결과 예시

📄 sample.txt

Hello world
This is a test
An error occurred in the system

 

🖥 실행 결과

대문자로 변환: HELLO WORLD
대문자로 변환: THIS IS A TEST
대문자로 변환: AN ERROR OCCURRED IN THE SYSTEM
단어 개수: 2
단어 개수: 4
단어 개수: 6
에러 메시지 발견: An error occurred in the system

사용 예제에서 람다식을 사용해서 콜백을 전달했지만, 아래와 같이 구체 클래스로 정의하여 재사용성을 향상시키는 방법도 있다.

public class UpperCaseCallback implements FileCallback {
    @Override
    public void process(String line) {
        System.out.println("대문자로 변환: " + line.toUpperCase());
    }
}
public class AppMain {
    public static void main(String[] args) {
        FileProcessor processor = new FileProcessor();
        String filePath = "file/sample.txt";

        processor.processFile(filePath, new UpperCaseCallback());
    }
}