티스토리 뷰
이번 포스팅에서는 우아한 프리코스를 진행하며
스스로 학습해 적용해보았던 일급컬렉션을 정리하고자 한다.
왜 사용하는가?
일급 컬렉션이 갖는 이점은 다음과 같이 정리할수 있겠다.
- 컬렉션의 불변성을 보장한다.
- 비즈니스에 종속적인 자료구조이다.
- 컬렉션에 이름을 붙여 직관적인 코딩이 가능하다.
먼저 컬렉션의 불변성을 보장한다는건,
일급컬렉션의 조건을 생각하면 금방 깨달을수 있다.
일급컬렉션은 상수를 제외한 멤버변수는 컬렉션하나만을 유일하게 갖고
생성자를 통해 주입받는 방식으로 만들어진다.
따라서 외부에서는 해당 컬렉션에 대해 접근이 불가하고
임의로 수정, 삭제등이 불가하므로 컬렉션에 대해 불변성을 보장해줄수 있는것이다.
비즈니스에 종속적인 자료구조라는 말이 조금 어렵게 느껴질수 있다.
좀 풀어서 설명하자면, JAVA에서 지원해주는 컬렉션 프레임 워크는 이름부터 Set, Map 등
범용성이 좋지만 해당 컬렉션이 의미하는바가 무엇인지 그리고 어떻게 사용되는지는
소스를 뜯어봐야 알 수 있을것이다.
이때 일급컬렉션을 적용한다면 개발자의 네이밍에 따라 직관적인 해석이 가능하고
해당 프로그램내에서만 사용하는 일급컬렉션임을 바로 구분할수 있다는 것이다.
또 우리가 원하는 자료구조가 컬렉션을 활용하되 여러 요구사항에 따라 일반적인 컬렉션을
그대로 사용하기 힘든경우 요구사항에 따른 제한을 갖는 컬렉션만을 정의해 사용한다면
이는 해당 비즈니스에 종속적인 자료구조를 갖는다 볼수 있고 이 때 일급컬렉션을 사용하기
아주 적절하다.
어떻게 사용하는가?
그럼 우아한 프리코스 미션을 진행하며 적용했던 예시를 들어
일급컬렉션의 사용방법을 소개하고 위에서 언급한 장점을 어필해보도록 하겠다.
예시는 우아한 프리코스 4주차 미션인 크리스마스 프로모션을 예로 들겠다.
이 미션에서는 사용자가 입력한 메뉴를 입력받아 처리해야 하는데
이 때 요구사항은 음료만으로는 구성 될 수 없을것,
그리고 모든 메뉴의 수량의 총합이 20을 넘어가지 않을것 이라고 되어있다.
그럼 먼저 메뉴의 이름, 그리고 수량을 저장할 컬렉션으로 Map을 떠올릴 수 있겠다.
그러나 단순히 Map을 사용해 두가지 요구사항을 검증하는 소스를 작성한다면
Map<String, Integer> map = new HashMap<>();
map.put("타파스", 3);
map.put("제로콜라", 1);
map.put("초코케이크", 3);
...
// 메뉴에대한 요구사항을 검증하는 소스들 ...
이런식으로 작성이 될것이다.
이런식의 소스 작성은 우선 언제든 map의 내부에 접근이 가능하므로 불변성을 보장할수 없고,
또 더 나아가 여러 기능이 한데 뭉쳐서 단일 책임의 원칙에도 위배되는 소스를 작성하기 마련이다.
그럼 일급 컬렉션을 적용해보도록 하겠다.
일급 컬렉션의 생성 규칙은 간단하다.
* 상수를 제외한 멤버변수는 컬렉션하나만을 유일하게 갖고 이를 Wrapping 해줌으로 불변성을 보장한다.
public class OrderMenu {
private final Map<FoodConstants, Integer> order;
public OrderMenu(final Map<FoodConstants, Integer> order) {
this.order = order;
}
}
위와 같이 생성자의 파라미터로 받아 Wrapping 된 컬렉션은 이제 내부에서만
해당 값에 대한 처리가 가능하고 외부에선 접근이 불가한 불변성을 갖는 컬렉션이 될것이다.
그리고 요구사항에 대한 검증처리 또한,
public class OrderMenu {
private static final int DEFAULT = 0;
private static final int MAX_ORDER = 20;
private static final int BEVERAGE_NUMBER = 3;
private final Map<FoodConstants, Integer> order;
public OrderMenu(final Map<FoodConstants, Integer> order) {
validateOrderCount(order);
validateBeverage(order);
this.order = order;
}
private void validateOrderCount(final Map<FoodConstants, Integer> order) {
int sum = DEFAULT;
for (int count : order.values()) {
sum += count;
if (sum > MAX_ORDER) {
throw InputException.createException(MAX);
}
}
}
private void validateBeverage(final Map<FoodConstants, Integer> order) {
for (FoodConstants foodConstants : order.keySet()) {
if (foodConstants.getCategory() != BEVERAGE_NUMBER) {
return;
}
}
throw InputException.createException(BEVERAGE);
}
...
}
다음과 같이 처리해주어 특정 요구사항에서만 사용가능한
비즈니스에 종속적인 자료구조를 사용할수 있을것이다.
따라서 값을 관리하면서 동시에 해당 값을 일급컬렉션 내부에서만 처리하여 사용하는것이 가능해졌다.
또 OrderMenu라는 직관적인 이름을 갖는 컬렉션으로서 명확하게 구분이 가능하고 직관적인 코딩또한
가능함을 확인할 수 있다.
해당 부분에 대한 보다 자세한 소스를 보고싶다면 하단의 링크를 참조하면 된다.
https://github.com/0bliviat3/java-christmas-6-0bliviat3
'Java > 이론' 카테고리의 다른 글
Enum (0) | 2023.11.24 |
---|---|
함수형 인터페이스 (JAVA) (0) | 2023.11.17 |
제네릭(Generic) (1) | 2023.10.04 |
연산자 (Operator) (0) | 2023.09.20 |
형 변환(casting) (0) | 2023.09.17 |