동작 파라미터화(Behavior Parameterization)란 메서드의
동작
을파라미터
로 받음으로써 변화에 대응하기 좋은 디자인 패턴이다.
예시로, 서비스에 User가 두 부류(Member, Designer)가 있다고 할 때, 한 서비스 객체에서 userList 중 Member만을 / Designer만을 filtering하는 메서드가 있다고 하자.
이를 구현하는 방법으로는 가장 간단하게 구현해보겠다.
public UserFilterService {
public List<Member> filterMembers(List<User> users) {
return users.stream
.filter(user -> user.getRole().equals("MEMBER"))
.collect(Collectors.toList());
}
public List<Designer> filterDesigners(List<User> users) {
return users.stream
.filter(user -> user.getRole().equals("DESIGNER"))
.collect(Collectors.toList());
}
}
위처럼 구현할 수 있을 것이다. 그런데 이 구현에는 두 가지 문제점을 제기할 수 있다.
그렇다면 동작 파라미터화를 적용해보자.
public CustomUserService {
public List<Member> filter(List<User> users, UserPredicate userPredicate) {
return users.stream
.filter(userPredicate::test)
.collect(Collectors.toList());
}
}
결과부터 보자면 하나의 메서드로 구현이 끝났다. 달라진 점은 UserPredicate
객체를 파라미터로 받아서 stream의 filter에서 userPredicate
의 test
메서드 참조를 통해 구현했다.
(UserPredicate
는 인터페이스로서, 전략패턴을 적용)
public MemberPredicate implements UserPredicate {
@Override
public boolean test(CustomUser user) {
return user.getRole().equals("MEMBER");
}
}
public class DesignerPredicate implements CustomUserPredicate {
@Override
public boolean test(CustomUser user) {
return user.getRole().equals("DESIGNER");
}
}
이렇게 메서드의 동작(Member/Designer filter)을 파라미터를 통해 전달함으로써 추가적인 요구사항에 대응하기 쉬워진다. (추가적인 전략 추가는 필요)
여기서 더 나아갈 수 있는 방법이 있다. Java 8 이후의 함수형 프로그래밍을 적용하는 것이다.
public class Main {
public static void main(String[] args) {
List<CustomUser> customUsers = new ArrayList<>(List.of(
new Member("memberA"),
new Member("memberB"),
new Designer("designerA"),
new Designer("designerB")
)
);
CustomUserService customUserService = new CustomUserService();
// 전략패턴 사용
customUserService.filter(userList, new MemberPredicate())
// 람다식을 통해 전략 구현
customUserService.filter(userList, customUser -> customUser.getRole().equals("MEMBER"));
}
}
동작 파라미터화는 여러 전략이 필요한 경우
+ 반복되는 코드가 예상될 때
사용하면 좋을 것 같다.