Java & Kotlin

[Java 객체지향] 추상 클래스와 템플릿 메서드 활용 예제 프로그램 (GameLevel 구현)

Sue 2022. 2. 2. 15:56
Player가 있고, Player는 GameLevel 속성을 가진다. 각 GameLevel 단계 마다 run(), jump(), turn() 세가지 기능이 업그레이드 된다.

Beginner : run()만 가능
Super : run(), jump() 가능
Advanced : run(), jump(), turn() 가능

Player는 한번에 하나의 레벨 상태만을 가질 수 있다.

Player가 play() 중에 레벨에 있는 go(int count)라는 메서드를 호출하면 run(), 횟수만큼 jump(), turn() 한다.

 

클래스 다이어그램
  • PlayerLevel는 abstract class로 선언한다.
  • go(int) 메서드는 템플릿 메서드로 구현하여 다른 클래스에서 순서를 변경할 수 없도록 한다.
  • 각 레벨의 클래스는 PlayerLevel 추상 클래스를 상속받는다.
  • PlayerLevel에서 선언한 추상 메서드를 각 레벨의 클래스에서 기능에 맞게 구현한다.
  • Player는 하나의 level만을 가지므로 디자인 패턴 중 state pattern이 적용된다.

 

출력 결과

 

source hierarchy

DAO 소스 계층을 떠올리면서 비슷하게 만들었다.

 

PlayerLevel.java
package gamelevel.level;

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) {
		
		showLevelMessage();
		run();
		for( int i = 0 ; i < count ; i ++ ) {
			jump();
		}
		turn();
	}

}

 

각 레벨 클래스에서 추상 메서드 구현

BeginnerLevel.java
package gamelevel.level.beginnerlevel;

import gamelevel.level.PlayerLevel;

public class BeginnerLevel extends PlayerLevel{

	@Override
	public void run() {
		System.out.println("천천히 달립니다.");
	}

	@Override
	public void jump() {
		System.out.println("점프 못하지롱");
	}

	@Override
	public void turn() {
		System.out.println("turn 못하지롱");
	}

	@Override
	public void showLevelMessage() {
			System.out.println("******초급자 레벨입니다******");
	}

}

 

SuperLevel.class
package gamelevel.level.superlevel;

import gamelevel.level.PlayerLevel;

public class SuperLevel extends PlayerLevel{
	

	@Override
	public void run() {
		System.out.println("빨리 달립니다.");
	}

	@Override
	public void jump() {
		System.out.println("높이 점프 합니다.");
	}

	@Override
	public void turn() {
		System.out.println("turn 못하지롱");
	}

	@Override
	public void showLevelMessage() {
			System.out.println("******중급자 레벨입니다******");
	}

}

 

AdvancedLevel.java
package gamelevel.level.advancedlevel;

import gamelevel.level.PlayerLevel;

public class AdvancedLevel extends PlayerLevel{
	
	
	@Override
	public void run() {
		System.out.println("엄청 빠르게 달립니다.");
	}

	@Override
	public void jump() {
		System.out.println("아주 높이 점프합니다.");
	}

	@Override
	public void turn() {
		System.out.println("turn 합니다.");
	}

	@Override
	public void showLevelMessage() {
		System.out.println("******고급자 레벨입니다******");
	}
	
	
}

 

Player.java
  • level은 Player당 하나씩 가지고 있어야 하므로 변수를 private으로 설정하고 내부에서만 조작이 가능하도록 한다.
  • private 변수에 대한 getter와 setter 대신 upgradeLevel 메서드로 level을 변경해줄 수 있다.

play 메서드에 매개변수가 없는 줄 알고 헤맸다리..

package gamelevel.player;

import gamelevel.level.PlayerLevel;

public class Player {
	
	private PlayerLevel level;	// level 변수 private으로 정의
	
	public PlayerLevel getLevel() {
		return level;
	}
	
	public void upgradeLevel(PlayerLevel level) {
		this.level = level;
	}
	
	public void play(int count) {
		level.go(count);
	}
	
}

 

PlayerTest.java
package gamelevel;

import gamelevel.level.PlayerLevel;
import gamelevel.level.advancedlevel.AdvancedLevel;
import gamelevel.level.beginnerlevel.BeginnerLevel;
import gamelevel.level.superlevel.SuperLevel;
import gamelevel.player.Player;

public class PlayerTest {

	public static void main(String[] args) {
		
		PlayerLevel beginnerLevel = new BeginnerLevel();
		PlayerLevel superLevel = new SuperLevel();
		PlayerLevel advancedLevel = new AdvancedLevel();
		
		Player p1 = new Player();
		Player p2 = new Player();
		Player p3 = new Player();
		
		p1.upgradeLevel(beginnerlevel);
		p1.play(1);
		
		p2.upgradeLevel(superlevel);
		p2.play(2);
		
		p3.upgradeLevel(advancedLevel);
		p3.play(3);
		
		
	}

}

 

※ 수정

  • Player 객체를 만들 때 초기화하는 default 생성자를 넣어주는게 좋다. (beginner level)
  • beginner level을 upgradeLevel로 설정할 필요 없음

 

Player.java

default 생성자 추가

public Player() {
    level = new BeginnerLevel();
}

 

PlayerTest.java
  • BeginnerLevel 객체 생성하는 부분과 upgradeLevel 부분을 제거해주었다.
package gamelevel;

import gamelevel.level.PlayerLevel;
import gamelevel.level.advancedlevel.AdvancedLevel;
import gamelevel.level.beginnerlevel.BeginnerLevel;
import gamelevel.level.superlevel.SuperLevel;
import gamelevel.player.Player;

public class PlayerTest {

	public static void main(String[] args) {
		
		PlayerLevel superLevel = new SuperLevel();
		PlayerLevel advancedLevel = new AdvancedLevel();
		
		Player p1 = new Player();
		Player p2 = new Player();
		Player p3 = new Player();
		
		p1.play(1);
		
		p2.upgradeLevel(superlevel);
		p2.play(2);
		
		p2.upgradeLevel(advancedLevel);
		p2.play(3);
		
		
	}

}