- 동작 파라미터화란
아직은 어떻게 실행할 것인지 결정하지 않은 코드블럭
을 의미한다.
- 동작 파라미터화를 사용하며 자주 바뀌는 요구사항에 효과적으로 대응할 수 있다.
2.1 변화하는 요구사항에 대응하기
녹색 사과 필터링하기
public static List<Apple> filterGreenApples(List<Apple> inventory) {
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory) {
if (Color.GREEN.equals(apple.getColor())) {
result.add(apple);
}
}
return result;
}
- 여기서 빨간색 사과도 필터링하고 싶으면, 전체 코드를 복사-붙혀넣기 해서 수정해야한다.
- 이렇게 단순 복-붙을 하면 코드 동작을 바꾸고 싶을 때 복-붙을 한 모든 코드를 수정해야한다.
- 따라서, 해당 코드를 추상화 시켜야한다.
색을 파라미터화
public static List<Apple> filterApplesByColor(List<Apple> inventory, Color color) {
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory) {
if (color.equals(apple.getColor())) {
result.add(apple);
}
}
return result;
}
- 여전히 문제는 존재한다. 무게를 기준으로 필터링하려고하면 다시 비슷한 동작을 하는 코드를 만들기 위해 복-붙을 해야한다.
- 뿐만 아니라 무게와 색상 두 기준 모두 적용하여 필터링하게 될 경우 또 새로운 필터링 메서드를 작성해야한다.
- 만약 새로운 코드를 작성하기 싫으면, 색상과 무게로 필터링 하는 두 메서드를 직렬적으로 실행해야하는데, 이는 DRY(Do not Repeat Yourself)를 위반한다.
가능한 모든 속성으로 필터링
- 이딴 코드를 짤 생각을 하는 사람이 세상에 존재할까? 하는 생각이 들어서 작성조차 하지 않았다. 라고 쓰면서 느낀건데, 놀랍게도 프론트 공부할 때 이렇게 짠 적이 있다… 세상에 존재하는 것이었다,,,,,,,,,,,,
2.2 동작 파라미터화
- 객체를 받아서 boolean을 리턴하는 Predicate를 활용하여 동작 자체를 파라미터화할 수 있다.
public interface ApplePredicate {
boolean test(Apple apple);
}
public class AppleGreenColorPredicate implements ApplePredicate {
@Override
public boolean test(Apple apple) {
return Color.GREEN.equals(apple.getColor());
}
}
public class AppleHeavyWeightPredicate implements ApplePredicate {
@Override
public boolean test(Apple apple) {
return apple.getWeight() > 50;
}
}
![](https://blog.kakaocdn.net/dn/uWBlr/btslnd5rXEg/h5whKPfAvu6ubFfkQ7y7a0/img.png)
- 이렇게 전략패턴을 사용해서 추상화하고, 이를 통해 동작을 파라미터화할 수 있다.
추상적 조건으로 필터링
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;
}
- 이제
Apple
에 대해서는 완전히 유연한 코드를 작성할 수 있다. 우리가filterApples
메서드에 전달하는ApplePredicate
객체에 따라 동작이 달라진다.
![](https://blog.kakaocdn.net/dn/YTKTA/btslndqPYuS/vyN3IqxIIYX68X5GVdoMQk/img.png)
- 실제적으로 동작에 영향을 주는 코드는
test
메서드 안에 있는 코드들이다. 나머지들은 동작에 전혀 영향을 주지않는다. 즉, 로직에 관계없는 코드들이 많이 추가 되었다.
- 메서드는 메서드를 파라미터로 받을 수 없고, 객체까지 받을 수 있으므로 어쩔 수 없는 코드들이다.
- 너무 많은 코드가 작성되는 문제는 람다를 통해서 해결할 수 있다.
한 개의 파라미터, 다양한 동작
![](https://blog.kakaocdn.net/dn/PW2eW/btsldOZHKSJ/SYBe0Pz2pmiTgPyCQ2Yzp0/img.png)
- 소제목처럼 하나의 파라미터로 다양한 동작을 할 수있는 것이 동작 파라미터화이다.
- 동작 파라미터화의 최대 강점은, 컬렉션 탐색 로직과 각 항목에 적용할 동작을 분리할 수 있다는 것이다. 이로써 유연한 API를 만들 수 있다.
2.3 복잡한 과정 간소화
- 앞서 얘기한 것 처럼, 유연성을 확보하기 위해서는 간단한 코드를 작성하는데에도 보다 많은 코드가 필요하다. 이렇게 로직과 관련 없는 코드가 많아질 수록 가독성이 떨어지고, 프로그래머의 흥미도 떨어지게된다.
- 이를 익명 클래스를 통해 어느정도 해결할 수 있다. 물론, 익명 클래스또한 람다로 더 줄일 수 있다.
익명 클래스
List<Apple> redApples = filterApples(inventory, new ApplePredicate() {
@Override
public boolean test(Apple apple) {
return apple.getColor().equals(Color.RED);
}
});
- 불필요한 코드가 많이 줄어들긴 했지만, 가독성이 오히려 더 떨어지는 경향이 있다.
- 이는 람다를 통해서 어느정도 해소할 수 있다.
람다 표현식 사용
List<Apple> result = filterApples(inventory, (Apple apple) -> apple.getColor().equals(Color.RED));
- 이 보다 더 줄일 수는 없다.
요약
![](https://blog.kakaocdn.net/dn/wZ7oq/btslpZskupE/tAp1pDLZpVuj575SkwuUs1/img.png)
- 동작 파라미터화에서는 메서드 내부적으로 다양한 동작을 수행할 수 있도록 코드를 메서드 인수로 전달한다.
- 동작 파라미터화를 사용하면 변화하는 요구사항에 더 잘 대응할 수 있는 코드르 구현할 수 있으며 나중에 엔지니어링 비용을 줄일 수 있다.
- 코드 전달 기법을 이용하면 동작을 메서드의 인수로 전달할 수 있다. 하지만 Java8 이전에는 코드를 지저분하게 구현해야 했다. 익명클래스로도 어느 정도 코드를 깔끔하게 만들 수 있지만 Java8에서는 인터페이스를 상속받아 여러 클래스를 구현해야하는 수고를 없앨 수 있는 방법을 제공한다.
- 자바 API의 많은 메서드는 정렬, 스레드, GUI 처리 등을 포함한 다양한 동작으로 파라미터화할 수 있다.
Uploaded by N2T
(22.10.04 15:23)에 작성된 글 입니다.