[그린컴퓨터] Server/JAVA(객체 지향 프로그래밍)

템플릿 메서드 { 추상 클래스와 템플릿 메서드, 템플릿 메서드의 역할, final }

Ben의 프로그램 2023. 6. 1. 10:38
728x90

추상 클래스와 템플릿 메서드 (무슨 관계일까?)

  • 추상 클래스를 활용한 예가 바로 템플릿 메서드입니다.
  • '템플릿 template' 이란 용어는 무엇을 뜻할까요?
  • 사전에서 보면 틀이나 견본을 뜻합니다. 
  • 틀이 있는 메서드라는 의미지요. 
  • 템플릿 메서드는 05장에서 소개한 싱글톤 패턴과 같은 디자인 패턴입니다.  (이전 포스팅 참조)
  • 즉 템플릿 메서드는 디자인 패턴의 한 방법으로 모든 객체 지향 프로그램에서 사용하는 구현 방법입니다. 
  • 따라서 이 구현 방법은 자바뿐 아니라 C++, C# 에서도 동일하게 적용됩니다. 
  • 예시를 통해서 알아보겠습니다. 
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( ) 2개의 추상 메서드와 3개의 구현된 메서드를 가지고 있습니다.
  • 시동을 끄고 켜는 것은 어떤 차이던 간에 모두 같기 때문에 일반 메서드로 구현을 했습니다.
  • 반대로 주행과 멈추는 기능은 차종에 따라 다를 수 있기 때문에 추상 메서드로 구현을 했습니다. 
  • 제일 아래에 있는 run( )  메서드를 확인해보겠습니다. 
  • run( ) 메서드는 시동을 켜고, 달리고, 멈추고, 시동을 끄는 모든 메서드를 사용합니다. 
  • 만약 Car 클래스를 상속받으면 어떤 자동차든 모두 이 순서대로 동일한 방식으로 달리는 것입니다. 

  • Car 클래스를 상속 받을 클래스를 2개 구현해 보겠습니다. 
  • 자율 주행 자동차와 일반 자동차 클래스들은 추상 클래스 Car 를 상속받았기 때문에 구현되지 않은 추상 메서드를 마저 구현해야 합니다. 
  •  AI 클래스와 Manual 클래스를 구현해보도록 하겠습니다. 
public class AICar extends Car {

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

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

}

 

public class ManualCar extends Car{

	@Override
	public void drive() {
		System.out.println("사람이 운전합니다");
		System.out.println("사람이 핸들을 조작합니다");
	}

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

}
  • 두 클래스 모두 상속받은 추상 메서드를 구현했습니다.
  • 이제 테스트 프로그램을 만들어서 두 자동차의 동작을 확인해보겠습니다. 
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();
	}

}

템플릿 메서드의 역할 (final 예약어)

  • CarTest 에서 두 개의 인스턴스를 생성했었습니다.
  • 그리구 run( ) 메서드를 호출했습니다.
  • run( ) 메서드는 Car 클래스에서 이미 구현된 메서드입니다. 
  • 차가 달리고 멈추는 과정은 어느 차이건 모두 동일합니다. 다만 상세한 방법들이 다를 뿐이죠.
  • 이렇게 템플릿 메서드의 역할을 메서드 실행 순서와 시나리오를 정의하는 것입니다. 
  • 템플릿 메서드 안에는 추상 메서드와 일반 메서드 모두 올 수 있습니다. 
  • 템플릿 메서드에서 호출하는 메서드가 추상 메서드라면 차종에 따라 구현 내용이 바뀔 수 있습니다. 
  • 우리가 보았던 예제에서 바뀌었던 것과 마찬가지로 말이죠. 
  • 하지만 시동을 켜고, 달리고, 멈추고, 시동을 끄는 시나리오 자체는 변하지 않습니다.
  • 이런 메서드를 템플릿 메서드로 정의하는 것입니다.
  • 템플릿 메서드는 실행 순서, 즉 시나리오를 정의한 메서드이므로 바뀔 수 없습니다. 
  • 상위 클래스를 상속받은 하위 클래스에서 템플릿 메서드를 재정의하면 안 된다는 것입니다. 
  • 그래서 템플릿 메서드는 final 예약어를 사용해 선언합니다. 
  • 메서드 앞에 final 을 사용하면 상속받은 하위 클래스가 메서드를 재정의할 수 없습니다. 
  • 템플릿 메서드는 로직 흐름이 이미 정해져 있는 프레임워크에서 많이 사용하는 기본 구현 방법입니다. 

템플릿 메서드와 final 예약어 정리하자면!

  • 추상 클래스는 하위 클래스에서도 사용할 수 있는 코드를 구현합니다.
  • 그런데 일반 메서드는 하위 클래스에서 재정의할 수 있습니다.
  • 즉 start( ) 와 turnOff( ) 도 추가 기능이 필요하다면 하위 클래스에서 재정의해서 사용하면 됩니다. 
  • 하지만 템플릿 메서드는 로직 흐름을 정의하는 역할을 수행합니다.
  • 템플릿 메서드는 하위 클래스에서 재정의를 통해서 수정이 되어서는 안되는 메서드이다. 
  • 따라서 하위 클래스에서 수정을 할 수 없게 만드는 예약어 final 을 함께 사용하여 템플릿 메서드를 선언합니다.

final 좀 더 알아보기

  • final 예약어는 쓰이는 위치에 따라 수행하는 역할이 달라집니다. 
  • 변수 앞에 사용하면 값을 변경할 수 없게 됩니다. 변수가 상수가 됩니다. 
  • 메서드 앞에 사용하면 재정의할 수 없는 메서드가 됩니다.
  • 클래스 앞에 사용하면 상속될 수 없는 클래스가 됩니다.