상세 컨텐츠

본문 제목

에러 코드를 예외로 전환( Replace Error Code with Exception )

자바강좌/리팩토링

by somiyuralove 2020. 2. 9. 22:37

본문

* 에러 코드를 예외로 전환( Replace Error Code with Exception )

- 프로그램이 동작하는 도중에 어떤 에러가 발생했다고 하면, 그 때 프로그램은 발생한 에러에 대한 에러처리를 해야합니다.
- 에러처리는 아주 중요함. 하지만 한 메서드안에 정상 처리와 에러 처리가 혼재하면 프로그램의 흐름을 파악하기 어려움.
- 어떤 메서드가 실행 중에 에러가 발생했는데 그 메서드 안에서 에러를 처리하지 않는다고 합시다. 이 경우 호출하는 쪽 메서드에
- 에러를 나타내는 값, 즉 에러 코드(error code)를 반환해 에러가 발생했다고 알려야 함. 하지만 호출하는 쪽에서도 에러 처리를 하지 않고
- 에러코드를 다시 상위 메서드에 반환할지도 모름. 그렇게 되면 에러 코드 전파 처리를 프로그램 전체에 집어넣어야 함.
- 에러코드를 예외로 치환(Replace Error Code with Exception)은 에러 발생 사실을 에러 코드로 표현하는 리팩토링입니다.

* 방법
1. 에러 종류에 맞는 적절한 예외 작성
1) 예외 상태가 아니라면 예외를 사용하지 않음
2) 복구 가능한 에러라면 검사 예외 선택
3) 복구 불가능한 에러 또는 프로그래머 실수로 인한 에러라면 비검사 예외 선택
4) 컴파일
2. 메서드를 호출하는 쪽 변경(검사 예외)
1) 호출하는 쪽에서 에러를 처리한다면 try ~ catch 추가
2) 호출하는 쪽에서 에러를 처리하지 않는다면 throws 절 추가
3) 컴파일해서 테스트
3. 메서드를 호출하는 쪽 변경(비검사 예외)
1) 호출하기 전에 조건 판정
2) 컴파일해서 테스트


* 리팩토링 전 코드

package ReplaceErrorCodeWithException.before;

import java.util.HashMap;
import java.util.Map;

public class Command {
public static final Command FORWARD = new Command("foward");
public static final Command BACKWARD = new Command("backward");
public static final Command TURN_RIGHT = new Command("right");
public static final Command TURN_LEFT = new Command("left");
private static final Map<String, Command>_commandNameMap = new HashMap<String, Command>();

static {
_commandNameMap.put(FORWARD._name, FORWARD);
_commandNameMap.put(BACKWARD._name, BACKWARD);
_commandNameMap.put(TURN_RIGHT._name, TURN_RIGHT);
_commandNameMap.put(TURN_LEFT._name, TURN_LEFT);
}
private final String _name;
private Command(String name) {
_name = name;
}

public String getName() {
return _name;

}

public static Command parseCommand(String name) {
if(!_commandNameMap.containsKey(name)) {
return null;
}
return _commandNameMap.get(name);
}
}


package ReplaceErrorCodeWithException.before;

public class Direction {
public int _x;
public int _y;

public Direction(int x, int y) {
_x = x;
_y = y;
}

public void setDirection(int x, int y) {
_x = x;
_y = y;
}

}


package ReplaceErrorCodeWithException.before;

public class Position {
public int _x;
public int _y;

public Position(int x, int y) {
_x = x;
_y = y;
}

public void relativeMove(int dx, int dy) {
_x += dx;
_y += dy;
}
}


package ReplaceErrorCodeWithException.before;

import java.util.StringTokenizer;


public class Robot {
private final String _name;
private final Position _position = new Position(0,0);
private final Direction _direction = new Direction(0,1);

public Robot(String name) {
_name = name;
}

public void execute(String commandSequence) {
StringTokenizer tokenizer = new StringTokenizer(commandSequence);
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
if(!executeCommand(token)) {
System.out.println("Invalid command: " + token);
}
}
}

public boolean executeCommand(String commandString) {
Command command = Command.parseCommand(commandString);
if(command == null) {
return false;
}
return executeCommand(command);
}

public boolean executeCommand(Command command) {
if(command == Command.FORWARD) {
_position.relativeMove(_direction._x, _direction._y);
} else if (command == Command.BACKWARD) {
_position.relativeMove(-_direction._x, -_direction._y);
} else if (command == Command.TURN_RIGHT) {
_direction.setDirection(_direction._y, -_direction._x);
} else if(command == Command.TURN_LEFT) {
_direction.setDirection(-_direction._y, _direction._x);
} else {
return false;
}
return true;
}

public String toString() {
return "[ Robot: " + _name + ""
+ "position(" + _position._x + ", " + _position._y + "), "
+ "direction(" + _direction._x + ", " + _direction._y + ") ]";
}
}


package ReplaceErrorCodeWithException.before;

public class Main {
public static void main(String[] args) {
Robot robot = new Robot("Andrew");
System.out.println(robot.toString());

robot.execute("forward right forward");
System.out.println(robot.toString());

robot.execute("left backward left forward");
System.out.println(robot.toString());

robot.execute("right forward forward farvard");
System.out.println(robot.toString());
}
}

* 리팩토링 후 코드

package ReplaceErrorCodeWithException.after;

