: 사과의 어떤 속성에 기초해서 불리언 값(참 또는 거짓)을 반환하는 함수를 프레디케이트라고 한다. 선택 조건을 결정하는 인터페이스를 정의해보자.
public interface ApplePredicate {
boolean test (Apple apple);
}
Java
복사
: 다음 예제들 처럼 다양한 선택 조건을 대표하는 여러 버전의 ApplePredicate를 정의할 수 있다.
public class AppleGreenColorPredicate {
public boolean test(Apple apple) {
return GREEN.equals(apple.getColor());
}
}
Java
복사
public class AppleHeavyWeightPredicate {
public boolean test(Apple apple) {
return apple.getWeight() > 150;
}
}
Java
복사
: 위 조건에 따라 filter 메서드가 다르게 동작할 것이라고 예상할 수 있다. 이를 전략 디자인 패턴이라고 부른다.
: 전략 디자인 패턴은 각 알고리즘을 캡슐화하는 알고리즘 패밀리를 정의해둔 다음에 런타임에 알고리즘을 선택하는 기법이다.
: 여기서 알고리즘 패밀리는 ApplePredicate, 전략은 AppleGreenColorPredicate, AppleHeavyWeightPredicate이다.
: 그런데 ApplePredicate는 어떻게 다양한 동작을 수행할 수 있을까? filterAples에서 ApplePredicate 객체를 받아 사과의 조건을 검사하도록 메서드를 고쳐야 한다.
: 이렇게 동작을 파라미터화 즉 메서드가 다양한 동작을 받아서 내부적으로 다양한 동작을 수행하게끔 만들 수 있다.
1. 네 번째 시도 : 추상적 조건으로 필터링
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;
}
Java
복사
: 첫 번째 코드에 비해 더 유연한 코드를 얻었으며 동시에 가독성도 좋아졌고, 사용하기도 쉬워졌다.
: 만약 농부가 150g이 넘으면서 빨간 사과를 검색해달라고 부탁하면 알고리즘 패밀리를 구현하는 AppleRedAndHeavyPredicate를 정의해서 사용하기만 하면 끝난다.
: 우리가 전달한 ApplePredicate 객체에 의해 filterApples 메서드의 동작이 결정된다, 즉 우리는 filterApples 메서드의 동작을 파라미터화한 것이다.
: 그림 2-2에서 보여주듯, 위 예제에서 가장 주요 구횬은 test 메서드이다. filterApples 메서드의 새로운 동작을 정의하는 것 또한 test 메서드로 안타깝게도 메서드는 객체만 인수로 받아 test 메서드를 ApplePredicate 객체로 감싸서 전달해야 한다.
: test 메서드를 구현하는 객체를 이용해서 불리언 표현식 등을 전달할 수 있으므로 이는 코드를 전달할 수 있는 것이나 다름없다.
: 2.3절에서는 람다를 이용해서 여러 개의 ApplePredicate 클래스를 정의하지 않고도 다음과 ㄱ
: 살펴본 것처럼, 컬렉션 탐색 로직과 각 항목에 적용할 동작을 분리할 수 있다는 것이 동작 파라미터화의 강점이다. 아래 그림에서 볼 수 있는 것처럼 한 메서드가 다르게 수행하도록 재활용할 수 있다.
한 개의 파라미터, 다양한 동작
: 한 메서드가 다른 메서드에 수행하도록 재활용할 수 있다. 따라서 유연한 API를 만들 때 동작 파라미터화가 중요한 역할을 한다.
: 지금까지 살펴본 것처럼 컬렉션 탐색 로직과 각 항목에 적용할 동작을 분리할 수 있다는 것이 동작 파라미화의 강점이다.