JAVA

동작 파라미터화 코드 전달하기(1)

응디 2023. 1. 10. 17:39

앞으로 모던 자바 인 액션 책을 읽고 기억해야 할 내용이나 새로 알게 된 내용을 정리해보려 한다.

아래는 2장 동작 파라미터화 코드 전달하기의 일부 내용이다.

 

우리가 어떤 상황에서 일을 하던 소비자의 요구사항은 항상 바뀐다.

시시각각 변하는 사용자 요구사항에 어떻게 대응해야 할까?

동작 파라미터화를 이용하자!

 

동작 파라미터화란?

: 아직은 어떻게 실행할 것인지 결정하지 않은 코드블록을 의미한다.

 

첫번째 시도

: 기존의 농장 재고목록 애플리케이션에 리스트에서 녹색 사과만 필터링 하는 기능을 추가해 보자!

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;
    }

근데 만약 농부가 빨간 사과도 필터링 하고 싶어진다면? filterRedApples 메소드를 만들어도 좋지만 나중에 농부가 더욱 다양한 색으로 필터링 할때 적절하게 대응 할 수 없다.

 

두번째시도

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

색을 파라미터화 할수 있도록 파라미터를 추가해주면 좀 더 유연하게 대처가 가능하다.

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;
    }

이제 아래처럼 구현한 메소드를 호출 할 수 있다.

List<Apple> greenApples = filterApplesByColor(inventory, GREEN);
List<Apple> redApples = filterApplesByColor(inventory, RED);

만약 색이 아닌 무게로 필터링을 하려면 어떻게 할까?

색과 마찬가지로 filterApplesByWeight 메소드를 만들아서 사용 할 수 있지만 이런 좋은 해결책이 아니다!

중첩되는 코드들이 존재하기 때문이다.( 이는 소프트웨어의 DRY-Don’t Repeat Yourself 원칙을 어기는것!)

 

세번째 시도

: 동작 파라미터화를 이용해보자

우리는 사과의 어떤 속성에 기초해서 boolean 값을 반환하는 방법을 사용해보자!

( 사과가 녹색인가? 150그램 이상인가?)

 

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

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

// 150그램 이상인 사과만 선택
public class AppleHeavyWeightPredicate implements ApplePradicate {
    public boolean test(Apple apple) {
        return apple.getWeight() > 150;
    }
}

ApplePredicate는 사과 선택 전략을 캡슐화 했다.

( 조건에 따라 filter 메소드가 다르게 동작함 → 전략 디자인 패턴 이라고 함)

전략 디자인 패턴은 각 알고리즘( 전략 )을 캡슐화 하고 알고리즘 패밀리를 정의해 둔 다음 런타임에 알고리즘을 선택하는 기법이다.

 

ApplePredicate → 알고리즘 패밀리

AppleGreenColorPredicate, AppleHeavyWeightPredicate → 알고리즘

 

네번째시도

: 추상적 조건으로 필터링

ApplePredicate 객체를 받아 사과의 조건을 검사하도록 메소드를 수정해보자.

// 동작 파라미터화
    public static List<Apple> filterApples(List<Apple> inventory, ApplePradicate ap){
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if (ap.test(apple)) {   // 이렇게 하면 두가지 다 검사 가능 (무게와 색 ) -> 두가지 클래스에서 test를 구현 했기 때문
                result.add(apple);
            }
        }
        return result;
    }

우리는 ApplePredicate 를 이용하여 소비자가 요구하는 다양한 사항들을 적절하게 구현하는 클래스만 만들어주면 된다.

ApplePredicate 객체를 filterApples 메서드에 전달하여 메서드의 동작을 결정 할 수 있다.

→ 즉, filterApples 메서드의 동작을 파라미터화 한것 ! (아래 예제 참고)

public class AppleRedHeavyWeightPredicate implements ApplePradicate {

    @Override
    public boolean test(Apple apple) {
        return RED.equals(apple.getColor()) &&
                apple.getWeight() > 150;
    }
}

// 동작 파라미터한 필터(AppleRedHeavyWeightPredicate)를 전달한다.
List<Apple> redAndHeavyApples = 
						filterApples(inventory, new AppleRedHeavyWeightPredicate());

이처럼 동작 파라미터화는 한개의 파라미터로 여러가지의 동작을 할 수 있게 해준다.

(filterApples 메서드의 파라미터는 ApplePredicate 객체 하나지만 동작 파라미터화로 여러가지 동작이 가능하다.)

따라서 유연한 API를 만들때 동작 파라미터 화가 중요한 역할을 한다.

'JAVA' 카테고리의 다른 글

Model Mapper 사용법  (0) 2023.01.26
동작 파라미터화 코드 전달하기(2)  (0) 2023.01.19
int 와 long  (0) 2022.12.27
BDD 스타일 Mockito API  (0) 2022.12.26
Mock 객체 확인  (0) 2022.12.15