import java.util.HashMap;
import java.util.Map;

public class Command {
public static final Command FORWARD = new Command("foward");
public static final Command BACKWARD = new Command("backward");
public static final Command TURN_RIGHT = new Command("right");
public static final Command TURN_LEFT = new Command("left");
private static final Map<String, Command>_commandNameMap = new HashMap<String, Command>();

static {
_commandNameMap.put(FORWARD._name, FORWARD);
_commandNameMap.put(BACKWARD._name, BACKWARD);
_commandNameMap.put(TURN_RIGHT._name, TURN_RIGHT);
_commandNameMap.put(TURN_LEFT._name, TURN_LEFT);
}
private final String _name;
private Command(String name) {
_name = name;
}

public String getName() {
return _name;

}

public static Command parseCommand(String name) throws InvalidCommandException {
if(!_commandNameMap.containsKey(name)) {
throw new InvalidCommandException(name);
}
return _commandNameMap.get(name);
}
}


package ReplaceErrorCodeWithException.after;

public class InvalidCommandException extends Exception {
public InvalidCommandException(String name) {
super(name);
}
public InvalidCommandException() {

}
}


package ReplaceErrorCodeWithException.after;

import java.util.StringTokenizer;


public class Robot {
private final String _name;
private final Position _position = new Position(0,0);
private final Direction _direction = new Direction(0,1);

public Robot(String name) {
_name = name;
}

public void execute(String commandSequence) {
StringTokenizer tokenizer = new StringTokenizer(commandSequence);
try {
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
executeCommand(token);
}
} catch (InvalidCommandException e) {
System.out.println("Invalid command: " + e.getMessage());
}

}

public void executeCommand(String commandString) throws InvalidCommandException {
Command command = Command.parseCommand(commandString);
executeCommand(command);
}

public void executeCommand(Command command) throws InvalidCommandException {
if(command == Command.FORWARD) {
_position.relativeMove(_direction._x, _direction._y);
} else if (command == Command.BACKWARD) {
_position.relativeMove(-_direction._x, -_direction._y);
} else if (command == Command.TURN_RIGHT) {
_direction.setDirection(_direction._y, -_direction._x);
} else if(command == Command.TURN_LEFT) {
_direction.setDirection(-_direction._y, _direction._x);
} else {
throw new InvalidCommandException();
}
}

public String toString() {
return "[ Robot: " + _name + ""
+ "position(" + _position._x + ", " + _position._y + "), "
+ "direction(" + _direction._x + ", " + _direction._y + ") ]";
}
}


* 분류 코드를 상태/전략 패턴으로 치환한 코드

package ReplaceErrorCodeWithException.after;

import java.util.HashMap;
import java.util.Map;

public abstract class Command {
public static final Command FORWARD = new Forward();
public static final Command BACKWARD = new Backward();
public static final Command TURN_RIGHT = new Right();
public static final Command TURN_LEFT = new Left();
private static final Map<String, Command>_commandNameMap = new HashMap<String, Command>();

static {
_commandNameMap.put(FORWARD._name, FORWARD);
_commandNameMap.put(BACKWARD._name, BACKWARD);
_commandNameMap.put(TURN_RIGHT._name, TURN_RIGHT);
_commandNameMap.put(TURN_LEFT._name, TURN_LEFT);
}
private final String _name;
protected Command(String name) {
_name = name;
}

public String getName() {
return _name;

}

public static Command parseCommand(String name) throws InvalidCommandException {
if(!_commandNameMap.containsKey(name)) {
throw new InvalidCommandException(name);
}
return _commandNameMap.get(name);
}

public abstract void execute(Robot robot);

private static class Forward extends Command {
public Forward() {
super("forward");
}
@Override 
public void execute(Robot robot) {
robot.forward();
}
}

private static class Backward extends Command {
public Backward() {
super("backward");
}
@Override 
public void execute(Robot robot) {
robot.backward();
}
}

private static class Right extends Command {
public Right() {
super("right");
}
@Override 
public void execute(Robot robot) {
robot.right();
}
}

private static class Left extends Command {
public Left() {
super("Left");
}
@Override 
public void execute(Robot robot) {
robot.left();
}
}

}


package ReplaceErrorCodeWithException.after;

import java.util.StringTokenizer;


public class Robot {
private final String _name;
private final Position _position = new Position(0,0);
private final Direction _direction = new Direction(0,1);

public Robot(String name) {
_name = name;
}

public void execute(String commandSequence) {
StringTokenizer tokenizer = new StringTokenizer(commandSequence);
try {
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
executeCommand(token);
}
} catch (InvalidCommandException e) {
System.out.println("Invalid command: " + e.getMessage());
}

}

public void executeCommand(String commandString) throws InvalidCommandException {
Command command = Command.parseCommand(commandString);
command.execute(this);
}

public void forward() {
_position.relativeMove(_direction._x, _direction._y);
}

public void backward() {
_position.relativeMove(-_direction._x, -_direction._y);
}

public void right() {
_direction.setDirection(_direction._y, -_direction._x);
}

public void left() {
_direction.setDirection(-_direction._y, _direction._x);
}


public String toString() {
return "[ Robot: " + _name + ""
+ "position(" + _position._x + ", " + _position._y + "), "
+ "direction(" + _direction._x + ", " + _direction._y + ") ]";
}
}


관련글 더보기

댓글 영역