일급 컬렉션 사용 후기
일급 컬렉션 소개와 사용해야 되는 이유
우아한 테크 pro 사전 과제를 하면서 사용하게 된 일급 컬렉션에 대해서 찾아보고 정리한 글 입니다.
일급 컬렉이란?
일급 컬렉션은 Collection을 Wrapping 하면서, Wrapping한 Collection 외 다른 멤버 변수가 없는 상태를 말한다.
※ 소트웍스 앤솔로지의 객체지향 생활체조 규칙8. 일급 컬렉션 사용에서 언급되었다.
사전 과제는 여러 자동차를 경주시켜서 우승자를 뽑는 게임을 구현하는 부분이었습니다. (시도 횟수 입력 받음 → 횟수 동안 각 자동차는 랜덤으로 숫자를 받아 FORWARD(4)를 넘으면 전진, 아래면 멈춤을 반복!)
class Car {
private static final int FORWARD_NUM = 4;
private String name;
private int position;
public void move() {
if (getRandom() >= FORWARD_NUM)
this.position++;
}
private getRandom() {
// 랜덤 번호(0 ~ 9) 생성
}
}
여러 자동차들을 한번에 전진 시키기 위해서는 List 생성하고, for 문을 써야 됩니다.
각 자동차들의 상태와 move 로직을 한번에 관리하기 위해서 일급 컬렉션을 사용하는 것이었습니다.
public class Cars {
private final List<Car> cars;
// 👾 1. 생성자 ISSUE 부분
public Cars(final List<Car> cars) {
this.cars = cars;
}
public void move() {
for (Car car : cars) {
car.move();
}
}
...
// 👾 2. Getter ISSUE 부분
public List<Car> getCars() {
return cars;
}
}
일급 컬렉션 (First Class Collection)의 소개와 써야할 이유에서는 4가지의 장점을 소개하고 있습니다.
- 비지니스에 종속적인 자료구조
- 불변
- 상태와 행위를 한곳에서 관리
- 이름이 있는 컬렉션 위의 글에서는 4번에서 네이버페이와 카카오페이를 예시로 드는 부분이 있어 좀 더 명확하게 장점을 알 수 있으니 참고 바랍니다.
하지만 Cars 클래스에서는 1, 3, 4번의 장점을 사용할 수 있었지만 불변성에 대해서는 지키지 못했습니다.
👾 1. 생성자 ISSUE 부분
List<Car> carList = new ArrayList<>();
carList.add(new Car("dooly"));
Cars cars = new Cars(carList);
// 👇 이 부분! → cars 도 함께 적용 😓
carList.add(new Car("hoit"));
이 부분에서 cars가 외부의 carList를 이용해서 변경에 함께 적용되게 됩니다.
(cars : ‘hoit’ 자동차가 추가)
👾 2. Getter ISSUE 부분
List<Car> carList = new ArrayList<>();
carList.add(new Car("dooly"));
Cars cars = new Cars(carList);
// 👇 이 부분! → cars 도 함께 적용 😓
cars.getCars().add(new Car("hoit"));
이 부분 또한 getCars() 로 받아온 List는 외부 요인 입니다. 여기서 추가를 해도 함께 적용되는 문제가 발생합니다. 🫠
즉 위의 Cars 클래스는 불변성을 지킬 수가 없습니다. >
이를 위해서 일급 컬렉션의 불변성을 위해 코드를 수정해야 합니다.
🪄 ISSUE 부분 해결하기 (불변성 지키기)
public class Cars {
private final List<Car> cars;
// 🪄 1. 생성자 ISSUE 부분 해결 → 불변성 보장
public Cars(final List<Car> cars) {
this.cars = new ArrayList<>(cars);
}
public void move() {
for (Car car : cars) {
car.move();
}
}
...
// 🪄 2. Getter ISSUE 부분 해결 → 불변성 보장
public List<Car> getCars() {
return Collections.unmodifiableList(cars);
}
}
위와 같이 생성자 부분에서 List를 새로 생성함으로써 매개변수로 받은 리스트와 단절시켜 불변성을 지킬 수 있고,
Getter 메서드의 경우는 Collections.unmodifiableList 메서드를 이용해서 수정 불가능 하도록 반환하여 불변성을 지킬 수 있습니다.
(unmodifiableList로 반환된 리스트를 수정하려고 하면 UnsupportedOperationException이 발생합니다.)
불변이 꼭 필수가 아닐지도 모르겠지만,
정보를 최대한 불변성으로 가져가는 것이 의도치 못한 변경을 막을 수 있으므로 할 수 있다면 최대한 가져가야 합니다.
여기까지가 일급 컬렉션 사용 후기였습니다.