동작 파라미터화 코드 전달하기 (1)에서 파라미터를 추가하는 방법이 아닌 변화하는 요구사항에 좀 더 유연하게 대응 할 수 있는 방법이 절실함을 확인 했다. 사과의 어떤 속성에 기초해서 불리언값을 반환 하는 방법이 있다. 참 또는 거짓을 반환하는 함수를 프리디케이트 라고 한다. 선택 조건을 결정하는 인터페이스를 정의해보자!
public interface ApplePredicate {
boolean test (Apple apple);
}선택 조건을 대표하는 여러 버전의 ApplePredicate를 정의 해보자!
Public class AppleHeavyWeightPredicate implements ApplePredicate {
public boolean test(Apple apple){
return apple.getWeight() > 150;
}
}
public class AppleGreenColorPredicate implements ApplePredicate {
public boolean test(Apple appplKakaoTalk_Photo_2022-05-26-22-25-03e){
return GREEN.equals(apple.getColor());
}
} 
ApplePredicate는 사과 선택 전략을 캡슐화 하였다 -> 이를 전략 디자인 패턴 (Stragegy Design Pattern이라고 한다.
즉, 전략 디자인 패턴은 각 알고리즘(전략이라 불리는)을 캡슐화 하여 알고리즘 패밀리를 정의해둔 다음에 런타임에 알고리즘을 선택하는 기법이다.
(ApplePredicate가 알고리즘 패밀리이고 AppleHeavyWeightPredicate와 AppleGreenColorPredicate가 전략이다)
어떻게 ApplePredicate는 다양한 동작을 수행 할 수 있을까? filterApples에서 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;
}
List<Apple> greenCololrApples = filterApple(inventory,new AppleGreenColorPredicate()); // 초록색 사과만 필터링 하도록 test메서드가 정의된 AppelPreicate 객체를 전달
우리가 전달한 ApplePredicate 객체에 의해 filterApples 메서드의 동작이 결정된다 즉, 우리는 앞으로 변덕쟁이 농부의 요구사항에 따라 사과를 필터링 할 수 있는 ApplePredicate를 적절하게 구현하는 클래스만 만들면 된당 !
filterApples 메서드의 새로운 동작을 정의하는 것은 test 메서드 이다. 안타깝게도 메서드는 객체만 인수로 받기 때문에 test메서드를 ApplePredicate 객체로 감싸서 전달해야 한다. test메서드를 구현하는 객체를 이용해서 불리언 표현식 등을 전달할 수 있기 때문에 이는 코드를 전달 할 수 있는거나 다름이 없다. 이후에는 ApplePreicate클래스를 정의하지 않고 람다식을 이용해서 더 깔끔하게 코드 구현 을 하는 법을 알아보자!!
한 개의 파라미터, 다양한 동작
한 메서드가 다른 동작을 수행 할 수록 재활용 할 수 있다. 따라서 유연한 API를 만들 때 동작 파라미터화가 중요한 역할을 한다.
Quiz 1. 유연한 prettyPrintApple 구현하기 🍎
사과 리스트를 인수로 받아 다양한 방법으로 문자열을 생성(커스터마이즈 된 다양한 toString메서드 같이) 할 수 있도록 파라미터화된 prettyPrintApple메서드를 구현하시오. 예를들어 prettyPrintApple 메서드가 각각 사과 무게를 출력하도록 지시할 수 있다. 혹은 각각의 사과가 무거운지 가벼운지 출력하도록 지시할 수 있다. prettyPrintApple 메서드는 지금까지 살펴 본 필터링 예제와 비슷한 방법으로 구현할 수 있다.
public interface AppleFommater {
String print(Apple apple);
}
public class PrintAppleWeight implements AppleFommater {
String print(Apple apple){
return "사과의 무게는" + apple.getWeight()+"g 입니다";
}
}
public class PrintAppleWeightStatus implements AppleFommater {
String print(Apple apple){
String result = apple.getWeight() > 150 ? "무겁" : "가볍";
return "이 사과는 "+ result+ "습니다.
}
}
public void prettyPrintApple(List<Apple> apples, AppleFommater af){
for(Apple a : apples){
system.out.println(af.print(a));
}
}
마무리
지금까지 동작을 추상화해서 변화하는 요구사항에 대응할 수 있는 코드를 구현하는 방법을 살펴봤다. 하지만 여러 클래스를 구현해서 인스턴스화하는 과정은 좀 많이 귀찮다. 어떻게 개선이 가능한지 다음시간에 알아보자~
'Dev > Java' 카테고리의 다른 글
| 쓰레드 동기화 (Thread Synchronization) (0) | 2022.08.06 |
|---|---|
| Optional의 안티 패턴을 피하는 방법 😎 (0) | 2022.07.22 |
| Optional 제대로 알고 쓰는건가요? (0) | 2022.07.10 |
| 동작 파라미터화 코드 전달하기 (마지막) (0) | 2022.05.29 |
| 동작 파라미터화 코드 전달하기 (1) (0) | 2022.05.20 |