1. 😱 중복된 검증 로직의 지옥에서 탈출하기
문제 코드
//일급 컬렉션을 사용하지 않을 시
public class RacingGame {
public void race(List<Car> cars) {
if (cars == null || cars.isEmpty()) {
throw new IllegalArgumentException("자동차가 없습니다.");
}
if (cars.size() > 8) {
throw new IllegalArgumentException("자동차가 너무 많습니다.");
}
// 게임 로직...
}
public void announceWinner(List<Car> cars) {
// 여기도 검증이 필요합니다
if (cars == null || cars.isEmpty()) {
throw new IllegalArgumentException("자동차가 없습니다.");
}
// 우승자 발표 로직...
}
}
- 매 메서드 작성시 검증 로직의 필요성을 고민해야 합니다
- 동일한 검증 로직이 여러 곳에 흩어져 있습니다
- 검증 로직 변경 시 모든 곳을 수정해야 합니다
일급 컬렉션 적용
public class Cars {
private final List<Car> cars;
public Cars(List<Car> cars) {
validateCars(cars);
this.cars = new ArrayList<>(cars);
}
private void validateCars(List<Car> cars) {
if (cars == null || cars.isEmpty()) {
throw new IllegalArgumentException("자동차가 없습니다.");
}
if (cars.size() > 8) {
throw new IllegalArgumentException("자동차가 너무 많습니다.");
}
}
}
2. 🔒 불변성 보장으로 얻은 안정성
문제 코드
public class RacingGame {
private List<Car> cars; // 여러 곳에서 수정이 가능한 상태입니다
public void addCar(Car car) {
cars.add(car); // 경주 중에도 차량 추가가 가능합니다
}
public void removeCar(Car car) {
cars.remove(car); // 경주 중에 차량 제거도 가능합니다
}
}
- 경기 진행 중에도 자동차 추가/제거가 가능합니다
- 여러 메서드에서 컬렉션 수정이 가능하여 디버깅이 어렵습니다
- 특정 시점의 컬렉션 상태를 예측하기 어렵습니다
일급 컬렉션 적용
public class Cars {
private final List<Car> cars; // final로 재할당을 방지합니다
public Cars(List<Car> cars) {
this.cars = new ArrayList<>(cars); // 방어적 복사를 수행합니다
}
// 수정 메서드가 없어 불변성이 보장됩니다
public List<Car> getCars() {
return Collections.unmodifiableList(cars);
}
}
3. 🎯 상태와 행위의 응집도 높이기
문제 코드
// 여러 곳에 흩어진 자동차 관련 로직들입니다
public class CarUtils {
public static int getMaxPosition(List<Car> cars) { ... }
}
public class WinnerCalculator {
public List<Car> findWinners(List<Car> cars) { ... }
}
public class RacingGame {
public void moveForward(List<Car> cars) { ... }
}
- 자동차 관련 로직이 여러 클래스에 흩어져 있습니다
- 새로운 기능 추가 시 위치 선정이 어렵습니다
- 코드 재사용이 어려운 상태입니다
일급 컬렉션 적용
public class Cars {
private final List<Car> cars;
public Cars move() {
List<Car> movedCars = cars.stream()
.map(Car::move)
.collect(Collectors.toList());
return new Cars(movedCars);
}
public List<Car> findWinners() {
int maxPosition = getMaxPosition();
return cars.stream()
.filter(car -> car.getPosition() == maxPosition)
.collect(Collectors.toList());
}
private int getMaxPosition() {
return cars.stream()
.mapToInt(Car::getPosition)
.max()
.orElse(0);
}
}
생각 없이 일급 컬렉션을 써왔지만 이번 기회에 공부해봄으로써 일급 컬렉션의 본질을 알 수 있었습니다.
일급 컬렉션(First Class Collection)이라는 개념은 The ThoughtWorks Anthology라는 책의 6장에서 Jeff Bay가 처음 소개했습니다.
'객체지향' 카테고리의 다른 글
🤔 private 메소드는 어떻게 테스트 할까(feat 객체 분리) (0) | 2024.11.12 |
---|---|
🚫 else 금지 이유와 개선 법 (0) | 2024.11.12 |
🫥 디미터 법칙의 오해 (1) | 2024.11.12 |
Google Java Style Guide 번역 (1) | 2024.10.15 |
[클린코드] 5 ~ 10장 (0) | 2024.03.04 |