티스토리 뷰

Before1

public void attack(Player target){
    	if ((int) (Math.random() * 1000) % 100 <(this.accuracy-target.dodge)) {
    		Mywin.ta.append("공격이 성공했습니다!\n");
    		System.out.println("공격이 성공했습니다!");
    		int r=(int) (Math.random() * 1000) % 6;
    		if(r==0) {
    			target.hp-=(this.power-target.protection);
    			System.out.printf("%s의 공격이 %s에게 %d 만큼의 데미지를 입혔습니다!",this.name,target.name,this.power-target.protection);
    			System.out.println();
    			String str= this.name +"의 공격이" + target.name+ "에게"+(this.power-target.protection)+"만큼의 데미지를 입혔습니다!\n";
    			Mywin.ta.append(str);
    		}
    		else if(r==1) {
    			target.hp-=(this.power-target.protection+1);
    			System.out.printf("%s의 공격이 %s에게 %d 만큼의 데미지를 입혔습니다!",this.name,target.name,this.power-target.protection+1);
    			System.out.println();
    			String str = this.name +"의 공격이" + target.name+ "에게"+(this.power-target.protection+1)+"만큼의 데미지를 입혔습니다!\n";
    			Mywin.ta.append(str);
    		}
    		else if(r==2) {
    			target.hp-=(this.power-target.protection+2);
    			System.out.printf("%s의 공격이 %s에게 %d 만큼의 데미지를 입혔습니다!",this.name,target.name,this.power-target.protection+2);
    			System.out.println();
    			String str = this.name +"의 공격이" + target.name+ "에게"+(this.power-target.protection+2)+"만큼의 데미지를 입혔습니다!\n";
    			Mywin.ta.append(str);
    		}
    		else if(r==3) {
    			target.hp-=(this.power-target.protection+3);
    			System.out.printf("%s의 공격이 %s에게 %d 만큼의 데미지를 입혔습니다!",this.name,target.name,this.power-target.protection+3);
    			System.out.println();
    			String str = this.name +"의 공격이" + target.name+ "에게"+(this.power-target.protection+3)+"만큼의 데미지를 입혔습니다!\n";
    			Mywin.ta.append(str);
    		}
    		else if(r==4) {
    			target.hp-=(this.power-target.protection+4);
    			System.out.printf("%s의 공격이 %s에게 %d 만큼의 데미지를 입혔습니다!",this.name,target.name,this.power-target.protection+4);
    			System.out.println();
    			String str = this.name +"의 공격이" + target.name+ "에게"+(this.power-target.protection+4)+"만큼의 데미지를 입혔습니다!\n";
    			Mywin.ta.append(str);
    		}
    		else if(r==5) {
    			target.hp-=(this.power-target.protection+5);
    			System.out.printf("%s의 공격이 %s에게 %d 만큼의 데미지를 입혔습니다!",this.name,target.name,this.power-target.protection+5);
    			System.out.println();
    			String str = this.name +"의 공격이" + target.name+ "에게"+(this.power-target.protection+5)+"만큼의 데미지를 입혔습니다!\n";
    			Mywin.ta.append(str);
    		}
    		if(target instanceof Heroes) {
	    		r=(int) (Math.random() * 1000) % 11;
	    		target.stress+=r;
	    		System.out.printf("공격으로 인해 %s의 스트레스가 %d만큼 증가합니다!",target.name,r);
	    		System.out.println();
	    		String str = "공격으로 인해"+target.name+ "의 스트레스가"+ r+"만큼 증가합니다!\n";
    			Mywin.ta.append(str);
    		}
    	}
    	else {
    		System.out.println("공격이 빗나갔습니다!");
    		String str = "공격이 빗나갔습니다!\n";
			Mywin.ta.append(str);
    	}
    }

 

