08.Tempalte Method Pattern

2025. 8. 30. 18:23
반응형
Generated Document

들어가기

두 가지 이상의 클래스에서 유사한 알고리즘을 공유해야 할 때 유용한 디자인 패턴이다.
오늘은 이에 대해서 알아보려고 한다.

필요한 예시

앞서 말했 듯이 두 가지 이상의 클래스에서 유용하다고 적었는데,
구체적으로 어떨때 필요할까 ?

프로젝트 중에서 소셜 로그인 부분을 구현해야 한다고 해보자.
우리가 흔히 하는 소셜 로그인은 네이버 , 카카오 , 구글 등 이 있을 것이다.

이때 카카오의 경우 AccessCode 를 통해 AccessToken 을 받는 로직이
다른 소셜로그인에 비해 필요하다고 가정해보자

NaverLogin.java

public class NaverLogin {
	public void login(){
		getInfoFromPage();
		getAccessToken();
		requestAuthServer();
	}
} 

KakaoLogin.java

public class KakaoLogin{
	public void login(){
		getInfoFromPage();
		getAccessCode();
		getAccessToken();
		requestAuthServer();
	}
}

KakaoLogin 의 getAccessCode() 를 제외하고 나머지 부분들은 Naver, Kakao, Goolge 로그인이
동일할때 추상 클래스를 사용해서 해결할 수 가 있다.

구현 과정

추상 클래스를 사용해보면 다음과 같다.

public abstract class AbstractSocialLogin {
	public final void login() {
	      getInfoFromPage();
        getAccessCode(); 
        getAccessToken();
        requestAuthServer();
	}
    // 훅 메서드: 모든 소셜 로그인에 공통된 단계 (기본 구현)
    protected void getInfoFromPage() {
        System.out.println("로그인 페이지에서 정보를 가져옵니다.");
    }
    
    // 추상 메서드: 하위 클래스에서 반드시 구현해야 할 단계
    protected abstract void getAccessToken();
    protected abstract void requestAuthServer();    
    
    // 훅 메서드: 필요에 따라 하위 클래스에서 재정의하는 단계
    protected void getAccessCode() {
        // 기본 구현은 아무것도 하지 않음 (네이버처럼 필요 없는 경우)
    }
} 

코드를 하나씩 뜯어보면 다음과 같다.

final void login()
공통으로 사용하는 메서드는 final 로 선언하여 하위 클래스에서 순서등을 바꾸지 못하게 한다.

protected void getInfoFromPage()
해당 메서드는 공통으로 사용되는 부분이기 때문에 추상클래스에서 정의 하였다.

protected abstract void getAccessToken(); protected abstract void requestAuthServer();
하위 클래스 마다 로직이 다르고 반드시 구현해야하는 메서드이기 때문에 추상 메서드로 선언한다.

protected void getAccessCode()
선택적으로 구현할 수 있도록 빈 메서드로 선언한다. 필요에 따라서 하위 클래스에서
수행할 수 있도록 한다.

이러한 추상 클래스를 정의하고 적용하면 다음과 같다.

NaverLogin.java

public class NaverLogin extends AbstractSocialLogin {

    @Override
    protected void getAccessToken() {
        System.out.println("네이버 API에서 Access Token을 바로 요청합니다.");
    }

    @Override
    protected void requestAuthServer() {
        System.out.println("네이버 인증 서버에 최종 로그인 요청을 보냅니다.");
    }
}

KakaoLogin.java

public class KakaoLogin extends AbstractSocialLogin {

    // 카카오에만 필요한 단계이므로 메서드를 재정의합니다.
    @Override
    protected void getAccessCode() {
        System.out.println("카카오 API에서 Access Code를 받습니다.");
    }

    @Override
    protected void getAccessToken() {
        System.out.println("Access Code를 사용해 Access Token을 받습니다.");
    }

    @Override
    protected void requestAuthServer() {
        System.out.println("카카오 인증 서버에 최종 로그인 요청을 보냅니다.");
    }
}

위 처럼 사용하면 조금 더 코드를 간결하게 사용할 수 있다.

Template Method 조금 더 자세히


Hook

추상 클래스에서 선언 되지만 기본 내용만 구현되어 있거나
아무 코드도 들어 있지 않은 메서드를 말한다.

위의 AbstractSocialLogin 에서 getAccessCode(), getInfoFromPage() 메서드를 말한다.

이처럼 서브클래스가 필요할 때마다 사용하게 두는 것을 말하는데,
서브클래스에 코드를 위임하는 것이라고 말 할 수 있다.


추상 메서드 남발하지 않기

서브 클래스가 필수적으로 정의해야하는 부분을 추상 메서드로 정의하고
그 구성을 하위 클래스가 할 수 있도록 하는데, 이를 남발하면 서브 클래스 정의할 때
불편할 수 있기 때문에 조심해야한다.


Java 에서 다양한 템플릿 메서드

이런 템플릿 메서드는 생각보다 다양한 곳에서 우리도 모르게 사용되고 있었다.
한 예로 AbstractList 클래스가 있다. 이를 통해 개발자들이 자신이 정의한 List 를 정의하고
정렬에 사용할 수 있다.


장단점

장점

  • 코드 재사용 및 중복 감소

    위와 같이 일일히 같은 구조의 클래스들을 정의할 필요가 없어진다.

  • 유지보수 용이

    추상클래스의 핵짐적인 요소만 변경하면 되기 때문에 유지보수에 용이 하다.

  • 일관된 구조 유지

    final 로 선언된 핵심메서드가 고정적이기 때문에 일관적인 구조를 유지할 수 있다.

단점

  • 복잡성 증가

    추상클래스를 하나 더 두어 계층이 늘어나며 이로 인한 코드 추적이 복잡해진다.

  • 유연성 부족

    핵심 메서드의 final 선언때문에 정해진 절차 변경이 어렵다.

  • 상속에 대한 의존성

    추상메서드를 상속해서 사용하기 때문에 상위 클래스의 변경이 모든 하위클래스에 적용된다.

반응형

BELATED ARTICLES

more