27강. 추상클래스와 템플릿 메서드 활용(2)

철새·2022년 3월 3일
0
  • Do it! 자바 프로그래밍 입문 온라인 강의를 수강하며 작성하였습니다.
  • Section 1. 자바의 핵심 - 객체지향 프로그래밍
  • 27강 "추상클래스와 템플릿 메서드 활용(2)"
  • 추상 클래스와 템플릿 메서드 > final 예약어 > 템플릿 메서드 구현 예

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

  • 템플릿 메서드 : 추상 메서드나 구현된 메서드를 활용하여 전체 기능의 흐름(시나리오)을 정의하는 메서드. (final로 선언하면 하위 클래스에서 재정의할 수 없음)
  • 프레임워크에서 많이 사용되는 설계 패턴
  • 추상 클래스로 선언된 상위 클래스에 템플릿 메서드를 활용하여 전체적인 흐름을 정의하고, 하위 클래스에서 다르게 구현되어야 하는 부분은 추상 메서드로 선언해서 하위 클래스가 구현하도록 함.

예시를 위해 Car 클래스를 추상 클래스로 만들고 하위 클래스로 ManualCar, AICar 클래스를 만들어주겠다.

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 final void run() {
		startCar();
		drive();
		stop();
		turnOff();
	}
}

시동을 키고 끄는 메서드는 모든 차량이 동일하고, 운전과 정지 메서드는 차량마다 다른 동작을 하기 위해 추상 메서드로 만들어주었다.
여기서 run() 메서드를 통해 시동을 키고, 운전 하고, 멈추고, 시동을 끄는 과정을 모든 차량이 그대로(수정 불가하게) 동작하게 만들기 위해 final 키워드를 이용하여 정의하였다.
이것을 템플릿 메서드라고 한다.

public class ManualCar extends Car{
	@Override
	public void drive() {
		System.out.println("사람이 운전합니다.");
		System.out.println("사람이 핸들을 조작합니다.");
	}
	@Override
	public void stop() {
		System.out.println("사람이 브레이크로 정지합니다.");
	}
}

ManualCar 클래스는 Car 클래스를 상속받고 drive()와 stop() 메서드는 사람이 운전, 정지한다고 출력한다.

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() 메서드는 자동차 스스로 한다고 출력한다.

public class CarTest {
	public static void main(String[] args) {
		Car myCar = new ManualCar();
		myCar.run();
		System.out.println("====================");
		Car yourCar = new AICar();
		yourCar.run();
	}
}

ManualCar와 AICar 인스턴스를 생성하고 run() 메서드를 실행하면 정상 출력되는 것을 확인할 수 있다.

final 예약어

  • final 변수는 값이 변경될 수 없는 상수임
  • final 변수는 오직 한 번만 값을 할당할 수 있음
  • final 메서드는 하위 클래스에서 재정의(overriding)할 수 없음
  • final 클래스는 더이상 상속되지 않음 (ex. java의 String 클래스)
public static final double PI = 3.14;

여러 자바 파일에서 공유하는 상수 값을 정의할 때 하나의 파일에 선언하여 사용하면 편리함

public class Define{
	public static final int MIN = 1;
    public static final int MAX = 99999;
    public static final int ENG = 1001;
    public static final int MATH = 2001;
}
public class UsingDefine{
	public static void main(String[] args){
    	System.out.println("수학 과목 코드 값은 " + Define.MATH + " 입니다.");
    }
}

템플릿 메서드 구현 예

  • 각 PlayerLevel 별 가능한 기능은 다름
  • 단, 기능의 순서는 run(), jump(), turn() 의 순서임
  • 기능의 순서와 반복에 대한 구현은 go(int) 메서드에서 구현되어 있음(템플릿 메서드)
public abstract class PlayerLevel {
	public abstract void run();
	public abstract void jump();
	public abstract void turn();
	public abstract void showLevelMessage();
	
	final public void go(int count) {
		run();
		for(int i=0; i<count; i++) {
			jump();
		}
		turn();
	}
}

PlayerLevel 클래스는 추상 클래스로, 각각의 레벨에서 run(), jump(), turn() 메서드를 다르게 활용하기 위해 추상 메서드로 만들어주었다.
go(int) 메서드는 모든 클래스에서 동일하게 작동하기 위해 final로 선언하였다.

public class BeginnerLevel extends PlayerLevel {
	@Override
	public void run() {
		System.out.println("천천히 달립니다.");
	}
	@Override
	public void jump() {
		System.out.println("jump 할 줄 모르지롱~");
	}
	@Override
	public void turn() {
		System.out.println("turn 할 줄 모르지롱~");
	}
	@Override
	public void showLevelMessage() {
		System.out.println("***** 초보자 레벨입니다. *****");
	}
}
public class AdvancedLevel extends PlayerLevel {
	@Override
	public void run() {
		System.out.println("빨리 달립니다.");
	}
	@Override
	public void jump() {
		System.out.println("높이 jump 합니다.");
	}
	@Override
	public void turn() {
		System.out.println("turn 할 줄 모르지롱~");
	}
	@Override
	public void showLevelMessage() {
		System.out.println("***** 중급자 레벨입니다. *****");
	}
}
public class SuperLevel extends PlayerLevel {
	@Override
	public void run() {
		System.out.println("엄청 빨리 달립니다.");
	}
	@Override
	public void jump() {
		System.out.println("엄청 높이 jump 합니다.");
	}
	@Override
	public void turn() {
		System.out.println("한 바퀴 돕니다.");
	}
	@Override
	public void showLevelMessage() {
		System.out.println("***** 고급 레벨입니다. *****");
	}
}

BeginnerLevel, AdvancedLevel, SuperLevel 클래스는 PlayerLevel 클래스를 상속받아 추상 메서드를 각각 작성하였다.

public class Player {
	private PlayerLevel level;
	public Player() {
		level = new BeginnerLevel();
		level.showLevelMessage();
	}
	public PlayerLevel getLevel() {
		return level;
	}
	public void upgradeLevel(PlayerLevel level) {
		this.level = level;
		level.showLevelMessage();
	}
	public void play(int count) {
		level.go(count);
	}
}

Player 클래스는 PlayerLevel 자료형의 level 변수를 선언하였고, upgradeLevel() 메서드를 통해 레벨을 변화시킬 수 있다.

public class MainBoard {
	public static void main(String[] args) {
		Player player = new Player();
		player.play(1);
		
		AdvancedLevel aLevel = new AdvancedLevel();
		player.upgradeLevel(aLevel);
		player.play(2);

		SuperLevel sLevel = new SuperLevel();
		player.upgradeLevel(sLevel);
		player.play(3);
	}
}

main 함수에서 player의 레벨을 변화시키고 play() 메서드를 실행하면 정상 출력된다.

profile
효율성을 추구하며 세상을 떠도는 철새입니다.

0개의 댓글

관련 채용 정보