문제점 1. 현재 attack메소드는 r값에 따라 target.hp -= this.power - target.protection+r 값을 수행한 후, 콘솔과 빌더에 메시지를 출력하는 간단한 내용으로 이루어져있다. 그러나 그걸 r값에 따라 분기하여 동일한 내용을 반복해서 써놨으므로 개선이 필요하다.

attack(Player target){
//1. 데미지와 target.hp -= 데미지 연산
//2. 콘솔+gui에 메시지 출력
//*랜덤값인 r값에 따라
}

 

해결책 1. attack(Player target) 메소드 내부에서 randomAttack(target, 랜덤값 r)을 호출한다. 그럼 랜덤값을 받아 데미지를 계산하고 데미지메시지를 작성하는 데미지메시지(target, 데미지) 함수를 호출한다. 이 값을 동시출력 메소드에 넣으면 두 가지 출력문이 나오게 된다.

After1

public void attack(Player target){
    	int random = (int)(Math.random()*100);
    	if (random <명중확률(target)) {
    		동시출력("공격이 성공했습니다!\n");
    		
    		int r=(int)(Math.random()*6);
    		randomAttack(target, r);
    		
    		if(target instanceof Heroes) {
	    		r=(int) (Math.random() * 1000) % 11;
	    		target.stress+=r;
    			동시출력("공격으로 인해"+target.name+ "의 스트레스가 "+ r+"만큼 증가합니다!\n");
    		}
    	}
    	else {
    		동시출력("공격이 빗나갔습니다!\n");
    	}
    }

public void randomAttack(Player target, int r) {
	//데미지 계산
    	int 데미지 = this.power - target.protection +r;
       	target.hp-=데미지;
        //데미지메시지 메소드에 target, 데미지값을 전달하고
        //이를 동시출력 메소드에 넘겨 출력한다.
    	동시출력(데미지메시지(target, 데미지)+"\n");
    }

public String 데미지메시지(Player target, int 데미지) {
    	String str = this.name+"의 공격이 "+target.name+"에게 "+데미지+"만큼의 데미지를 입혔습니다!";
    	return str;
    }
    
public static void 동시출력(String s) {
    	//if(Mywin.ta!=null) 
    	Mywin.ta.append(s);
    	System.out.print(s);
    }

 

문제점2. instanceof heroes 라는 부분이 있는데 instanceof는 모듈화를 해치고 나중에 찾아서 수정하기 불편하게 만들기 때문에 없애야 한다.

Before2

if(target instanceof Heroes) {
	    		r=(int) (Math.random() * 1000) % 11;
	    		target.stress+=r;
	    		System.out.printf("공격으로 인해 %s의 스트레스가 %d만큼 증가합니다!",target.name,r);
	    		System.out.println();
	    		String str = "공격으로 인해"+target.name+ "의 스트레스가"+ r+"만큼 증가합니다!\n";
    			Mywin.ta.append(str);
    		}

 

해결책2. Player 클래스와 Heroes 클래스에 handleStress(int s) 메소드를 만들어서 target.handleStress(s)를 호출하면 target이 Heroes 일 땐 자동으로 Heroes 클래스의 메소드를 소환하도록 메소드 오버라이딩을 해보자.

After2

public void attack(Player target){
    	int random = (int)(Math.random()*1000)%100;
    	if (random <명중확률(target)) {
    		동시출력("공격이 성공했습니다!\n");
    		
    		int r=(int)(Math.random()*1000)%6;
    		randomAttack(target, r);
         
    		int s=(int)(Math.random()*1000)%11;
            //고친 부분. instanceof Heroes를 개선하였다.
    		target.handleStress(s);
    	}
    	else {
    		동시출력("공격이 빗나갔습니다!\n");
    	}
    }
//Player클래스의 비워둔 메소드
public void handleStress(int s) {
    	//비워놓으면 target이 Heroes일 때만 Heroes 클래스의 handleStess(int s) 메소드가 실행되어 특정한 일을 할 수 있다.
    }
