본문 바로가기
백엔드/Java

[Java] 템플릿 메서드 패턴, 전략 패턴, 템플릿 콜백 패턴

by 작은소행성 2024. 4. 18.

템플릿 메서드 패턴

템플릿 메서드 패턴이란, 여러 클래스에서 공통으로 사용하는 메서드를 템플릿화하여 상위클래스에서 정의하고 하위 클래스마다 세부 동작을 다르게 구현하는 패턴이다. 

템플릿 메소드 패턴은 상속이라는 기술을 극대화하여, 알고리즘의 뼈대를 맞추는 것에 초점을 둔다.

 

변하지 않는 템플릿(기능)은 상위 클래스에만 만들어두고 

자주 변경되며 확장할 템플릿(기능)은 하위 클래스에서만 만든다.

이렇게 하 면 자식 클래스가 알고리즘의 전체 구조를 변경하지 않고, 특정 부분만 재정의할 수 있는데

하위 클래스를 사용해 상속과 오버라이딩을 통 한 다형성으로 문제를 해결하는 것이다. 

 

 

템플릿 메서드 패턴은 클래스를 계속 만들어야 하는 단점이 있는데 

익명 내무 클래스를 사용하면 이러한 단점을 보완할 수 있다. 

 

익명 내부 클래스를 사용하면 객체 인스턴스를 생성하면서 동시에 생성할 클래스를 상속 받은 자식 클래스를 정의할 있다. 클래스는 `SubClassLogic1` 처럼 직접 지정하는 이름이 없고 클래스 내부에 선언되는 클래스여서 익명 내부 클래스라고 한다. 

 

 

익명 내부 클래스란 

익명 클래스는 다른 내부 클래스들과 달리 이름이 없다. 

클래스 선언과 객체의 생성을 동시에 하기 때문에 번만 사용될 있고 하나의 객체만을 사용할 있는 일회용 클래스이다. 

@RestController
@RequiredArgsConstructor
public class AnonymousController {

    @GetMapping
    public void AnonymousTest() {

        @Override
        public void method(){
             log.info(“익명 클래스, 한 번 사용하고 끝임”);
        }        
    }
}

 

템플릿 메서드 패턴의 장점

- 상위 클래스의 로직을 공통화해 코드 중복을 줄인다.

- 서브 클래스의 역할을 줄이고 상위 클래스에서 관리하므로 코드 관리가 용이해진다.

 

템플릿 메서드 패턴의 단점 

- 알고리즘 구조가 복잡해지면 템플릿 로직 형태를 유지하기 어렵다.

- 추상 메서드가 많아지면 클래스의 생성, 관리가 어려워질 수 있다.

- 상위 클래스를 수정하면 하위 클래스가 영향을 받는다. 

 

 

 

 

전략 패턴 

템플릿 메서드 패턴과 공통점은 부모를 상속한다는 것이다. 

템플릿 메서드 패턴과 비슷한 역할을 하면서 상속의 단점을 제거할  있는 패턴이 바로 전략 패턴(Strategy Pattern)이다. 

스프링에서 사용하는 의존성 주입 방식이 전략 패턴이다. 

 

 

예제

Context(문맥)는 변하지 않는 로직을 가진 템플릿 역할을 하는 코드이다. 

이 문맥 속에서 Strategy(전략)를 통해 일부 전략이 변경된다고 생각하면 된다. 

이 전략 패턴의 핵심은 Context는 Strategy 인터페이스에만 의존한다는 것이다. Strategy를 변경해도 Context에는 영향을 주지 않는다. 

@Slf4j
public class ContextV1 {

    private Strategy strategy;

    public ContextV1(Strategy strategy) {
        this.strategy = strategy;
    }

    public void execute() {
        long startTime = System.currentTimeMillis();
        //비즈니스 로직 실행
        strategy.call(); //위임
        //비즈니스 로직 종료
        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("resultTime={}", resultTime);
    }
}

 

 

인터페이스는 변하는 알고리즘 역할을 한다. 

public interface Strategy {
    void call();
}

 

