일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 클라이언트사이드렌더링
- publicapi
- 지네릭스
- bean
- DI
- 애너테이션
- 더티채킹
- Spring
- 항해99
- 스프링컨테이너
- privateapi
- 인수테스트
- 인프콘
- refreshtoken
- 정적중첩클래스
- 변경감지
- IoC
- 일급컬렉션
- 자바의정석
- 항해99 9기
- 스파르타코딩클럽
- 비정적중첩클래스
- 서버사이드렌더링
- 싱글톤패턴
- github actions
- 9기
- java
- Velog
- 다형성
- SOLID
- Today
- Total
멈재
[JAVA] 08. 일급 컬렉션(First Class Collection) 본문
일급 컬렉션
일급 컬렉션이란 Collection을 Wrapping하면서, Wrapping한 Collection 외 다른 멤버 변수가 없는 상태를 말한다.
....롸..? 뭐라고요..?
코드 예시
// 일급 컬렉션 적용 전
class Person {
private String name;
private Cars cars;
}
class Car {
private String name;
private String oil;
}
// 일급 컬렉션 적용 후
class Person {
private String name;
private Cars cars;
// private List<Car> cars;
}
// 일급 컬렉션
// List<Car> cars를 Wrapping
class Cars {
// 멤버 변수는 한 개만 존재해야 한다.
private List<Car> cars;
}
class Car {
private String name;
private String oil;
}
일급 컬렉션이란 단어는 소트웍스 앤솔로지의 객체지향 생활체조 파트에서 언급이 되었다.
📌 규칙 8: 일급 콜렉션 사용
이 규칙의 적용은 간단하다.
콜렉션을 포함한 클래스는 반드시 다른 멤버 변수가 없어야 한다.
각 콜렉션은 그 자체로 포장돼 있으므로 이제 콜렉션과 관련된 동작은 근거지가 마련된셈이다.
필터가 이 새 클래스의 일부가 됨을 알 수 있다.
필터는 또한 스스로 함수 객체가 될 수 있다.
또한 새 클래스는 두 그룹을 같이 묶는다든가 그룹의 각 원소에 규칙을 적용하는 등의 동작을 처리할 수 있다.
이는 인스턴스 변수에 대한 규칙의 확실한 확장이지만 그 자체를 위해서도 중요하다.
콜렉션은 실로 매우 유용한 원시 타입이다.
많은 동작이 있지만 후임 프로그래머나 유지보수 담당자에 의미적 의도나 단초는 거의 없다.
- 소트웍스 앤솔로지 객체지향 생활체조편 -
거두절미하고 일급 컬렉션은 클래스내에 Collection을 포함한 그 외 다른 멤버 변수가 없는 상태이고, 그에 따라 상태와 행위를 한 곳에서 관리할 수 있다.
일급 컬렉션을 사용하지 않고, GS 편의점에 아이스크림을 팔고있다고 가정해보자.
class GSStore {
private List<IceCream> iceCreams;
public GSStore(List<IceCream> iceCreams) {
this.iceCreams = iceCreams;
}
}
class IceCream {
private String name;
private String price;
}
특이하게도 해당 편의점은 아이스크림의 종류를 10가지 이상 판매하지 못한다고 한다.
그러면 size가 10이 넘으면 안되는 검증이 필요할 것이다.
class GSStore {
private List<IceCream> iceCreams;
public GSStore(List<IceCream> iceCreams) {
validateSize(iceCreams);
this.iceCreams = iceCreams;
}
// size가 10이 넘으면 안되는 검증
private void validateSize(List<IceCream> iceCreams) {
if(iceCreams.size() >= 10) {
throw new IllegalArgumentException("ice cream은 10개 이상의 종류를 팔 수 없습니다.");
}
}
}
class IceCream {
private String name;
private String price;
}
그런데 만약 커피, 우유, 라면, 과자 등 여러 종류의 물품이 있고 각각에 대해서도 몇 개까지만 판매 가능하다는 조건이 있다면??
각각에 대해서 검증하는 메서드를 별도로 만들거나 조건 분기로 검증을 해야할 것이다.
class GSStore {
private List<IceCream> iceCreams;
private List<Creakers> crakers;
public GSStore(List<IceCream> iceCreams, List<Crakers> crakers) {
validateSize(iceCreams);
validateSize(crakers);
validateSize(coffees);
validateSize(milks);
...
this.iceCreams = iceCreams;
this.crakers = crakers;
...
}
...
}
...
만약 CUStore에서도 동일한 조건이 있다면 또 똑같은 검증 처리를 할 것인가?
class GSStore {
private List<IceCream> iceCreams;
private List<Creakers> creakers;
public GSStore(List<IceCream> iceCreams, List<Creakers> creakers) {
// 검증...
validateSize(iceCreams);
validateSize(creakers);
validateSize(coffees);
validateSize(milks);
...
this.iceCreams = iceCreams;
this.creakers = creakers;
...
}
...
}
...
class CUStore {
private List<IceCream> iceCreams;
private List<Creakers> creakers;
public CUStore(List<IceCream> iceCreams, List<Creakers> creakers) {
// 검증.. 또 검증..
validateSize(iceCreams);
validateSize(creakers);
validateSize(coffees);
validateSize(milks);
...
this.iceCreams = iceCreams;
this.creakers = creakers;
}
...
}
...
이번엔 검증이 아닌 특정 물품을 찾는 상황이 추가되어야 한다면??
아마 GSStore와 CUStore에 동일한 기능인 특정 물품을 찾는 메서드가 추가되야 할 것이다.
// GS Store
class GSStore {
private List<IceCream> iceCreams;
public GSStore(List<IceCream> iceCreams, List<Creakers> creakers) {
// 검증...
validateSize(iceCreams);
validateSize(creakers);
validateSize(coffees);
validateSize(milks);
...
this.iceCreams = iceCreams;
this.creakers = creakers;
...
}
public IceCream find(String name) {
for (IceCream iceCream : iceCreams) {
if(iceCream.getName() == name) {
return iceCream;
}
}
throw new IllegalArgumentException("해당 상품이 존재하지 않습니다.");
}
...
}
...
// ======================================= //
// CU Store
class CUStore{
...
public IceCream find(String name) {
for (IceCream iceCream : iceCreams) {
if(iceCream.getName() == name) {
return iceCream;
}
}
throw new IllegalArgumentException("해당 상품이 존재하지 않습니다.");
}
...
}
...
이럴 경우 코드의 중복 코드가 많아지고 유지보수에도 어려움이 어려워질 것이다.
이것을 해결해주는 것이 일급 컬렉션(First Class Collection)이다.
아이스크림을 일급 컬렉션으로 만들어보면 다음과 같을 것이다.
class IceCream {
private String name;
private String price;
// getters and setters
}
// 일급 컬렉션 적용
class IceCreams {
// 일급 컬렉션은 멤버 변수가 단 한 개만 존재할 수 있다.
private List<IceCream> iceCreams;
public IceCreams(List<IceCream> iceCreams) {
validateSize(iceCreams);
this.iceCreams = iceCreams;
}
private void validateSize(List<IceCream> iceCreams) {
if(iceCreams.size() >= 10) {
throw new IllegalArgumentException("ice cream은 10개 이상의 종류를 팔 수 없습니다.");
}
}
public IceCream find(String name) {
for (IceCream iceCream : iceCreams) {
if(iceCream.getName() == name) {
return iceCream;
}
}
throw new IllegalArgumentException("해당 상품이 존재하지 않습니다.");
}
}
위 코드를 GSStore와 CUStore에 적용하게 된다면 어떻게 달라질까?
기존에는 각각의 편의점마다 다음과 같은 코드들이 적용되었다.
// GS Store
class GSStore {
private List<IceCream> iceCreams;
public GSStore(List<IceCream> iceCreams, List<Crakers> crakers) {
// 검증... 또 검증... 또또 검증.. 또또또 검증...
validateSize(iceCreams);
validateSize(creakers);
validateSize(coffees);
validateSize(milks);
...
this.iceCreams = iceCreams;
this.creakers = creakers;
...
}
public IceCream find(String name) {
for (IceCream iceCream : iceCreams) {
if(iceCream.getName() == name) {
return iceCream;
}
}
throw new IllegalArgumentException("해당 상품이 존재하지 않습니다.");
}
...
}
...
그러나 일급 컬렉션을 적용한 편의점은 다음과 같이 될 것이다.
class GSStore {
private IceCreams iceCreams;
private Crakers crakers;
public GSStore(IceCreams iceCreams, Crakers crakers) {
// 검증 완료
this.iceCreams = iceCreams;
this.crakers = crakers;
}
public IceCream find(String name) {
return iceCreams.find(name);
}
...
}
class IceCreams {
private List<IceCream> iceCreams;
public IceCreams(List<IceCream> iceCreams) {
validateSize(iceCreams);
this.iceCreams = iceCreams;
}
private void validateSize(List<IceCream> iceCreams) {
if(iceCreams.size() >= 10) {
throw new IllegalArgumentException("ice cream은 10개 이상의 종류를 팔 수 없습니다.");
}
}
public IceCream find(String name) {
for (IceCream iceCream : iceCreams) {
if(iceCream.getName() == name) {
return iceCream;
}
}
throw new IllegalArgumentException("해당 상품이 존재하지 않습니다.");
}
}
class IceCream {
private String name;
private String price;
// getters and setters
}
만약 아이스크림과 초콜릿 등의 물품이 추가돼도 검증은 일급 컬렉션이 처리할 것이다.
그리고 일급 컬렉션을 적용하기 전에 GS Store나 CU Store에서 했던 validate와 find 기능을 일급 컬렉션에게 위임하게 되면서 상태와 행위를 한 곳에서 관리할 수 있게 된다.
💡 정리하면, 일급 컬렉션을 사용하면 상태과 로직을 따로 관리할 수 있어서 클래스의 부담을 줄일 수 있고, 중복코드를 줄일 수 있다.
여기부터는 참고한 포스팅의 내용 중 일부입니다.
컬렉션의 불변성을 보장
일급 컬렉션을 검색할 때 제일 많이 보는 글은 일급 컬렉션 (First Class Collection)의 소개와 써야 할 이유 일 것이다.
이점 중 하나인 컬렉션의 값을 변경할 수 있는 메소드가 없어 불변성을 보장 해준다는 글을 볼 수 있다.
https://jojoldu.tistory.com/412
일급 컬렉션 (First Class Collection)의 소개와 써야할 이유
최근 클린코드 & TDD 강의의 리뷰어로 참가하면서 많은 분들이 공통적으로 어려워 하는 개념 한가지를 발견하게 되었습니다. 바로 일급 컬렉션인데요. 왜 객체지향적으로, 리팩토링하기 쉬운 코
jojoldu.tistory.com
하지만 필자는 일급컬렉션은 불변성을 보장하지 않으며, 보장하도록 구현해야 할 필요는 없다는 메시지를 전하고 싶다.
자세한 건 참고한 포스팅을 참고해주세요.
*참고*
https://tecoble.techcourse.co.kr/post/2020-05-08-First-Class-Collection/
일급 컬렉션을 사용하는 이유
일급 컬렉션이란? 본 글은 일급 컬렉션 (First Class Collection)의 소개와 써야할 이유를 참고 했다. 일급 컬렉션이란 단어는 소트웍스 앤솔로지의 객체지향 생활체조 규칙 8. 일급 콜렉션 사용에서 언
tecoble.techcourse.co.kr
'JAVA & Spring & JPA' 카테고리의 다른 글
[Spring/JPA] 14. AttributeConverter로 코드의 가독성을 높여보자 (0) | 2022.12.20 |
---|---|
[JAVA] 13. JAVA의 HashSet은 어떻게 동작할까? (1) | 2022.12.19 |
[JAVA/Spring] 10. CQS 패턴 (Command Query Separation) (0) | 2022.12.17 |
[JAVA/Spring] 07. MVC 패턴 (추가 예정) (0) | 2022.10.17 |
[JAVA/Spring] 04. DI & IoC & Bean - 1 (0) | 2022.10.09 |