//Heroes 클래스
public void handleStress(int s) {
    	this.stress+=s;
    	Player.동시출력("공격으로 인해 "+this.name+"의 스트레스가 "+s+"만큼 증가합니다!\n");
    }

 

문제점3. 프로젝트 전체에 랜덤수가 엄청나게 많이 사용된다...!! 그때마다 긴 문장을 쓰기 힘들다.

Before3

public void attack(Player target){
	//1번
    	int random = (int)(Math.random()*1000)%100;
    	if (random <명중확률(target)) {
    		동시출력("공격이 성공했습니다!\n");
    		//2번
    		int r=(int)(Math.random()*1000)%6;
    		randomAttack(target, r);
            	//3번. attack 메소드 안에서만 3번이 쓰였다.
    		int s=(int)(Math.random()*1000)%11;
    		target.handleStress(s);
    	}
    	else {
    		동시출력("공격이 빗나갔습니다!\n");
    	}
    }

 

해결책3. static 메소드를 만들어서 해결하자

After3

//Player클래스의 static 메소드
public static int 랜덤수(int r){
     	return (int)(Math.random()*1000)%r;
     }
public void attack(Player target){
    	if (랜덤수(100) <명중확률(target)) {
    		동시출력("공격이 성공했습니다!\n");
    		randomAttack(target, 랜덤수(6));
    		target.handleStress(랜덤수(11));
    	}
    	else {
    		동시출력("공격이 빗나갔습니다!\n");
    	}
    }

 

문제점4. playerStress 메소드 안에서 if-else문이 쓰였다. 특정 부분을 찾아서 수정하는 게 불편하다.

public void playerStress(Player pl,JLabel Label,String image1, String image2) {
    	if(pl.stress>=25&&stressCount==0) {
    		동시출력("영웅이 고통의 굴림에 빠졌습니다...\n");
  
    		if(랜덤수(4)==0) {
    			Label.setIcon(new ImageIcon(Mywin.class.getResource(image2)));
    			동시출력("영웅의 기상에 돌입합니다!\n");
    			pl.power+=2;
    			동시출력("power가 2만큼 증가합니다!\n");
    			pl.stress=0;
    		}
    		else {
    			Label.setIcon(new ImageIcon(Mywin.class.getResource(image1)));
    			stressCount++;
    			동시출력("영웅이 붕괴합니다..\n");
    			pl.dodge-=10;
    			동시출력("dodge가 10만큼 감소합니다..\n");
    		}
    	}
    	if(pl.stress>=50&&stressCount==1) {
    		동시출력("스트레스가 50이 되어 영웅이 심장마비로 죽습니다.\n");
    		pl.hp=0;
    	}
    }

 

해결책4. 아직 찾지 못했다... pl.stress>=25면 boolean값 0, pl.stress>=50이면 boolean값 1로 정의하는 메소드 있고 stressCount도 0이면 false, 1이면 true, 랜덤수(4)도 0이면 false, 0 아니면 true 해서 public void playerStress(b_stress, stressCount, 랜덤수(4)) 다 불리안 값으로 받는 메소드를 만들어도 ifelse문이랑 모듈화 측면에서 별 차이가 없을 것 같다... 아직 공부가 부족한 듯 싶다.

 

그리하여 최종 수정본 Player 클래스 코드는 다음과 같다.

최종After

