규칙 8. 일급 컬렉션을 사용한다.
일급 컬렉션이란 컬렉션을 wrapping 하면서 wrapping 한 컬렉션 외 다른 멤버변수가 없는 상태를 일급 컬렉션이라 한다.
즉 이번 여덟 번 째 지침은 도메인 클래스를 컬렉션으로 감싸 처리해야 하는 경우 이를 일급 컬렉션으로 구현하라는 지침이다.
우리는 이전에 세 번째 지침인 '모든 문자열과 원시 자료구조를 포장하라'에서 기본 자료구조를 포장하며 얻는 이점에 대해 다뤄본 적이 있다. 여기선 '단수형 클래스'에 도메인적 요소를 부여는 것에 초점을 두었다면, 이번 여덟 번째 지침에서는 '복수형 클래스'에 도메인적 요소를 부여하여 단수형 클래스가 가질 수 없는 비즈니스 로직을 구현하도록 초점을 두는 것이다.
예시
먼저 일급 컬렉션이 무엇인지 예시를 통해알아보자.
다음과 같이 쿠키를 팔아야 하는 매장이 있다. 이제 이 클래스에 일급 컬렉션을 적용해 보자.
public class Store {
private String name;
private List<Cookie> cookies = new ArrayList<>();
}
쿠키들의 집합을 Cookies라는 별도의 클래스로 나누었다. Cookies 클래스는 컬렉션인 ArrayList를 감싸고 있으며 이 외의 인스턴스 변수는 보유하고 있지 않기 때문에 일급 컬렉션의 조건을 충족한다.
public class Store {
private String name;
private Cookies cookies;
}
public class Cookies {
private List<Cookie> cookies = new ArrayList<>();
}
이제 매장이 운영을 시작해 다음과 같은 간단한 요구사항이 있다고 하자.
- 매장에서 쿠키 판매가 가능하다.
- 쿠키 재고가 없다면 판매할 수 없다.
- 선입 선출을 위해 가장 먼저 만들어진 쿠키를 먼저 판매한다.
이 요구사항을 일급 컬렉션을 적용하지 않고 구현해 보자.
판매와 쿠키에 대한 요구사항울 매장이 모두 관리하고 있다.
public class Store {
private String name;
private List<Cookie> cookies = new ArrayList<>();
public Cookie sellCookie() {
validateStock(cookies);
return getCookie(cookies);
}
public void validateStock(List<Cookie> cookies) {
if (cookies.isEmpty()) {
throw new IllegalArgumentException("재고가 없습니다.");
}
}
public Cookie getCookie(List<Cookie> cookies) {
return cookies.stream()
.sorted(Comparator.comparing(Cookie::getCreatedAt))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("재고가 없습니다."));
}
}
일급 컬렉션을 적용하여 구현해보자.
이제 매장은 판매만 할 수 있다. 쿠키에 대한 요구사항은 Cookies라는 클래스에서 따로 관리하고 있기 때문이다.
public class Store {
private String name;
private Cookies cookies;
public Cookie sellCookie() {
cookies.validateStock();
return cookies.getCookie();
}
}
public class Cookies {
private List<Cookie> cookies = new ArrayList<>();
public void validateStock() {
if (cookies.isEmpty()) {
throw new IllegalArgumentException("재고가 없습니다.");
}
}
public Cookie getCookie() {
return cookies.stream()
.sorted(Comparator.comparing(Cookie::getCreatedAt))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("재고가 없습니다."));
}
}
같은 쿠키를 B 매장에서도 판매를 시작했다고 가정해 보자. 일급 컬렉션을 적용하지 않았다면 B 매장에도 쿠키에 대한 요구사항을 모두 구현해야만 한다. 하지만 일급 컬렉션을 이용하여 구현한다면 B 매장에서도 A 매장과 같이 쿠키 관리에 대한 신경은 쓰지 않고 판매만 하면 된다.
이번엔 A 매장에서 커피도 판매를 시작하였다고 가정하자. 일급 컬렉션을 적용하지 않으면 커피에 대한 요구사항도 매장에서 관여해야만 한다.
일급 컬렉션을 사용함으로 인해 관심사를 분리하고 코드의 중복을 줄일 수 있다.