우테코 프리코스 때 받았던 피드백 중에 이런 내용이 있었다.
원시 타입과 문자열을 포장하라.
일급 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();`
Comments powered by Disqus.