Java - 추상클래스와 템플릿 메서드 패턴

@hongo · August 31, 2022 · 4 min read

추상 클래스

  • 구현 코드 없이 메서드의 선언만 있는 추상 메서드(abstract method)를 포함한 클래스이다.
  • 상속만을 하기위해 만들어졌다고 봐도 무방하다.
  • 메서드 선언(declaration) : 반환타입, 메서드 이름, 매개변수로 구성
  • 메서드 정의(definition) : 메서드 구현(implementation)과 동일한 의미 구현부(body) 를 가짐 ({ })

예) int add(int x, int y); // 선언 int add(int x, int y){ } // 구현부가 있음, 추상 메서드 아님


  • abstract 예약어를 사용
  • 추상 클래스는 new 할 수 없음 ( 인스턴스화 할 수 없음 )

📌 예시

classes

위와 같은 구조를 갖는 클래스들이 있다고 하자. (기울어진 글씨체는 추상클래스or추상메서드임을 의미한다.)

public abstract class Computer {
	public abstract void display();
	public abstract void typing();
	public void turnOn() {
		System.out.print("turn on\n");
	}
	public void turnOff() {
		System.out.print("turn on\n");
	}
}
  • 추상클래스인 Computer는 메서드 선언부만 존재한 추상 메서드를 가질 수 있다.
  • 추상 메서드외에 일반 메서드도 가질 수 있다.

public class DeskTop extends Computer {

	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.print("desktop display\n");
	}

	@Override
	public void typing() {
		// TODO Auto-generated method stub
		System.out.print("desktop typing\n");
	}

}
  • 추상 클래스를 상속받는 DeskTop클래스이다.
  • DestTop은 추상 클래스인 Computer안에 있는 추상 메서드들을 모두 정의해줘야 일반 클래스로 동작할 수 있다.
  • 물론 모든 추상 메서드들을 정의했어도 추상클래스가 될 수 있다.

public abstract class NoteBook extends Computer {

	@Override
	public void typing() {
		// TODO Auto-generated method stub
		System.out.print("notebook typing");
	}

}
  • 추상 클래스를 상속받는 NoteBook클래스이다.
  • NoteBook은 추상 메서든 display()와 typing()중 typing()만 정의했지만 NoteBook역시 추상 클래스이기 때문에 모든 추상 메서드를 구체화하지 않아도 된다.

public class MyNoteBook extends NoteBook{

	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.print("my notebook display\n");
	}

	@Override
	public void turnOn() {
		// TODO Auto-generated method stub
		System.out.print("my notebook turn on");
	}

	@Override
	public void turnOff() {
		// TODO Auto-generated method stub
		super.turnOff();
	}

}

추상클래스 NoteBook을 상속받은 MyNoteBook클래스이다. NoteBook에서 구체화하지않은 display()를 구체화하고있다.



//ex

Computer desktop = new DeskTop(); // DeskTop은 Computer를 상속했으므로 업캐스팅이 가능하다.
Computer computer = new Computer(); // error : 추상클래스이므로 인스턴스 생성이 불가능하다

템플릿 메서드 패턴

  • 추상 메서드나 구현 된 메서드를 활용하여 코드의 흐름(시나리오)를 정의하는 메서드이다.
  • 코드의 흐름이 바뀌면 안되기 때문에 final로 선언하여 하위 클래스에서 재정의 할 수 없게 한다.

    final 예약어

    • 변수에 사용될 경우 : 상수
    • 메서드에 사용될 경우 : 재정의(오버라이딩) 불가능
    • 클래스에 사용될 경우 : 상속 불가능

📌 예시

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();
	}
}
  • 위 코드에서 final로 선언된 run 메서드를 보면 클래스 내부 메서드들을 순서에 맞게 실행시키는 것을 볼 수 있다.
  • 이처럼 특정 코드의 흐름을 정의해둔 것을 템플릿 메서드라고 한다.
  • 사용자는 run메서드를 사용해 Car을 상속받은 모든 클래스에서 절차에 맞게 run내부의 함수들을 실행시킬 수 있다.

📌 훅 메서드(Hook Method)

훅 메서드는 추상 클래스에 들어있으며, 아무 일도 하지 않거나 기본 행동을 정의하는 메소드로, 서브 클래스에서 오버라이드 할 수 있다. 예시를 봐보자!

public abstract class Car {

	public abstract void drive();
	public abstract void stop();

	public void startCar() {
		System.out.println("시동을 켭니다.");
	}

	public void turnOff() {
		System.out.println("시동을 끕니다.");
	}

    public void washCar(){}

	final public void run() {
		startCar();
		drive();
		stop();
		turnOff();
        washCar();
	}
}
  • washCar이라는 메서드가 추가되었다.
  • washCar은 정의부{} 가 있지만 안에 어떤 코드도 써있지않은 빈 함수이다.
  • washCar 내부를 정의하지않은 클래스에서 run을 실행시키면 washCar는 마치 없는 것 처럼 동작하지않는다.

public class ManualCar extends Car{

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

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

}

-- 실행부분
// ManualCar mc = new ManualCar();
// mc.run();

시동을 켭니다.
사람이 운전합니다.
브레이크를 밟아서 정지합니다.
시동을 끕니다.
  • 자, 여기 Car를 상속받은 ManualCar클래스가 있다.
  • ManualCar 객체를 만든 뒤 run메서드를 실행하면 위와 같이 실행된다.
  • washCar는 정의하지 않았으므로 무시된다.

public class AICar extends Car{

	@Override
	public void drive() {
		System.out.println("자율 주행합니다.");
		System.out.println("자동차가 스스로 방향을 바꿉니다.");
	}

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

    @Override
    public void washCar(){
        System.out.println("차를 자동으로 세차합니다.");
    }
}

-- 실행부분
// ManualCar mc = new ManualCar();
// mc.run();

시동을 켭니다.
자율 주행합니다.
자동차가 스스로 방향을 바꿉니다.
스스로 멈춥니다.
시동을 끕니다.
차를 자동으로 세차합니다.
  • ManualCar 객체를 만든 뒤 run메서드를 실행하면 위와 같이 실행된다.
  • washCar를 정의했으므로 실행된다.
@hongo
홍고 블로그