1주차 과제 - 문자열 덧셈 계산기
기능 명세
1. 기본적으로 쉼표(,) 또는 콜론(:)을 구분자로 가짐
2. "//"와 "\n" 사이에 위치하는 문자를 커스텀 구분자로 사용
예외 처리
1. 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생
2. 잘못된 입력 예시: 음수, 구분자를 제외한 문자들
구현 기능 목록(초안)
구분자 모음이 있는 클래스 설계
- String 리스트 필드 => 디폴티 값인 쉼표(,) 콜론(:) 추가
- 커스텀 구분자를 추가하는 메소드 구현
로직 구현
- 입력 값을 커스텀 구분자 문자열과 계산기 문자열로 나누는 메소드 구현
- 입력 값에서 커스텀 구분자 리스트를 반환하는 메소드 구현
- 커스텀 구분자 리스트를 구분자 클래스의 필드에 넣는 메소드 구현
- 문자열에서 숫자를 추출하여 더하는 계산기 메소드 구현
고민 사항
매 입력마다 디폴트 구분자 + 커스텀 구분자가 다른데 어떤 식으로 값을 추가해야 할까?
커스텀 구분자를 추가하는 로직은 서비스 코드가 알 필요가 없다. 그냥 특정 구분자를 추가만 요청하면 된다.
따라서 매 요청 때마다 새로운 구분자 리스트가 들어 있는 객체가 만들면 되지 않을까? 생각이 들었다.
처음에는 여러 개의 요청이 들어올 때 동시성 이슈가 발생할 수 있겠다는 걱정을 했다.
하지만 요청 때마다 구분자 객체를 만들면 각각이 서로 다른 구분자 리스트를 가질 수 있다. 따라서 동시성 이슈는 발생하지 않을 것이다.
서비스 로직에서 구분자 객체를 어떻게 받을지?
서비스 코드에서 new를 통해 객체를 받을 수 있다. 하지만 다음을 고려해봐야 한다.
new를 통해 구분자 객체를 받으면 구분자 클래스의 생성자에 디폴트 구분자를 넣어야 한다. 생성자에 의무적으로 디폴트 구분자가 추가된다면 만약 다른 서비스에서 해당 객체를 사용하고자 할 때 무조건 적으로 디폴트 구분자가 추가될 수 밖에 없다.
다시 말해서 구분자 클래스가 계산기 서비스 코드에 심하게 의존한다 생각했다.
따라서 static 메소드를 활용해 getInstanceWithDefaultSeparator 를 통해 가져오면 서비스 코드에서
의존 관계 없이 객체를 가져올 수 있겠다 생각이 들었다.
또 다른 방법은 추상 클래스를 이용해 서로 다른 구분자에 따른 구분자 하위 클래스를 만드는 것도
생각해봤다. 하지만 기능이 바뀌는 것이 아닌 디폴트 구분자가 바뀐다는 이유로 분리해야 할 필요는 없다 판단해
추상 클래스는 사용하지 않기로 했다.
구분자 리스트으로 계산기 문자열을 계산하는 방식
총 2가지 경우가 가능하다.
1. 서비스 코드에서 문자열.split(구분자 리스트 모음을 정규식으로 바꾸는 메소드)
2. 구분자 객체 내 메소드를 통해서 계산하기
구분자를 기준으로 계산하는 책임이 어디에 할당해야 될까?
이를 생각하기 위해서 서비스 코드와 구분자 클래스의 책임에 대해 생각해봤다.
입력값로부터 커스텀 구분자를 추출하는 책임은 확실히 서비스 코드에게 있다.
하지만 구분자 클래스는 구분자 리스트를 받는 필드 뿐만 아니라 구분자를 기준으로 계산하는 책임까지 있다.
따라서 구분자 클래스라고 명명하는 것이 아닌 구분자가 있는 계산기 클래스라 부르는게 정확하다.
이를 기준으로 구현 기능 목록을 다시 작성하였다.
개선된 구현 기능 목록
구분자 모음이 있는 클래스 설계계산기 클래스 구현
- String 리스트 필드 => 디폴트 값인 쉼표(,) 콜론(:) 추가
- 커스텀 구분자를 추가하는 메소드 구현
- 구분자 리스트를 기준으로 계산하는 메소드 구현
서비스 코드 구현
- 입력 값을 커스텀 구분자 문자열과 계산기 문자열로 나누는 메소드 구현
- 입력 값에서 커스텀 구분자 리스트를 반환하는 메소드 구현
- 커스텀 구분자 리스트를 구분자 클래스의 필드에 넣는 로직 작성- 문자열에서 숫자를 추출하여 더하는 계산기 메소드 구현
1차 구현 후 고민 사항
계산기의 책임은 어디까지인가?
기존에는 계산기 안에 구분 문자 리스트를 넣었다. 하지만 계산기에 구분 문자 필드가 필요할까?
라는 생각이 들었다. 계산서비스에서 `calculate` 함수에 파라미터로 구분 문자 리스트를 넘기는게
더 계산이라는 책임에 맞는 코드가 되는 것 같다고 생각이 들었다.
최초에 구분 문자 추가 로직을 구분자가 있는 계산기라 구분 문자도 해당 서비스에 있어야 하지 않나
생각이 들어 구분문자 필드를 계산기 서비스에 넣었다.
하지만 계산기는 단순 계산하는 로직이다. 만약 구분문자가 없는 서비스와 같이 사용하게 된다면
구분문자 필드가 없는 클래스가 생길 텐데, 이렇게 되면 둘을 하나의 인터페이스로 묶기 어렵다 판단됐다.
따라서 Calculator 서비스에 구분 문자 리스트 필드를 제거하고 구분문자 관련된 기능을 하는
DelimiterUtil을 따로 만들기로 했다.
2차_개선_구현_기능_목록
계산기 클래스 구현- String 리스트 필드 => 디폴트 값인 쉼표(,) 콜론(:) 추가- 커스텀 구분자를 추가하는 메소드 구현
- 구분자 리스트를 기준으로 계산하는 메소드 구현
서비스 코드 구현
- 입력 값을 커스텀 구분자 문자열과 계산기 문자열로 나누는 메소드 구현
- 입력 값에서 커스텀 구분자 리스트를 반환하는 메소드 구현
- 커스텀 구분자 리스트를 구분자 클래스의 필드에 넣는 로직 작성
구분자 Util 구현
- 커스텀 구분자를 받아 최종 구분자 리스트를 반환하는 메소드 구현