해당 코드를 리팩토링 하려는 이유는 숫자값 '100'이라는 값이 어떤 의미인지 파악하기 힘들고,
숫자값이 변경될 경우 어떠한 숫자값들이 여기서 의미하는 '100'과 같은 숫자인지 확인하고 수정하기 힘들기 때문이다.
그럼 지금부터 리팩토링의 대상이 될 예시 코드를 살펴보도록 하자.
먼저 매직넘버가 작성되어 있는 Robot 클래스부터 살펴보자.
리팩토링 적용 전
public class Robot {
private final String _name;
public Robot(String name){
_name = name;
}
public void order(int command){
if(command == 0){
System.out.println(_name + " walks.");
}else if(command == 1){
System.out.println(_name + " stops.");
}else if(command == 2){
System.out.println(_name + " jumps.");
}else{
System.out.println("Command error. command = "+command);
}
}
}
다음은 Robot 클래스의 인스턴스를 생성하여 메소드를 호출하는 Main 클래스이다.
public class Main {
public static void main(String[] args){
Robot robot = new Robot("kjk3071");
robot.order(0); //walk
robot.order(1); //stop
robot.order(2); //jump
}
}
order에 보내는 파라미터가 어떤 기능을 수행하는지 전혀 알 수 없기 때문에 주석을 이용해 표현하고 있다.
하지만 이는 근본적인 문제해결로 볼 수 없으므로 리팩토링을 적용해 보도록 하겠다.
리팩토링 적용 후
public class Robot {
private final String _name;
public static final int COMMAND_WALK = 0;
public static final int COMMAND_STOP = 1;
public static final int COMMAND_JUMP = 2;
public Robot(String name){
_name = name;
}
public void order(int command){
if(command == COMMAND_WALK){
System.out.println(_name + " walks.");
}else if(command == COMMAND_STOP){
System.out.println(_name + " stops.");
}else if(command == COMMAND_JUMP){
System.out.println(_name + " jumps.");
}else{
System.out.println("Command error. command = "+command);
}
}
}
Robot 클래스의 매직넘버를 심볼릭 정수로 변환한 모습을 확인할 수 있다.
Main 클래스에서도 Robot 클래스의 심볼릭 정수를 직접적으로 사용하였다.
접근제어자가 public 이고 static을 사용하였으므로 객체 생성여부 상관없이 해당 변수를 사용할 수 있다.
public class Main {
public static void main(String[] args){
Robot robot = new Robot("kjk3071");
robot.order(Robot.COMMAND_WALK);
robot.order(Robot.COMMAND_STOP);
robot.order(Robot.COMMAND_JUMP);
}
}
다른 방법을 사용한 심볼릭 정수 표현
enum을 사용한 예시를 살펴보도록 하자.
public class Robot {
private final String _name;
public enum Command{
WALK,
STOP,
JUMP
}
public Robot(String name){
_name = name;
}
public void order(Robot.Command command){
if(command == Command.WALK){
System.out.println(_name + " walks.");
}else if(command == Command.STOP){
System.out.println(_name + " stops.");
}else if(command == Command.JUMP){
System.out.println(_name + " jumps.");
}else{
System.out.println("Command error. command = "+command);
}
}
}
public class Main {
public static void main(String[] args){
Robot robot = new Robot("kjk3071");
robot.order(Robot.Command.WALK);
robot.order(Robot.Command.STOP);
robot.order(Robot.Command.JUMP);
}
}
다음은 타입코드를 클래스로 치환하여 사용한 예시이다.
public class RobotCommand {
private final String _name;
public RobotCommand(String name){
_name = name;
}
public String toString(){
return "[ RobotCommand: " + _name + " ] "
}
}
public class Robot {
private final String _name;
public static final RobotCommand COMMAND_WALK = new RobotCommand("walk");
public static final RobotCommand COMMAND_STOP = new RobotCommand("stop");
public static final RobotCommand COMMAND_JUMP = new RobotCommand("jump");
public Robot(String name){
_name = name;
}
public void order(RobotCommand command){
if(command == COMMAND_WALK){
System.out.println(_name + " walks.");
}else if(command == COMMAND_STOP){
System.out.println(_name + " stops.");
}else if(command == COMMAND_JUMP){
System.out.println(_name + " jumps.");
}else{
System.out.println("Command error. command = "+command);
}
}
}
public class Main {
public static void main(String[] args){
Robot robot = new Robot("kjk3071");
robot.order(Robot.COMMAND_WALK);
robot.order(Robot.COMMAND_STOP);
robot.order(Robot.COMMAND_JUMP);
}
}
다른 방법을 사용한 예시들은 다양한 방법을 통해 심볼릭 정수를 사용할 수 있다는 것을 보여준다.
하지만 심볼릭 정수를 적용하지 말아야 할 부분이 존재한다.
가변성을 띄는 변수나 명확히 정의된 변수가 바로 그러한 대상이다.
이외에도 바이트코드에 쓰여있는 정수를 조심해야 한다. 컴파일 시점에 따라 전혀 다른 값이 될 수 있기 때문이다.
지금까지 매직넘버를 심볼릭 정수로 변환하는 리팩토링에 대해서 살펴보았다.
리팩토링을 통해 개선하는것도 중요하지만, 이번 장의 내용은 최초 코딩시에 고려하여 작성하는 것이 가장 좋을 듯 싶다.
'JAVA > REFACTORING' 카테고리의 다른 글
[JAVA] 리팩토링의 정의 (0) | 2012.02.15 |
---|