우테코 프리코스 커뮤니티에서 객체지향 생활체조를 알게되었고 때문에 일급 컬렉션을 처음 접했다.
일단 일급 컬렉션이 뭔지부터 알아보았다.
https://jojoldu.tistory.com/412
일급 컬렉션 (First Class Collection)의 소개와 써야할 이유
최근 클린코드 & TDD 강의의 리뷰어로 참가하면서 많은 분들이 공통적으로 어려워 하는 개념 한가지를 발견하게 되었습니다. 바로 일급 컬렉션인데요. 왜 객체지향적으로, 리팩토링하기 쉬운 코
jojoldu.tistory.com
https://tecoble.techcourse.co.kr/post/2020-05-08-First-Class-Collection/
일급 컬렉션을 사용하는 이유
일급 컬렉션이란? 본 글은 일급 컬렉션 (First Class Collection)의 소개와 써야할 이유를 참고 했다. 일급 컬렉션이란 단어는 소트웍스 앤솔로지의 객체지향 생활체조 규칙 8. 일급 콜렉션 사용에서 언
tecoble.techcourse.co.kr
여러 사이트를 참고하며 알게된 일급 컬렉션의 특징은 다음과 같다.
- 비즈니스에 필요한 형태의 자료구조를 만들어 비즈니스에 종속적인 자료구조가 됨
- 불변성을 보장하지 않음
- Collection 원본에 접근해 값을 변경하지 않는다면 불변성 보장
- 값과 로직이 함께 존재해 상태와 행위를 한 곳에서 관리함
- 이름이 있는 컬렉션
나는 숫자를 담는 일급 컬렉션을 만들었다.
public class Numbers {
private final List<Integer> numbers;
public Numbers(List<Integer> numbers) {
validateSize(numbers);
validateRange(numbers);
validateDuplication(numbers);
this.numbers = numbers;
}
...
}
그리고 각각 따로 만들어진 객체의 숫자들을 비교해야했는데, 숫자 자체에 접근하려면 getter를 사용해야했다.
jojoldu님은
저 역시 일급컬렉션에 필요한 값만 반환하는 별도의 메소드들을 만들어서 사용하고 있습니다.
(컬렉션 그대로 반환하지 않고, 외부에선 컬렉션 내부 필드에 단독 접근은 불가능한 형태죠)
생성자로 받은 컬렉션값을 그대로 반환하는 기능은 두지 않고, 가공된 값 or 목적에 맞는 값만 반환하는 형태로 구현하고 있습니다.
라고 하셨다.
그래서 검증된 값만 반환하도록 getter를 사용했다. 그런데 객체지향 생활체조는 도메인 객체 모델에 getter/setter를 지양하라고 했다.
나는 고민 끝에 "Numbers는 서비스 로직을 수행하는 도메인 객체 모델이 아니기 때문에 getter를 사용해도 된다!"라고 결론내렸다.
Numbers는 숫자들을 검증하고 규격에 맞는 숫자들을 만든다. 서비스 로직에 포함시킬 수 있지만, 나는 숫자들을 비교하는 부분부터 서비스 로직이라고 생각했다.
getter로 원본 값에 접근해도 값이 바뀌는 불상사를 막기위해 티거님의 글을 참고해서 unmodifiableList()
를 사용했다. 그리고 아래와 같이 getter를 추가했다.
...
public List<Integer> getNumbers() {
return Collections.unmodifiableList(numbers);
}
...
그럼 일급 컬렉션 객체를 어떻게 생성해야 할까?
객체 생성방식은 초기화된 컬렉션 객체를 반환하는 메서드를 일급 컬렉션 객체 생성자의 파라미터로 넘겨주면 된다.
나는 코드의 중복을 줄이기 위해 템플릿 메서드 패턴을 적용했다.
UserNumbersGenerator
와 ComputerNumbersGenerator
가 NumbersGenerator
를 상속받고 createNumbers()
를 오버라이딩한다.
public abstract class NumbersGenerator {
public List<Integer> generate() {
Numbers numbers = new Numbers(createNumbers());
return numbers.getNumbers();
}
abstract List<Integer> createNumbers();
}
public class UserNumbersGenerator extends NumbersGenerator{
public List<Integer> createNumbers() {
List<Integer> userNumbers = new ArrayList<>();
System.out.print("숫자를 입력해주세요 : ");
String userInput = readLine();
for (int i = 0; i < userInput.length(); i++) {
String str = userInput.substring(i, i + 1);
userNumbers.add(Integer.parseInt(str));
}
return userNumbers;
}
}
그리고 NumbersGenerator
객체의 generate()
를 호출하면 Numbers
객체의 원본 List를 반환한다.
List<Integer> userNumbers = numbersGenerator.generate();
일급 컬렉션을 어떻게 적용할지 많이 고민했지만 이렇게 하는게 맞는지 잘 모르겠다.
그래도 일급 컬렉션을 사용해봤다는데 의의를 두고 싶다.
'Java' 카테고리의 다른 글
Java 기초 문법(1) (0) | 2023.12.20 |
---|---|
Java 구동 방식 (1) | 2023.12.20 |
팩토리 메서드 패턴을 적용해보자 (0) | 2023.10.26 |
템플릿 메서드 패턴을 적용해보자 (0) | 2023.10.26 |
static 메서드는 언제 사용해야할까? (1) | 2023.10.26 |