본문 바로가기

[모던 자바 인 액션] 2장 동작 파라미터화 코드 전달하기

동작 파라미터화(behavior parameterization)

- 자주 바뀌는 요구사항에 효과적으로 대응할 수 있다. 

- 동작 파라미터화란 아직은 어떻게 실행할 것인지 결정하지 않은 코드 블록을 의미한다. 

- 코드의 실행은 나중으로 미뤄진다. 

 

2.1 변화하는 요구사항에 대응하기

- 거의 비슷한 코드가 반복 존재한다면 그 코드를 추상화 한다. 

 

2.2 동작 파라미터화 

- 참 또는 거짓을 반환하는 함수를 프레디케이트라고 한다. 선택 조건을 결정하는 인터페이스를 정의.

- 동작 파라미터화, 즉 메서드가 다양한 동작(또는 전략)을 받아서 내부적으로 다양한 동작을 수행할 수 있다. 

 

2.3  복잡한 과정 간소화 

- 자바는 클래스의 선언과 인스턴스화를 동시에 수행할 수 있도록 익명 클래스라는 기법을 제공.

  // 첫 번째 시도 : 녹색 사과 필터링
    public static List<Apple> filterGreenApples(List<Apple> inventory) {
        List<Apple> result = new ArrayList<>(); // 사과 누적 리스트
        for (Apple apple : inventory) {
            if (GREEN.equals(apple.getColor())) {
                result.add(apple);
            }
        }
        return result;
    }

    // 두 번째 시도 : 색을 파라미터화
    public static List<Apple> filterApplesByColor(List<Apple> inventory, Color color) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if (apple.getColor().equals(color)) {
                result.add(apple);
            }
        }
        return result;
    }

    public static List<Apple> filterApplesByWeight(List<Apple> inventory, int weight) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if (apple.getWeight() > weight) {
                result.add(apple);
            }
        }
        return result;
    }

    // 세 번째 시도 : 가능한 모든 속성으로 필터링
    public static List<Apple> filterApples(List<Apple> inventory, Color color, int weight, boolean flag) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if ((flag && apple.getColor().equals(color)) || (!flag && apple.getWeight() > weight)) {
                result.add(apple);
            }
        }
        return result;
    }

    // 네 번째 시도 : 추상적 조건으로 필터링
    public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if (p.test(apple)) {
                result.add(apple);
            }
        }
        return result;
    }

    // 다섯 번째 시도 : 익명 클래스 사용
        List<Apple> redApples1 = service.filterApples(inventory, new ApplePredicate() {
            @Override
            public boolean test(Apple apple) {
                return Color.RED.equals(apple.getColor());
            }
        });

        // 여섯 번째 시도 : 람다 표현식 사용
        List<Apple> redApples2 = service.filterApples(inventory, (Apple apple) -> Color.RED.equals(apple.getColor()));

        // 일곱 번째 시도 : 리스트 형식으로 추상화
        List<Apple> greenApples2 = service.filter(inventory, (Apple apple) -> Color.GREEN.equals(apple.getColor()));
        List<Integer> numbers = new ArrayList<>();
        List<Integer> evenNumbers = service.filter(numbers, (Integer i) -> i % 2 == 0);

    // 일곱 번째 시도 : 리스트 형식으로 추상화
    public static <T> List<T> filter(List<T> list, Predicate<T> p) {
        List<T> result = new ArrayList<>();
        for (T t : list) {
            if (p.test(t)) {
                result.add(t);
            }
        }
        return result;
    }