테스트를 위한 전략 코드 두개를 만든다 

// 전략 1 코드
@Slf4j
public class StrategyLogic1 implements Strategy {
    @Override
    public void call() {
        log.info("비즈니스 로직1 실행");
    }
}


// 전략 2 코드
@Slf4j
public class StrategyLogic2 implements Strategy {
    @Override
    public void call() {
        log.info("비즈니스 로직2 실행");
    }
}

 

 

전략 패턴의 사용 방식 

1. 조립 방식 (선 조립, 후 실행)

context 내부 필드에 strategy를 조립하고 사용하는 방식을 선 조립, 후 실행 이라고 하는데 

이러한 방식의 장점은 한번 연결하고 나면 context를 실행만 시키면 되는데 이러한 방식은 의존관계를 모두 맺고난 뒤 실제 요청을 처리하는 원리이다. 

단점으로는 조립한 이후에는 전략을 변경하기 번거롭다는 점이다. Context 싱글톤으로 사용할 때는 동시성 이슈 고려할 점이 많아서 context 하나 생성하고 그곳에 strategy 사용하는 것이 낫다. 

 

2. 파라미터 전달 방식

파라미터에 strategy를 전달받는 방식으로 사용하면 실행할 때마다 전략을 유연하게 변경해서 사용할 수 있는데

실행할 때마다 전략을 계속 지정해주어야 한다는 단점이 있다.

 

 

 

 

템플릿 콜백 패턴 

전략 패턴에서 전략 부분이 콜백으로 변경된 것이다. 

콜백코드는 호출(call) 한 곳에서 실행되지 않고 호출을 요청한 곳(back)에서 실행되는 코드를 말한다. 

해당 디자인 패턴은 GOF패턴은 아니고 스프링에서만 불리는 패턴이다. 

자바8 이전에는 익명 내부 클래스를 주로 사용했는데 자바8부터는 람다 형태로 사용한다. 

 

스프링에서는 `JdbcTemplate` , `RestTemplate` , `TransactionTemplate` , `RedisTemplate` 처럼 다양 템플릿 콜백 패턴이 사용된다. 스프링에서 이름에 `xxxTemplate` 있다면 템플릿 콜백 패턴으로 만들어져 있다 생각하면 된다. 

 

템플릿 콜백 패턴의 장단점

장점 

전략패턴은 별도의 전략 클래스가 필요하지만, 템플릿 콜백 패턴은 별도의 전략 클래스 없이 메소드에 매개변수 값으로 로직을 넘겨서 실행하기 때문에 전략 객체를 일일히 만들 필요가 없다

 

단점 

인터페이스에서 실제 사용할 클래스를 직접 선언하기 때문에 결합도가 증가한다. 

 

 

템플릿 콜백 패턴 예시 - RedisTemplate

스프링에서 사용하는 RedisTemplate 으로 실제 사용 코드를 찾아 보았다.

 

콜백 인터페이스에 해당하는 RedisCallBack이 있고 doInRedis 가 call 역할을 한다.

 

 

Context(Template)에 해당하는 부분이다. 

파라미터에서 받아와서 호출한다. 

 

 

클라이언트에서 delete 를 호출하면 아래 코드 내부에 있는 execcute가 호출되고 

이때 콜백을 람다로 넘긴다. 

그러면 execute 메서드에서 doInRedis가 호출된다. 

 

 

템플릿마다 다른 이름으로 사용될 수 있으며

콜백에 어떤 구현체를 넘겨주는지에 따라 유연하게 변경되는 부분만 교체할 수 있다. 

 

 

 

참고 

https://inf.run/rQEkx

 

스프링 핵심 원리 - 고급편 | 김영한 - 인프런

김영한 | 스프링의 핵심 원리와 고급 기술들을 깊이있게 학습하고, 스프링을 자신있게 사용할 수 있습니다., 핵심 디자인 패턴, 쓰레드 로컬, 스프링 AOP스프링의 3가지 핵심 고급 개념 이해하기

www.inflearn.com

 

반응형