public int 명중확률(Player target) {
    	return this.accuracy - target.dodge;
    }
    
    public void randomAttack(Player target, int r) {
    	int 데미지 = this.power - target.protection +r;
       	target.hp-=데미지;
    	동시출력(데미지메시지(target, 데미지)+"\n");
    }
    
     public static int 랜덤수(int r){
     	return (int)(Math.random()*1000)%r;
     }
     
    public static void 동시출력(String s) {
    	//if(Mywin.ta!=null) 
    	Mywin.ta.append(s);
    	System.out.print(s);
    }
    
    public String 데미지메시지(Player target, int 데미지) {
    	String str = this.name+"의 공격이 "+target.name+"에게 "+데미지+"만큼의 데미지를 입혔습니다!";
    	return str;
    }
    
    public void attack(Player target){
    	if (랜덤수(100) <명중확률(target)) {
    		동시출력("공격이 성공했습니다!\n");
    		randomAttack(target, 랜덤수(6));
    		target.handleStress(랜덤수(11));
    	}
    	else {
    		동시출력("공격이 빗나갔습니다!\n");
    	}
    }
    
    public void handleStress(int s) {
    	//비워놓으면 target이 Heroes일 때만 Heroes 클래스의 handleStess(int s) 메소드가 실행되어 특정한 일을 할 수 있다.
    }
    
    public void playerStress(Player pl,JLabel Label,String image1, String image2) {
    	if(pl.stress>=25&&stressCount==0) {
    		동시출력("영웅이 고통의 굴림에 빠졌습니다...\n");
    		
    		if(랜덤수(4)==0) {
    			Label.setIcon(new ImageIcon(Mywin.class.getResource(image2)));
    			동시출력("영웅의 기상에 돌입합니다!\n");
    			pl.power+=2;
    			동시출력("power가 2만큼 증가합니다!\n");
    			pl.stress=0;
    		}
    		else {
    			Label.setIcon(new ImageIcon(Mywin.class.getResource(image1)));
    			stressCount++;
    			동시출력("영웅이 붕괴합니다..\n");
    			pl.dodge-=10;
    			동시출력("dodge가 10만큼 감소합니다..\n");
    		}
    	}
    	if(pl.stress>=50&&stressCount==1) {
    		동시출력("스트레스가 50이 되어 영웅이 심장마비로 죽습니다.\n");
    		pl.hp=0;
    	}
    }
    
    
}

1. attack(Player target) 메소드에서 randomAttack(target, 랜덤수) 호출, randomAttack(target, 랜덤수) 메소드에서 동시출력(데미지메시지(target, 데미지)+"\n"); 호출

2. target instanceof Heroes 대신 Player 클래스(메소드 바디 비워놓음)와 Heroes 클래스(오버라이딩하여 영웅만 스트레스 받는다는 내용 추가)에 target.handleStress(s) 메소드를  target이 Heroes일 때는 자동으로 오버라이딩된 메소드를 호출하도록 바꾸었다.

3. 이외에도 랜덤수 생성 메소드, 동시출력 메소드, 명중확률 계산 메소드 등을 이용해 반복성을 줄이고 해당 메소드만 찾아가면 기능을 쉽게 볼 수 있도록 하였다.

 

아쉬운 점

다만, 끝내 하지 못했던 것은 playerStress 메소드에서의 if-else문을 바꾸는 일이었다. pl.stress 값과 stressCount 값에 대한 불리안 값을 만들어 그걸 인자로 받는 각각의 메소드를 만들어보려 했으나 그거나 if-else문이나 다른 점이 없는 것 같아 해보지 않았다. 더 나은 방안은 무엇일까? 아직까진 찾아내지 못하였다. 사실 이것까지 해보는 것이 배틀3 리팩토링의 의도인 것 같아 거기까지 미치지 못한 게 부끄럽지만....

 

알아낸 점

그럼에도, 일단 과거 배틀 과제를 할 때는 Mywin.ta.append(String s)하는 좋은 방법을 쓰지 않고 TextAreaOutputStream 방법을 사용했었다. 이번 과제를 통해 정석적인 방법을 알았다. 또한 반복성을 줄이고 맡은 역할을 메소드에 따라 분리해보면서 메소드 작성에 대한 이해가 높아졌다. 거기에다가, 상위클래스와 하위클래스의 관계를 이용하여 특정 하위클래스에게 특별한 동작을 맡기고 싶을 때 메소드 오버라이딩을 이용해보면서 instanceof 대신 target.메소드 방법이 얼마나 간편한지를 몸소 느끼게 되었다. 

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2026/03   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함