일급 컬렉션의 장점과 사용 이유
포스트
취소

일급 컬렉션의 장점과 사용 이유

우테코 프리코스 때 받았던 피드백 중에 이런 내용이 있었다.

원시 타입과 문자열을 포장하라.
일급 Collection(자료구조)을 사용한다.

일급 컬렉션은 컬렉션 외의 다른 필드(인스턴스 변수)가 없는 클래스라고 한다. 이걸 어따 써먹을까?

규칙 8: 일급 콜렉션 사용
이 규칙의 적용은 간단하다.
콜렉션을 포함한 클래스는 반드시 다른 멤버 변수가 없어야 한다.
각 콜렉션은 그 자체로 포장돼 있으므로 이제 콜렉션과 관련된 동작은 근거지가 마련된셈이다.
필터가 이 새 클래스의 일부가 됨을 알 수 있다.
필터는 또한 스스로 함수 객체가 될 수 있다.
또한 새 클래스는 두 그룹을 같이 묶는다든가 그룹의 각 원소에 규칙을 적용하는 등의 동작을 처리할 수 있다.
이는 인스턴스 변수에 대한 규칙의 확실한 확장이지만 그 자체를 위해서도 중요하다.
콜렉션은 실로 매우 유용한 원시 타입이다.
많은 동작이 있지만 후임 프로그래머나 유지보수 담당자에 의미적 의도나 단초는 거의 없다. - 소트웍스 앤솔로지 객체지향 생활체조편

일급 컬렉션은 자료의 불변을 보장한다

일반적으로 변수를 불변하게 하려면 final을 쓰면 된다고 생각한다. 하지만 엄밀히 말해서 final은 재할당만을 금지하는 것으로, 컬렉션을 final로 선언할 경우에도 기존 컬렉션에 값 추가가 가능하다.

일급 컬렉션은 자료를 수정할 수 있는 일체의 행위를 다른 클래스에 노출시키지 않음으로서 불변성을 보장할 수 있다.

일급 컬렉션은 자료를 검증해 저장한다 (비지니스에 종속적이다)

기본적으로 자바에서는 자료를 원시 자료형에 담게 된다. 예를 들면 반 성적 평균을 내기 위해 모든 학생들의 성적을 담는다고 해보자.

`List<Integer> scores = new ArrayList<>(); 

scores.add(100); 
scores.add(50); 
scores.add(65);`

성적을 100점 만점으로 냈기 때문에 100을 넘어가는 점수가 scores에 들어가면 안 된다. 하지만 원시 자료형인 List<Integer>는 잘못된 값이 추가하는 걸 막을 수 없다.

`scores.add(105); // 에러 없이 추가됨`

이를 막기 위해 scores를 쓰는 곳에 검증 메소드를 추가할 수 있을 것이다.

`public void validateScore(int score) {
    if(score < 0 || score > 100) {
        throw new IllegalArgumentException("올바른 점수값을 입력해 주세요");
    }
    scores.add(score);
}`

간단한 프로그램일 때는 괜찮을지 모르지만, 이렇게 하면 scores를 필요로 하는 곳마다 검증 메소드를 하나씩 다 넣어줘야 한다.

검증을 일일이 해 주는 대신, 자료를 생성할 때 자료에 대한 요구사항이 알아서 검증되도록 하는 것이 일급 컬렉션의 개념이다.

`public class Scores {
    private final List<Integer> scores;

    public Scores(List<Integer> scores) {
        validateScore(scores)
        this.scores = scores;
    }

...`

이제 아까처럼 잘못된 값이 들어간 scores 리스트를 Scores 일급 컬렉션에 넣으려고 하면 오류가 날 것이다.

`List<Integer> scores = new ArrayList<>();

scores.add(100);
scores.add(50);
scores.add(65);
scores.add(105); // 잘못된 값

Scores classScores = new Scores(scores); // 여기서 오류 발생`

일급 컬렉션은 상태와 행위를 한 곳에서 관리한다

이렇게 한 번 생성된 일급 컬렉션 객체 classScores는 유일한 필드인 scores가 final이며, 값을 집어넣을 수 있는 메소드가 생성자 외에 없기에 절대로 수정할 수 없는 상태가 된다.

또한 일급 컬렉션도 클래스이기 때문에 scores에 관한 행위 내지는 기능들을 메소드로 추가할 수 있다. 예를 들어 학생들의 점수 합계를 내주는 메소드를 만든다고 하자.

`public int calculateSum() {
    return scores.stream().mapToInt(Integer::intValue).sum();
}`

이렇게 한 곳에서 상태와 함께 행위를 관리하여 나중에 프로젝트 담당자가 바뀌거나, 오래 되어서 구현 내용을 까먹더라도 간편하게 사용할 수 있다.

`int scoreSum = scores.calculateSum();`
This post is licensed under CC BY 4.0 by the author.

자바 레이싱 게임 - TDD

씽크패드 X1 Carbon 5세대 액정 4K로 개조하기 - 1. 자료 수집

Comments powered by Disqus.