변화에 대처 가능한 코드를 짜려면
어떻게 해야할까?
컴파일에 결정되는 코드가 아닌
런타임에 결정되는 코드를 짜야 한다.
대표적으로 동작 파라미터화(behavior parameterization)가 있다.
많은 데이터 중 원하는 데이터만 필터링 하려한다. 가볍게 데이터를 파라미터로 받아 조건문으로 필터링하면 된다. 하지만 요구사항은 바뀐다. 필터링 조건은 끊임없이 바뀌고 그럴 때마다 필터링하는 메소드도 복잡해진다.
요구사항이 변함에 따라 필터로직도 수없이 바뀐다. 그렇다면 우리는 어떻게 변화에 대응해야할까? 첫 번째 대응 방법은 '전략 디자인 패턴(Strategy Pattern)'이다. 전략 디자인 패턴은 문제해결을 위한 여러가지 전략이 존재할 때, 전략의 패밀리를 인터페이스로 구현하고 런타임시, 상황에 따라 전략을 선택하는 패턴을 의미한다.
런타임 중, 필요한 로직을 가져와 사용할 뿐, 필터로직패밀리(인터페이스)는 바뀌지 않는다. 그러므로 요구사항이 바뀌면 필터로직만 새로 추가해주면 된다. 코드를 통해 보자.
과수원에 사과가 많이 열렸다. 이 중 상품성있는 사과만 고르는 코드를 만들려고 한다.
public static List<Apple> getFilteredApples(List<Apple> allApples, ApplePredicate applePredicate){
List<Apple> filteredApples = new ArrayList<Apple>();
for(Apple apple : allApples){
if(applePredicate.isProper(apple)){
filteredApples.add(apple);
}
}
return filteredApples;
}
getFilteredApples 메소드의 파라미터인 ApplePredicate 객체는 인터페이스 객체이다. 해당 파라미터에 어떤 구현객체를 던지느냐에 따라 실행결과는 달라진다.
public class ColorPredicate implements ApplePredicate {
@Override
public boolean isProper(Apple apple) {
if(apple.getColor().equals("RED")) return true;
else return false;
}
}
public class WeightPredicate implements ApplePredicate {
@Override
public boolean isProper(Apple apple) {
if(apple.getWeight() > 10) return true;
else return false;
}
}
ColorPredicate는 사과색이 RED인 사과만 선별한다. 반대로 WeightPredicate는 무게가 10g이상인 사과만 선별한다. 이처럼 서로 다른 로직을 갖고 있지만 실제로 필터링하는 코드인 getFilteredApples 메소드의 소스 변화는 없다. 단지, 해당 메소드를 호출할 때 어떤 구현객체를 파라미터로 던질지만 정하면 된다.
public static void main(String[] args) {
// 사과 객체 생성
List<Apple> apples = new ArrayList<Apple>();
apples.add(new Apple("RED",8));
apples.add(new Apple("GREEN",10));
apples.add(new Apple("RED",7)) ;
// 어떤 구현 객체를 파라미터로 넘기느냐에 따라 getFilteredApples 메소드의 로직이 결정된다.
List<Apple> result1 = getFilteredApples(apples,new ColorPredicate());
List<Apple> result2 = getFilteredApples(apples,new WeightPredicate());
}
동작 파라미터의 강점은 이런 것이다. 코드는 크게 세 가지로 분리된다.
자료구조는 데이터가 저장되는 장소이다. 알고리즘은 데이터에 접근하는 방식이다. 그리고 조건은 데이터가 접근되는 조건이다. 이때 동작 파라미터는 자료구조와 알고리즘을 조건과 분리시킬 수 있다는 점이 강점이다.
List 자료구조에 저장된 사과 객체를 for문으로 탐색하는 알고리즘에 필터링 조건이 색깔이 되든 무게가 되든 색깔, 무게 둘 다 되든 자료구조와 알고리즘에는 어떤 영향을 주지 않는다. 이로써 다양한 요구사항 변경에도 소스에는 영향을 주지 않을 수 있다.
이처럼, '전략 디자인 패턴'을 이용하면 요구사항 변화에 강한 동작 파라미터화를 구현할 수 있다. 하지만 문제가 있다. 구현해야하는 요구사항이 많아지면 그만큼 구현해야 할 구현 객체가 늘어난다. 많은 클래스를 생성하는 것도 좋지 못하다. 그러므로 다음 포스팅에서는 구현 클래스를 만들지 않아도 동작파라미터화를 구현할 수 있는 방법을 다루어보겠다.
참고자료
'JAVA > Modern JAVA' 카테고리의 다른 글
[MODERN JAVA] 람다(Lambda)의 활용 - Predicate, Consumer, Function (0) | 2023.03.15 |
---|---|
[MODERN JAVA] 람다(Lambda)의 활용 - 실행 어라운드 패턴 (0) | 2023.03.08 |
[MODERN JAVA] 람다(Lambda)란? (0) | 2023.02.14 |
[MODERN JAVA] 동작 파라미터화 - Comparator,Runnable,Callable (1) | 2023.01.25 |
[MODERN JAVA] 동작 파라미터화 - 익명 클래스(Anonymous Class) (0) | 2023.01.16 |