[내일배움캠프] 숫자 야구 게임 구현 - 리팩토링(3)

2024. 9. 23. 20:18내일배움캠프

 Level04 요구사항까지 구현을 하고 리팩토링을 진행했다. 이번 리팩토링에서는 기본적으로 변수명 또는 메서드명을 수정하고 주석 추가작성 및 수정을 진행하였다. 그 밖의 수정 내용은 아래에 작성했으며, 수정된 코드는 여기서 확인할 수 있다.

 

1. Scanner in NumbersBaseballApp

 'Main.main()' 메서드는 'Scanner' 및 'NumbersBaseballApp' 객체를 생성해 'NumbersBaseballApp.start(Scanner)' 메서드를 호출한다. 하지만 사실 'main()' 메서드에서 'Sacnner' 객체를 파라미터로 넘기는 것 외에 사용할 일이 없다. 그래서 'NumbersBaseballApp' 객체에서 'Scanner' 객체를 생성하도록 아래와 같이 수정하였다.

NumbersBaseballApp 클래스에 Scanner 객체 필드 추가

 

이제부터 사용자의 입력을 받는데 사용되는 'Scanner' 객체는 'NumbersBaseballApp' 객체 생성시 생성되고 'NumbersBaseballApp.start()' 메서드는 'Scanner' 객체를 파라미터로 전달 받을 필요가 없어져 아래와 같이 수정했다.

파라미터가 없어진 start() 메서드

 

그리고 'start()' 메서드의 수행부의 일부를 아래와 같이 메서드로 분리했다.

start() 메서드에서 분리한 selectNumberLength() 메서드

 

'selectNumberLength()' 메서드는 'start()' 메서드의 수행부에서 '사용자가 정답의 길이를 입력하는 로직' 을 분리한 것으로 문자열을 입력 받아 'int' 타입으로 파싱한 값을 반환한다.

 

 

2. 기본 자리수 변수 상수화

 숫자 야구 게임은 메뉴의 '0. 자리수 설정하기' 또는 '1. 게임 시작하기' 항목을 택해 플레이 할 수 있으며, 기본적으로 길이 '3' 의 정답을 생성하고 맞추는 게임을 플레이할 수 있도록 구현하였다. 또한 사용자가 자리수를 설정하는 경우 입력 값을 파라미터로 전달해 해당 자릿수의 정답을 생성하고 맞추는 게임을 플레이할 수 있도록 하였다.

 

그런데 위의 과정을 구현할 때, 'NumbersBaseballApp.start()' 메서드의 수행부에 '기본 자리수' 를 갖는 변수를 선언해 버렸다. 큰 문제가 아닐 수도 있을지 모르겠으나 나의 경우 '기본 자리수' 같은 값은 충분히 변경될 수 있는 값이라 생각했다. 근데 '변경' 가능성이 높은 값을 저장하는 변수가 'start()' 메서드 중앙에 떡 하니 있으니, 해당 변수를 수정하고자 하면 수행부를 하나씩 확인해 가며 비효율적인 유지보수를 하게 될 것이다. 구현한 사람도 이렇게 생각하는데 만약 다른 개발자가 해당 변수를 찾고자 할 경우에는... 말하지 않아도 알 것 같다.

'기본 자리수' 값을 갖는 상수 필드 추가

 

그래서 위의 이미지와 같이 'NumbersBaseballApp' 클래스의 필드에 '기본 자리수' 값을 갖는 상수를 추가하였다. '1. 게임 시작하기' 를 선택하는 경우 'int defaultNumberLength' 을 파라미터로 사용해 게임을 플레이할 수 있다. '0. 자리수 설정하기' 의 경우에는 기존처럼 사용자가 입력한 값을 파라미터로 사용해  게임을 플레이하게 된다.

 

 

3. ValidCriteria (enum) 클래스 분리

 Level04 요구사항을 반영하면서 게임 플레이시 입력하는 값을 검증할 때, 사용자가 지정한 '자리수' 에 따라 적절한 정규식을 바꿔 검증에 사용해야 했다. 근데 이를 'if 문' 또는 'switch 문' 을 사용해 구현할 경우, 정규식을 통해 한 번에 유효성을 검증하던 기존 메서드의 기능을 분리하거나 일부 기능이 중복된 채로 코드를 구현해야 했다.

 

그래서 사용자가 입력한 '자리수' 를 파라미터로 사용해 'ValidCriteria' 클래스에서 파라미터와 같은 필드 값을 갖는 상수를 조회해 반환하는 메서드를 'ValidCriteria' 에 아래와 같이 구현하는 것으로 위의 문제를 해결했다.

 

하지만 ValidCriteria 클래스에 조회 메서드를 구현하게 되면서, 구지 'length' 필드가 필요 없는 상수들 또한 필드를 추가하게 되었고 또한 조회 메서드 사용 시, 찾고자 하는 상수가 아닌 상수들도 반복문을 통해 비교해야 하는 불필요한 수행을 하게 되었다. 그래서 정답을 맞힐 때 입력하는 값의 유효성 검증 시 사용되는 정규식(Regex)을 필드로 갖는 상수들을 따로 아래와 같이 분리하게 되었다.

추가된 UserAnswerRegex 클래스

 

 

4. 예외 클래스 추가

 UserAnswerRegex 클래스에서 길이를 파라미터로 받아 상수를 조회하는 'findByLength(int)' 메서드는 해당 클래스의 모든 상수의 'length' 필드와 파라미터를 비교해 같은 값을 갖는 상수가 있을 때 해당 상수를 반환하고 없다면 예외를 발생시킨다.

 

하지만 기존처럼 'BadInputException' 을 발생시키는 것은 명확한 예외를 파악하기 힘들게 하므로 아래와 같이 '상수가 존재하지 않는다' 라는 의미를 파악할 수 있는 'NotExistConstantsException' 을 추가적으로 구현해 사용했다.

추가된 NotExistConstantsException 예외 클래스
NotExistConstantsException 을 사용하는 UserAnswerRegex.findByLength(int) 메서드