동작 파라미터화. 아직은 어떻게 실행할 것인지 결정하지 않은 코드 블록. 이 코드 블록은 나중에 프로그램에서 호출함.
자주 바뀌는 요구사항에 효과적으로 유연하게 대응할 수 있음.
사과를 filter함.
public interface ApplePredicate {
boolean test(Apple apple);
}
ApplePredicate는 사과 선택 전략을 캡슐화 한다.
public class AppleHaveyWeightPredicate implements ApplePredicate {
@Override
public boolean execute(Apple apple) {
return apple.getWeight() > 150;
}
}
public class AppleGreenColorPredicate implements ApplePredicate {
@Override
public boolean execute(Apple apple) {
return GREEN.equals(apple.getColor());
}
}
이는 전략 디자인 패턴으로 볼 수 있다.
각 알고리즘(=전략)을 캡슐화 하는 알고리즘 패밀리를 정의해둔 다음에, 런타임에 알고리즘을 선택하는 기법이다.
public static List<Apple> filterAppes(List<Apple> inventory, ApplePredicate p) {
List<Apple> result = new ArrayList<>();
if(p.execute(apple)) {
result.add(apple);
}
return result;
}
이렇게 동작 파라미터화, 즉 메서드가 다양한 동작(또는 전략)을 받아서 내부적으로 다양한 동작을 수행할 수 있다.
위 예제에서 보이는 바와 같이, 새로운 동작은 전달하려면 인터페이스를 만들고, 이를 구현하는 여러 클래스를 정의한 뒤, 인스턴스화해야 한다. 이는 상당히 번거롭다.
말 그대로 이름이 없는 클래스이다. 클래스 선언과 인스턴스화를 동시에 할 수 있다.
List<Apple> redApples = filterApples(inventory, new ApplePredicate() {
public boolean execute(Apple apple) {
return RED.equals(apple.getColor());
}
})
익명 클래스도 여전히 버겁다. 람다를 통해 간단하게 구현할 수 있다.
List<Apple> result = filterApples(inventory, (Apple apple) -> RED.equals(apple.getColor()));
동작 파라미터화와 값 파라미터화
Generic을 이용하여 type에도 유연하게 만들면 좋다. (= 형식 파라미터)
자바 API의 많은 메서드를 다양한 동작으로 파라미터화 할 수 있다.
자바 8의 List에는 sort 메서드가 포함되어 있다. 다음과 같은 인터페이스를 갖는 java.util.Comparator
객체를 이용해서 sort의 동작을 파라미터화 할 수 있다.
// java.util.Comparator
public interface Comparator<T> {
int compare(T o1, T o2);
}
-> 사과 무게로 정렬하기
inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
자바 스레드를 이용하면 병렬로 코드 블록을 실행할 수 있다. 어떤 코드를 실행할 것인지를 스레드에게 알려주면 된다. 이때 Runnable
인터페이스를 이용해 실행할 코드 블록을 지정할 수 있다.
// java.lang.Runnable
public interface Runnable {
void run();
}
-> 구현하기
Thread t = new Thread(() -> System.out.println("hello world!"));
이외에도
Callable
,GUI event 처리
등을 예로 들 수 있다.