Chapter 2. 동작 파라미터화 코드 전달하기

doxxx·2022년 4월 25일
0

모던자바인액션

목록 보기
1/14
post-thumbnail

요구사항이 변한다. 따라서 유지보수가 쉬운 코드를 짜는 것이 중요하다.

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

public class FilteringApples {

    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 class FilteringApples {

    public static List<Apple> filterAppleByColor(List<Apple> inventory, Color color) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if (apple.getColor().equals(color)) {
                result.add(apple);
            }
        }
        return result;
    }
}

플래그란: Boolean flag

특정 동작을 수행할지 말지 결정하는 (보통 1비트인) 변수를 플래그라고 부른다.

2.2 동작 파라미터화

참 또는 거짓을 반환하는 predicate를 이용한다.

public class FilteringApples {

    interface ApplePredicate {

        boolean test(Apple a);

    }

    public class AppleHeavyWeightPredicate implements ApplePredicate {

        @Override
        public boolean test(Apple apple) {
            // 무거운 사과만 선택
            return apple.getWeight() > 150;
        }
    }

    public class AppleGreenColorPredicate implements ApplePredicate {

        @Override

        public boolean test(Apple apple) {
            // 녹색 사과만 선택
            return GREEN.equals(apple.getColor());
        }
    }
}

디자인 패턴을 통해 filter 메서드가 다르게 동작한다.
Strategy pattern 위키피디아

import java.util.ArrayList;
import java.util.List;
import java.util.function.IntUnaryOperator;

enum BillingStrategy {

    // 평상시의 정책(전략)
    NORMAL(a -> a),
    // Happy hour시의 정책(전략) (50% 할인)
    HAPPY_HOUR(a -> a / 2),
    ;
    // int 단항 연산자 전략
    private final IntUnaryOperator strategy;

    BillingStrategy(IntUnaryOperator strategy) {
        this.strategy = strategy;
    }

    // 소수점 반올림 방지를 위한 int타입
    int getActPrice(int rawPrice) {
        return this.strategy.applyAsInt(rawPrice);
    }

}

class CustomerBill {

    private final List<Integer> drinks = new ArrayList<>();
    private BillingStrategy strategy;

    public CustomerBill(BillingStrategy strategy) {
        this.strategy = strategy;
    }

    public void add(int price, int quantity) {
        this.drinks.add(this.strategy.getActPrice(price * quantity));
    }

    // 결제
    public void print() {
        int sum = this.drinks.stream().mapToInt(v -> v).sum();
        System.out.println("Total due: " + sum);
        this.drinks.clear();
    }

    // 전략 설정
    public void setStrategy(BillingStrategy strategy) {
        this.strategy = strategy;
    }
}

public class StrategyPattern {

    public static void main(String[] arguments) {
        // 전략 준비, 평상시와 HappyHour를 enum으로 설정
        BillingStrategy normalStrategy = BillingStrategy.NORMAL;
        BillingStrategy happyHourStrategy = BillingStrategy.HAPPY_HOUR;

        CustomerBill firstCustomer = new CustomerBill(normalStrategy);

        // 평상시 계산방법
        firstCustomer.add(100, 1);

        // HappyHour 시작
        firstCustomer.setStrategy(happyHourStrategy);
        firstCustomer.add(100, 2);

        //  HaapyHour 새로운 고객
        CustomerBill secondCustomer = new CustomerBill(happyHourStrategy);
        secondCustomer.add(80, 1);
        // 결제
        firstCustomer.print();

        // HappyHour 종료
        secondCustomer.setStrategy(normalStrategy);
        secondCustomer.add(130, 2);
        secondCustomer.add(250, 1);
        secondCustomer.print();
    }
}

2.2.1 네 번째 시도: 추상적 조건으로 필터링

퀴즈 2-1 유연한 prettyPrintApple 메서드 구현하기

public class Quiz2_1 {

    /**
     * prettyPrintApple 메서드
     * 1. 각각의 사과 무게를 출력
     * 2. 각각의 사과가 무거운지, 가벼운지 출력
     */
    public static void prettyPrintApple(List<Apple> inventory, AppleFormatter formatter) {
        for (Apple apple : inventory) {
            String output = formatter.accept(apple);
            System.out.println(output);
        }
    }

    public interface AppleFormatter {

        String accept(Apple apple);
    }

    public class ApplyFancyFormatter implements AppleFormatter {

        @Override
        public String accept(Apple apple) {
            String characteristic = apple.getWeight() > 150 ? "heavy" : "light";
            return "A" + characteristic + " " + apple.getColor() + "apple";
        }
    }

    public class AppleSimpleFormatter implements AppleFormatter {

        @Override
        public String accept(Apple apple) {
            return "An apple of " + apple.getWeight() + "g";
        }
    }

}

2.3 복잡한 과정 간소화

2.3.3 여섯 번째 시도: 람다 표현식 사용

public class FilteringApples {

    List<Apple> result =
        filterApples(inventory, (Apple apple) -> RED.equals(apple.getColor()));

}

2.3.4 일곱 번째 시도: 리스트 형식으로 추상화

2.4 실전 예제

2.4.1 Comparator로 정렬하기

inventory.sort(
    (Apple a1,Apple a2)->a1.getWeight().compareTo(a2.getWeight()));

2.4.2 Runnable로 코드 블록 실행하기

Thread t = new Thread(() -> System.out.println("Hello world"));

2.4.3 Callable을 결과로 반환하기

Interface ExecutorService

0개의 댓글