ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Java - 추상 클래스(템플릿 메서드 응용하기)4
    개발언어/JAVA 2023. 11. 4. 07:05

    템플릿 메서드 응용하기

    클래스의 기능과 관계

    if(level == beginner)
       //beginner 기능구현
    else if(level == advanced)
       //advanced 기능구현
    else if(level == super)
       //super 기능구현

     

    간단하게 생각하면 Player 클래스를 만들고 현재 player의 레벨에 따라 if 조건문으로 코드를 구현하면 된다. 의사 코드(pseudo code)로 작성하면 위 코드와 같다. 그런데 위와 같이 구현하면 level 수만큼 if문이 증가해서 유지보수가 어려운 코드가 된다. 현재는 level이 3개 밖에 없지만, 기능이 추가되어 level이 7개 정도로 늘어난다면 각 level마다 if-else if문을 7개씩 코딩해야 하기 때문이다.

     

    클래스 설계하기

    우선 클래스를 좀 더 체계적으로 설계하기 위해 각 플레이어가 가질 수 있는 레벨을 클래스로 분리한다. 각 레벨마다 고통 기능과 개별 기능이 있으므로 레벨 클래스를 상속 관계로 표현할 수 있다. 

     

    위 클래스 다이어그램에 포함된 클래스는 모두 하나의 gameLevel 패키지에 만들어야 프로그래밍 제대로 실행된다. Player 클래스와 PlayerLevel 클래스는 포함(HAS-A)관계이다. 게임에서 모든 Player는 자신의 레벨이 있기 때문에, Player 클래스에서 PlayerLevel을 멤버 변수로 갖는 것이다. 레벨이 올라갈 수록 수행하 수 있는 기능이 달라진다. 그러므로 PlayerLevel클래스를 추상 클래스로 만들어 모든 레벨에서 공통으로 수행하는 기능을 구현하고, 각 레벨마다 달라지는 기능은 추상 메서드로 만들어 둔다. 그리고 PlayerLevel을 상속 받는 각 레벨에 해당하는 구현 클래스에서 추상메서드로 선언한 부분을 나름 필요에 맞게 구체적으로 구현한다.

     

    Player 클래스 구현

    package gameLevel;
    
    public class Player{
    	//Player가 가지는 level 변수 선언
    	private PlayerLevel level;
        
        //디폴트 생성자. 처음 생성되면 BeginnerLevel로 
        //시작하며 레벨 메시지 출력
        public Player(){
        	level = new BeginnerLevel();
            level.showLevelMessage();
        }
        
        public PlayerLevel getLevel(){
        	return level;
        }
        
        //매개변수 자료형은 모든 레벨로 변환 가능한 
        //PlayerLevel
       
        //레벨 변경 메서드 현재 자신의 level을
        //매개변수로 받은 level로 변경하고
        //레벨 메시지 출력
        public void upgradeLevel(PlayerLevel level){
        	this.level = level;
            level.showLevelMessage();
        }
        
        public void play(int count){
        	//레벨마다 할수 있는 play가 다르므로
            //PlayerLevel의 템플릿 메서드 go()호출
            level.go(count);
        }
        
    }

     

    Player는 한 번에 하나의 레벨 상태만 가질 수 있으므로 Player를 처음 만들때 가질수 있는 레벨에 해당하는 인스턴스를 대입한다. 그리고 추후에 레벨을 변경할 수 있는 upgradeLevel()메서드도 만든다.

     

    upgradeLevel()메서드를 보자. 실제로 게임에서는 특정 조건을 만족해야 레벨이 올라가겠지만 이 예제에서는 매개변수로 넘어온 레벨로 바로 업그레이드된다.

     

    play()메서드에서는 player가 level에 따라 할 수 있는 행동이 결정 되므로 PlayerLevel 클래스가 제공하는 go()메서드를 호출한다.

     

    PlayerLevel클래스

    package gameLevel;
    
    public abstract class PalyerLevel{
    	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();
        }
    }

     

    초보자 레벨 클래스

    package gameLevel;
    
    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("*****초보자 레벨입니다.*****");
        }
    }

     

     

    중급자 레벨 클래스

    package gameLevel;
    
    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("*****중급자 레벨입니다.*****");
        }
    }

     

    고급자 레벨 클래스

    package gameLevel;
    
    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("한 바퀴 돕니다.");
        }
        
        @Override
        public void showLevelMessage(){
        	System.out.println("*****고급자 레벨입니다.*****");
        }
    }

     

    테스트 프로그램 작성해서 실행하기

    package gameLevel;
    
    public class MainBoard{
    	public static void main(String[] args){
        	//처음 생성하면 BeginnerLevel
            Player player = new Player();
            //*****초보자 레벨입니다.*****
            player.play(1);
            //천천히 달린다.
            //아직 Jump할 수 없습니다.
            //아직 Turn할 수 없습니다.
            
            AdvancedLevel aLevel = new AdvancedLevel();
            player.upgradeLevel(aLevel);
            //*****중급자 레벨입니다.*****
            player.play(2)
            //빨리 달린다.
            //높이 점프한다.
            //높이 점프한다.
            //아직 Turn할 수 없습니다.
            
            SuperLevel sLevel = new SuperLevel();
            player.upgradeLevel(sLevel);
            //*****고급자 레벨입니다.*****
            player.play(3);
            //빨리 달린다.
            //높이 점프한다.
            //높이 점프한다.
            //높이 점프한다.
            //한 바퀴 돕니다.
        }
    }

     

    추상 클래스와 다형성

    앞서 만든 Player 클래스와 PlayerLevel 클래스를 살펴보자. 모든 레벨 클래스는 PlayerLevel 클래스를 상속 받았다. 그리고 Player가 가질 수 있는 여러 레벨을 별도의 자료형으로 선언하지 않고 PlayerLevel로 선언했다. 레벨을 변경하는 upgradeLevel()메서드의 매개변수 자료형도 PlayerLevel이다. 따라서 레벨 클래스가 여러 개 존재하더라도 모든 클래스는 PlayerLevel 클래스로 대입될 수 있다. level.go()메서드가 호출되면 가상 메서드에 의해 각 레벨 클래스에 구현된 레벨별 기능이 호출된다. 정리하자면, 상위 클래스인 추상클래스는 하위에 구현된 여러 클래스를 하나의 자료형(상위 클래스 자료형)으로 선언하거나 대입할 수 있다. 추상 클래스에 선언된 메서드를 호출하면 가상 메서드에 의해 각 클래스에 구현된 기능이 호출된다. 즉 하나의 코드가 다양한 자료형을 대상으로 동작하는 다형성을 활용할 수 있는 것이다.

     

    [출저 - Do it! 자바 프로그래밍 입문 , 박은종]

    http://www.easyspub.co.kr/20_Menu/BookView/A001/267/PUB

     

    http://www.easyspub.co.kr/20_Menu/BookView/A001/267/PUB

     

    www.easyspub.co.kr

     

    댓글

Designed by Tistory.