지난 글: [프로그래밍 언어/JAVA] - JAVA 입문 - 템플릿 메서드
지난 글에서 템플릿 메서드를 공부했으니 한 가지 예제를 만들어보자. 게임을 할 때를 가정해보자. 게임 캐릭터에는 레벨이 있다. 레벨은 경험치가 쌓이거나 어떤 이벤트를 통해 올라간다. 플레이어 레벨이 다르면 해당 레벨마다 할 수 있는 역할도 다르다. 이를 템플릿 메서드를 사용해 구현해보자.
시나리오:
Player가 있고, 이 Player가 게임을 한다. 게임에서 Player가 가지는 레벨에 따라 할 수 있는 세 가지 기능이 있다.
- 초보자 레벨 : 천천히 달릴(run) 수 있다.
- 중급자 레벨 : 빠르게 달리고(run) 점프할(jump) 수 있다.
- 상급자 레벨 : 굉장히 빨리 달리고(run) 점프하며(jump), 턴(turn)할 수 있다.
모든 레벨에서 Player가 할 수 있는 필살기 go(int count) 메서드를 제공한다. go( ) 메서드는 한 번 run하고, 매개변수로 전달된 count만큼 jump하고, 한 번 turn한다. 그 레벨에서 불가능한 기능을 요청하면 할 수 없다는 메시지를 출력한다.
============================================================================
클래스 기능과 관계
시나리오를 코드로 구현하기 전에 생각을 해보자. 무조건 클래스를 만들어 코딩하는 것보다 주어진 문제를 어떻게 해결할 것인지 생각해 보고 클래스 다이어 그램을 간략하게 그려보는 것이 객체 지향 방식으로 문제를 해결하는 좋은 습관이다. 큰 프로젝트를 진행할 때는 이 과정을 분석·설계 과정이라고 한다. 시나리오에서 제시한 내용에 기반해 클래스를 간단하게 생각해보면 Player 클래스를 만들고 현재 Player 레벨에 따라 if 조건문으로 코드를 구현하면 된다. 의사 코드(pse udo code)로 작성하면 level 수만큼 if문이 증가해서 복잡해질 것이다. 예제에는 level이 3개뿐이지만, level이 늘어난다면 각 level마다 if-else문을 코딩해야하기 때문이다.
클래스 설계하기
이제부터는 클래스를 좀 더 체계적으로 설계하면서 진행해보자. 각 플레이어가 가질 수 있는 레벨을 클래스로 분리한다. 각 레벨마다 공통 기능과 개별 기능이 있으므로 레벨 클래스를 상속 관계로 표현해보자. 아래 클래스 다이어그램에 포함된 클래스는 모두 하나의 gameLevel 패키지에 만들어야 프로그램이 제대로 실행된다.
Player 클래스와 PlayerLevel 클래스는 포함(HSA-A) 관계이다. 게임에서 모든 Player는 자신의 레벨을 갖기에, Player 클래스에서 PlayerLevel을 멤버 변수로 갖는다. 레벨이 올라갈수록 수행할 수 있는 기능이 달라지므로 PlayerLevel 클래스를 추상 클래스로 만들어 모든 레벨에서 공통으로 수행하는 기능을 구현하고, 각 레벨마다 달라지는 기능은 추상 메서드로 만들어 둔다. 그리고 PlayerLevel을 상속받은 하위 클래스에서 추상 메서드로 선언한 부분을 나름의 필요에 맞게 구체적으로 구현하면 된다.
Player 클래스 구현하기
Player 클래스는 한 번에 하나의 레벨 상태이므로 level 변수에 레벨에 해당하는 인스턴스를 대입한다. 레벨을 변경할 수 있는 upgradeLevel( )도 만든다. 6행 Player 디폴트 생성자에서 초기 레벨을 Beginner로 지정하고 현재 레벨이 무엇인지 출력한다. 15행 upgradeLevel( )메서드는 모든 레벨이 매개변수로 대입될 수 있기에, 모든 레벨의 상위 클래스인 Player Level을 매개변수의 자료형으로 정했다. 20행의 Play( ) 메서드에서는 PlayerLevel 클래스가 제공하는 go( )메서드를 호출한다.
PlayerLevel 클래스 구현
각 레벨에서 수행할 공통 기능은 PlayerLevel 추상 클래스에서 선언한다. 각 레벨마다 다르게 구현되어야 하는 메서드는 추상 메서드로 선언한다. go( ) 메서드는 시나리오대로 수행되어야 하므로 코드 내용을 완전히 구현했다. 이 코드는 모든 레벨에서 동일하고 불변해야하기에 final 예약어를 사용해 템플릿 메서드로 구현했다. 각 레벨에서는 해당 레벨별로 제공하는 메서드들의 기능을 구현한다.
BeginnerLevel 클래스 구현
AdvancedLevel 클래스 구현
SuperLevel 클래스 구현
테스트 프로그램 작성해서 실행
다이어그램에서 제시한 클래스를 모두 구현했으니 테스트 프로그램을 만들어 실행해보자.
Player 클래스의 디폴트 생성자는 초보자 레벨로 시작하도록 구현되어 있다.
추상 클래스와 다형성
위에서 만든 Player 클래스와 PlayerLevel 클래스에서 다형성이 구현된 코드를 사용하였다. 모든 레벨 클래스는 PlayerLev el 클래스를 상속받았다. 그리고 Player가 가질 수 있는 여러 레벨을 별도의 자료형으로 선언하지 않고 PlayerLevel로 선언했다. 레벨을 변경하는 upgradeLevel( ) 메서드의 매개변수 자료형도 PlayerLevel이다. 따라서 레벨 클래스가 여러 개 존대하더라도 모든 클래스는 PlayerLevel 클래스로 대입될 수 있다. 정리하면 상위 클래스인 추상 클래스는 하위에 구현된 여러 클래스를 하나의 자료형(상위 클래스 자료형)으로 선언하거나 대입할 수 있다. 추상 클래스에 선언된 메서드를 호출하면 가상 메서드에 의해 각 클래스에 구현된 기능이 호출된다. 즉 하나의 코드가 다양한 자료형을 대상으로 동작하는 다형성을 활용할 수 있다.
참고 서적: 자바 프로그래밍 입문 - 박은종
'프로그래밍 언어 > JAVA' 카테고리의 다른 글
JAVA 입문 - 인터페이스 (0) | 2022.05.26 |
---|---|
JAVA 입문 - final 예약어 (0) | 2022.05.25 |
JAVA 입문 - 템플릿 메서드 (0) | 2022.05.24 |
JAVA 입문 - 추상 클래스 (0) | 2022.05.23 |
JAVA 입문 - 다운 캐스팅과 instanceof (0) | 2022.05.22 |