ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 일급 컬렉션
    ☕️ java 2023. 10. 24. 02:56

     

     

    🧑🏻‍💻 이동욱님의 글을 보고 공부용으로 정리했습니다.

     

    ⭐ 일급 컬렉션


    Collection을 Wrapping 하면서, 그 외 다른 멤버 변수가 없는 상태를 일급 컬렉션이라 한다.

    Map<String, String> map = new HashMap<>();
    map.put("1", "A");
    map.put("2", "B");
    map.put("3", "C");
    
    public class GameRanking {
    
        private Map<String, String> ranks;
    
        public GameRanking(Map<String, String> ranks) {
            this.ranks = ranks;
        }
    }

     

    🌟 Wrapping의 이점

    1. 비지니스에 종속적인 자료구조
    2. Collection의 불변성 보장
    3. 상태와 행위를 한 곳에서 관리
    4. 이름이 있는 컬렉션

     

    1️⃣ 비지니스에 종속적인 자료구조

    📖 숫자 야구의 2가지 조건

    • 3개의 번호로 이루어져있다.
    • 3개의 번호는 1 ~ 9 까지의 서로 다른 임의의 수이다.

     

    🧑🏻‍💻 구현

    public class BaseBallApp {
    
        private static final int DIGIT = 3;
        ...
        
        if(!InputValidator.isValidatedAnswer(DIGIT, inputAnswer)) {
             throw new IllegalArgumentException(
                    String.format("%d자리 숫자가 아닌 잘못된 입력값 입니다. - %s", DIGIT, inputAnswer));
        }
        ...
    }
    • 비지니스 로직을 서비스 부분에서 처리

     

    ⚠️ 문제

    숫자 야구 번호가 필요한 곳에서 계속해서 검증로직이 들어가야 한다.

    • 모든 코드에 대해 알고 있지 않다면 문제가 발생할 수 있다.

     

    💡 숫자 야구의 조건을 만족하는 자료구조를 직접 만들자.

    ⇒ 해당 조건으로만 생성할 수 있는 자료구조

     

    public class BaseBallNumber {
    
        private static final int DIGIT = 3;
        private final int[] numbers;
    
        public BaseBallNumber(int[] numbers) {
            validationSize(DIGIT, numbers);
            validationDuplicated(numbers);
            this.numbers = numbers;
        }
        ...
    }
    
    • 이런 클래스를 일급 컬렉션이라고 한다.

     

    2️⃣ 불변

    일급 컬렉션은 컬렉션의 불변을 보장한다.

     

    📖 final 키워드

    • Java 에서의 final 은 불변을 만들어주는 것이 아니다 ❌, 재할당만 금지한다

     

    🌟 불변 객체의 중요성

    • 객체의 값이 절대 바뀔일이 없다는 것이 보장되면 코드를 이해하고 수정하는 사이드 이펙트가 최소화된다.

    Java에서는 final로 불변 객체를 만들 수 없기 때문에 일급 컬렉션과 래퍼 클래스등의 방법으로 해결해야 한다.

     

    public class BaseBallNumber {
    
        private static final int DIGIT = 3;
        private final int[] numbers;
    
        public BaseBallNumber(int[] numbers) {
            validateSize(numbers);
            validateWithinRange(numbers);
            this.numbers = numbers;
        }
    
        public void calculate(BiConsumer<Integer,Integer> biConsumer){
            for(int i = 0; i < numbers.length; i++) {
                biConsumer.accept(numbers[i], i);
            }
        }
    }
    

    이렇게 값을 변경할 수 있는 메소드가 없는 컬렉션을 만들게 되면 해당 컬렉션은 불변 컬렉션이 된다.

     

    3️⃣ 상태와 행위를 한 곳에서 관리

    • 값과 로직이 함께 존재

     

    ex) 여러 Pay 방법들이 있을 때, NaverPay 금액의 합이 필요한 경우

    List<Pay> pays = Arrays.asList(
        new Pay(NAVER_PAY, 1000),
        new Pay(KAKAO_PAY, 1500),
        new Pay(NAVER_PAY, 2000),
        new Pay(KAKAO_PAY, 2000));
    
    Long naverPaySum = pays.stream()
            .filter(pay -> pay.getPayType().equals(NAVER_PAY))
            .mapToLong(Pay::getAmount)
            .sum();
    • Pay라는 컬렉션과 계산하는 로직에 관계가 존재한다.

     

    ⚠️ 문제

    • 똑같은 기능을 하는 메소드가 중복되어 생성될 수 있다.
    • 메소드를 누락할 수 있다.
    • 다른 결과가 필요한 경우 더 코드가 흩어질 수 있다.
    public class PayGroups {
        private List<Pay> pays;
    
        public PayGroups(List<Pay> pays) {
            this.pays = pays;
        }
    
        public Long getNaverPaySum() {
            return pays.stream()
                    .filter(pay -> PayType.isNaverPay(pay.getPayType()))
                    .mapToLong(Pay::getAmount)
                    .sum();
        }
    
    		public Long getKakaoPaySum() {
            return getFilteredPays(pay -> PayType.isKakaoPay(pay.getPayType()));
        }
    
        private Long getFilteredPays(Predicate<Pay> predicate) {
            return pays.stream()
                    .filter(predicate)
                    .mapToLong(Pay::getAmount)
                    .sum();
        }
    }
    • PayGroups 라는 일급 컬렉션을 통해 상태와 로직이 한곳에서 관리될 수 있게 되었다.

     

    List<Pay> pays = Arrays.asList(
        new Pay(NAVER_PAY, 1000),
        new Pay(KAKAO_PAY, 1500),
        new Pay(NAVER_PAY, 2000),
        new Pay(KAKAO_PAY, 2000));
    
    PayGroups payGroups = new PayGroups(pays);
    
    Long naverPaySum = payGroups.getNaverPaySum();
    

     

    4️⃣ 이름있는 컬렉션

    컬렉션에 이름을 붙일 수 있다.

    • 일급 컬렉션을 만들면 해당 컬렉션을 기반으로 용어 사용과 검색을 하면 된다.

     

    📖 참고자료


    일급 컬렉션 (First Class Collection)의 소개와 써야할 이유

    '☕️ java' 카테고리의 다른 글

    @ParameterizedTest  (0) 2023.10.25
    👀 Unit Test 네이밍 컨벤션  (0) 2023.10.24
    🧪 JMH (Java Microbenchmark Harness)  (1) 2023.10.23
    🆚 Random 함수 비교  (0) 2023.10.23
    DAO DTO / VO  (0) 2023.03.10

    댓글

Designed by Tistory.