멈재

[JAVA] 08. 일급 컬렉션(First Class Collection) 본문

JAVA & Spring & JPA

[JAVA] 08. 일급 컬렉션(First Class Collection)

멈재 2022. 10. 19. 11:56
728x90

일급 컬렉션

일급 컬렉션이란 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