JAVA

템플릿 메서드 (디자인패턴)

seungmin576 2024. 12. 24. 18:08

추상 클래스와 템플릿 메서드

템플릿(template) 이란 용어의 의미는 틀이나 견본을 뜻한다.

템플릿 메서드는 추상 클래스를 사용하여 구현할 수 있다.

 

package template;

public abstract class Car {
    public abstract void drive();
    public abstract void stop();
    
    public void startCar(){
        System.out.println("시동을 켭니다");
    }
    
    public void turnOff(){
        System.out.println("시동을 끕니다");
    }
    
    final public void run(){
        startCar();
        drive();
        stop();
        turnOff();  //템플릿 메서드
    }
}

Car 클래스를 생성했다. 이 클래스는 drive()와 stop() 추상 메서드와 3개의 구현된 메서드 startCar(), turnOff(), run()을 가지고 있다.

자동차 시동을 켜고 끄는 방법은 어느 차나 동일하다.

그래서 startCar()와 turnOff()는 미리 코드를 구현해 두었다.

drive()와 stop()은 차종에 따라 다른 방식으로 움직일  수 있다.

그래서 추상 메서드로 선언했다.

이 중 15 ~ 20행에 구현된 템플릿 메서드인 run() 메서드를 살펴보면 이 메서드는 자동차가 달리는 방법을 순서대로 구현해 두었다.

만약 Car 클래스를 상속받으면 어떤 자동차든 모두 이 순서대로 동일한 방식으로 달린다.

 

Car 클래스를 상속받을 클래스 2개 자율 주행 자동차(AICar)와 일반 자동차 (ManualCar)를 구현해보자.

이 클래스들은 추상 클래스 Car를 상속받았기 때문에 구현되지 않은 추상 메서드를 마저 구현해야한다.

AICar는 자율 주행이 가능하다.

사람이 시동을 켠 후에는 자동차가 알아서 주행을 한다.

ManualCar는 우리가 사용하는 보통 자동차이다.

사람이 시동을 켜고 핸들도 조작한다.

즉 자동차 종류에 따라 구현 내용이 달라지는 부분은 추상 메서드로 만들고, 공통으로 사용하는 메서드는 추상 클래스에 구현하여 상속 받아 사용한다.

 

  • AICar
package template;

public class AICar extends Car{
    @Override
    public void drive() {
        System.out.println("자율 주행한다.");
        System.out.println("자동차가 알아서 방향을 전환한다.");
    }

    @Override
    public void stop() {
        System.out.println("스스로 멈춘다.");
    }
}

AICar 클래스는 Car 클래스를 상속받았고 drive()와 stop() 추상 메서드를 구현했다.

 

  • ManualCar
package template;

public class manualCar extends Car{
    @Override
    public void drive() {
        System.out.println("사람이 운전 한다.");
        System.out.println("사람이 핸들을 조작한다.");
    }

    @Override
    public void stop() {
        System.out.println("브레이크로 정지한다.");
    }
}

ManualCar 클래스도 AICar 클래스와 마찬가지로 Car 클래스를 상속받았다.

그리고 추상 메서드 drive()와 stop()을 구현했다.

 

  • 테스트프로그램
package template;

public class CarTest {
    public static void main(String[] args){
        System.out.println("===== 자율 주행 자동차 =====");
        Car myCar = new AICar();
        myCar.run();

        System.out.println("==== 닝겐 운전 자동차 =====");
        Car hisCar = new manualCar();
        hisCar.run();
    }
}


템플릿 메서드의 역할

CarTest에서 두 개의 인스턴스(myCar, hisCar)를 생성했다.

그리고 run()을 호출했다.

run()은 Car 클래스에 이미 구현된 메서드이다.

차가 어떻게 달려야 하는지를 구현해 놓았고, 작동 순서는 어느 차나 동일하다.

이렇게 템플릿 메서드의 역할은 메서드 실행 순서와 시나리오를 정의하는 것이다.

템플릿 메서드에서 호출하는 메서드가 추상 메서드라면 차종에 따라 구현 내용이 바뀔 수는 있다.

하지만 시동을 켜고, 달리고, 멈추고, 시동을 끄는 시나리오는 변하지 않는다.

이런 메서드를 템플릿 메서드로 정의하는 것이다.

템플릿 메서드는 실행 순서, 즉 시나리오를 정의한 메서드이므로 바뀔 수 없다.

상위 클래스를 상속받은 하위 클래스에서 템플릿 메서드를 재정의하면 안 된다는 것이다.

그래서 템플릿 메서드는 final 예약어를 사용해 선언한다.

메서드 앞에 final을 사용하면 상속받은 하위 클래스가 메서드를 재정의할 수 없다.

템플릿 메서드는 로직 흐름이 이미 정해져 있는 프레임워크에서 많이 사용하는 기본 구현 방법이다.

 

정리하자면, 추상 클래스는 하위 클래스에서도 사용할 수 있는 코드를 구현한다.

그런데 일반 메서드는 하위 클래스에서 재정의할 수 있다.

start()와 turnOff()도 추가 기능이 필요하다면 하위 클래스에서 재정의해서 사용하면 된다.

하지만 템플릿 메서드는 로직 흐름을 정의하는 역할이다.

이 흐름은 모든 하위 클래스가 공통으로 사용하고 코드를 변경하면 안되기 때문에 final로 선언하는 것이다.

 

'JAVA' 카테고리의 다른 글

final  (2) 2024.12.26
템플릿 메서드 응용하기  (0) 2024.12.24
추상 클래스  (0) 2024.12.24
다운 캐스팅, instanceof  (1) 2024.12.23
다형성 활용하기  (0) 2024.12.23