정의
컬렉션을 포장한 클래스로, 컬렉션과 관련된 로직을 해당 클래스에 담아 일급 객체*처럼 활용하는 방식
이 클래스는 컬렉션을 포함하고 있으며, 그 컬렉션을 유일한 인스턴스 변수로 가지는 객체임
- 컬렉션 자체와 컬렉션을 사용하는 로직을 일관되게 관리할 수 있어, 유지보수가 쉬운 코드를 작성할 수 있음
- 데이터 무결성, 불변성, 가독성 등 객체 지향의 장점을 활용하여 안정적이고 응집력 있는 코드를 만들기 좋음
* 일급 객체란?:
변수에 할당될 수 있고, 함수의 인수로 전달되거나, 함수의 반환값으로 사용할 수 있는 객체. 객체, 함수, 메서드 등이 일급 객체로 다뤄질 수 있음. 다른 데이터와 마찬가지로 프로그램에서 직접 다룰 수 있는 객체. 함수형 프로그래밍에서 중요하게 다뤄지는 개념
- 예: String message = "Hello, World!"; 에서 선언된 문자열 객체이자 변수 message는 일급 객체임."Hello, World!"는 단순한 문자열 데이터로 일급 객체가 아님. 데이터는 객체로 만들어질 수 있지만, 문자열 그 자체는 객체가 아님.
- 예: Runnable myRunnable = () -> System.out.println("Hello from Runnable"); 라는 람다 표현식에서 myRunnable도 일급 객체임. (함수나 메서드도 일급 객체일 수 있음.)
그럼 모든 객체는 일급 객체 아닌가?:
맞음. 근데 일급 객체 개념 자체가 프로그래밍 언어에서 객체를 어떻게 다루는지에 대한 거라서 아래 조건을 충족해야 함.
- 변수에 할당 가능해야 하고 / 함수의 인수로 전달 가능해야 하고 / 함수의 반환값으로 사용 가능해야 하고 / 데이터 구조(리스트, 맵 등)에 포함 가능해야 함
자바에서 모든 객체는 위에 해당하기 때문에 모든 객체는 일급 객체임.
예시
// StudentList: 일급 컬렉션으로, 학생 목록을 관리하면서 비즈니스 로직을 포함하고 있음
// 외부에서는 컬렉션 내부의 학생 목록을 변경할 수 없고, getStudents()를 통해서도 불변 리스트만 받을 수 있음
import java.util.Collections;
import java.util.List;
import java.util.Objects;
public class StudentList {
// 컬렉션 하나만 인스턴스 변수로 가짐
private final List<Student> students;
public StudentList(List<Student> students) {
this.students = Objects.requireNonNull(students);
}
// 컬렉션에 대한 직접 접근을 막고, 불변성을 보장
public List<Student> getStudents() {
return Collections.unmodifiableList(students);
}
// 비즈니스 로직 포함: 특정 학생이 있는지 확인
public boolean containsStudent(Student student) {
return students.contains(student);
}
// 비즈니스 로직 포함: 전체 학생 수
public int count() {
return students.size();
}
}
// Order 클래스가 Item 객체들의 리스트를 관리하는 경우에,
// 리스트를 직접 사용하지 않고 일급 컬렉션인 ItemList를 사용하는 예시
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
class Item {
private final String name;
private final double price;
public Item(String name, double price) {
this.name = name;
this.price = price;
}
public double getPrice() {
return price;
}
}
class ItemList {
private final List<Item> items;
public ItemList(List<Item> items) {
this.items = new ArrayList<>(items);
}
// 컬렉션에 새로운 항목 추가 로직 포함
public ItemList addItem(Item item) {
List<Item> newItems = new ArrayList<>(this.items);
newItems.add(item);
return new ItemList(newItems); // 불변성 유지
}
// 컬렉션에서 특정 비즈니스 로직 수행
public double calculateTotalPrice() {
return items.stream().mapToDouble(Item::getPrice).sum();
}
// 컬렉션의 보호된 접근
public List<Item> getItems() {
return Collections.unmodifiableList(items);
}
}
public class Order {
private final ItemList itemList;
public Order(ItemList itemList) {
this.itemList = itemList;
}
public double getTotalPrice() {
return itemList.calculateTotalPrice();
}
}
특징과 장점
1. 특징
1) 컬렉션 하나만 인스턴스 변수로 가짐
- 일급 컬렉션 클래스는 컬렉션을 관리하는 역할을 하지만, 인스턴스 변수로 컬렉션(List, Set 등) 하나만 가질 수 있음
- 다른 필드를 포함하지 않음으로써 컬렉션 관리에 집중
2) 불변성을 보장
- 상태를 변경하지 않고 새로운 객체를 반환함으로써 외부에서 컬렉션을 수정할 수 없도록 불변성을 보장
- 이를 통해 컬렉션에 불필요한 사이드 이펙트가 생기는 것을 방지
3) 비즈니스 로직 포함
- 컬렉션의 조회, 추가, 삭제 등 행위를 일급 컬렉션 내부에 구현하여, 컬렉션과 관련된 비즈니스 로직을 해당 클래스에 포함시킴
- 코드의 응집도가 높아지고, 컬렉션 사용과 관련된 중복 코드가 줄어듦
- 컬렉션 관련 비즈니스 로직을 캡슐화할 수 있음
(예: 컬렉션에 요소 추가/제거 시 특정 조건을 검증하는 로직을 일급 컬렉션에 넣어 일관된 검증 수행)
4) 컬렉션 외부 직접 접근 차단
- 일급 컬렉션 내 메서드를 통해 접근하게 함으로써, 컬렉션에 직접 접근하는 것을 막아 캡슐화를 강화
- 컬렉션을 통해 발생할 수 있는 불필요한 결합도를 줄임
2. 장점
1) 데이터 변경 통제
- 컬렉션을 불변하게 관리할 수 있어 안전성이 높아짐
2) 응집도 증가
- 컬렉션과 관련된 비즈니스 로직을 한 곳에 모아 코드 가독성과 유지보수성 향상되고, 관리가 쉬워짐
3) 중복 코드 방지
- 컬렉션 사용과 관련된 중복 코드와 부작용이 줄어듦
4) 유효성 검증 및 제약 조건 적용
- 컬렉션에 데이터를 추가하거나 조회할 때 제약 조건을 쉽게 관리할 수 있음
비고
1. 정리해 보니 어렴풋이 알고 있던 정의가 말끔해졌다.
레퍼런스
1. 멘토링 강의, 도서관, 코드 예시의 경우 ChatGPT