public abstract class ReportGenerator {
// 템플릿 메서드
public final void generateReport() {
fetchData();
processData();
if (shouldFormatReport()) { // 후크 메서드 사용
formatReport();
}
printReport();
}
protected abstract void fetchData();
protected abstract void processData();
protected abstract void formatReport();
protected void printReport() {
System.out.println("Report is ready to be printed.");
}
// 후크 메서드: 하위 클래스에서 오버라이드 가능
protected boolean shouldFormatReport() {
return true; // 기본적으로 보고서는 형식을 갖추도록 설정
}
}
위 코드에서 shouldFormatReport 메서드가 후크 역할을 합니다. 이 메서드는 기본적으로 true를 반환하지만, 하위 클래스에서 이 메서드를 오버라이드하여 보고서를 형식화할지 여부를 결정할 수 있습니다.
하위 클래스 (Concrete Class)
public class SalesReportGenerator extends ReportGenerator {
@Override
protected void fetchData() {
System.out.println("Fetching sales data from the database...");
}
@Override
protected void processData() {
System.out.println("Processing sales data...");
}
@Override
protected void formatReport() {
System.out.println("Formatting sales report...");
}
}
public class InventoryReportGenerator extends ReportGenerator {
@Override
protected void fetchData() {
System.out.println("Fetching inventory data from the warehouse...");
}
@Override
protected void processData() {
System.out.println("Processing inventory data...");
}
@Override
protected void formatReport() {
System.out.println("Formatting inventory report...");
}
}
여기서 SalesReportGenerator와 InventoryReportGenerator는 각각 ReportGenerator의 하위 클래스이며, 각각의 보고서 유형에 맞게 데이터를 가져오고 처리하는 방식을 구현합니다.
클라이언트 코드
public class ReportService {
public void createReport(String type) {
ReportGenerator reportGenerator;
if ("sales".equalsIgnoreCase(type)) {
reportGenerator = new SalesReportGenerator();
} else if ("inventory".equalsIgnoreCase(type)) {
reportGenerator = new InventoryReportGenerator();
} else {
throw new IllegalArgumentException("Unknown report type: " + type);
}
reportGenerator.generateReport();
}
}
위 코드에서 ReportService는 클라이언트 역할을 하며, 사용자가 지정한 보고서 유형에 따라 적절한 ReportGenerator 하위 클래스를 선택하여 보고서를 생성합니다.
후크
후크 메서드는 부모의 템플릿 메서드의 영향이나 순서를 제어하고 싶을때 사용되는 메서드 형태입니다.
후크 메서드는 하위 클래스에서 선택적으로 Override할 수 있는 메서드로, 템플릿메서드에서 기본적으로는 아무런 동작도 하지 않지만, 필요에 따라 하위 클래스에서 구현하여 특정 동작을 추가/수정합니다.
상위 클래스
public abstract class ReportGenerator {
// 템플릿 메서드
public final void generateReport() {
fetchData();
processData();
if (shouldFormatReport()) { // 후크 메서드 사용
formatReport();
}
printReport();
}
protected abstract void fetchData();
protected abstract void processData();
protected abstract void formatReport();
protected void printReport() {
System.out.println("Report is ready to be printed.");
}
// 후크 메서드: 하위 클래스에서 오버라이드 가능
protected boolean shouldFormatReport() {
return true; // 기본적으로 보고서는 형식을 갖추도록 설정
}
}
위 코드에서 shouldFormatReport 메서드가 후크 역할을 합니다. 이 메서드는 기본적으로 true를 반환하지만, 하위 클래스에서 이 메서드를 오버라이드하여 보고서를 형식화할지 여부를 결정할 수 있습니다.
후크 메서드를 활용하는 하위 클래스
public class QuickReportGenerator extends ReportGenerator {
@Override
protected void fetchData() {
System.out.println("Fetching quick data...");
}
@Override
protected void processData() {
System.out.println("Processing quick data...");
}
@Override
protected void formatReport() {
System.out.println("Quick report does not require formatting.");
}
@Override
protected boolean shouldFormatReport() {
return false; // 이 보고서에서는 형식을 적용하지 않도록 설정
}
}
위 코드에서 QuickReportGenerator는 shouldFormatReport 후크 메서드를 오버라이드하여 보고서 형식을 건너뛰도록 설정했습니다. 이렇게 하여 기본 알고리즘의 흐름을 유지하면서도, 특정 단계에서는 동작을 변경할 수 있습니다.
장점
제어 역전
하위 클래스가 알고리즘의 전체 흐름을 제어하지 않습니다. 상위 클래스에서 전체 흐름을 주도합니다.
구현 세부사항 은닉
상위 클래스는 알고리즘의 구조를 알고 있지만, 구체적인 구현 세부사항은 하위 클래스에게 맡깁니다. 상위 클래스는 알고리즘의 전반적인 흐름을 유지하면서도, 세부 구현을 다양하게 변경할 수 있습니다.