티스토리 뷰
728x90
반응형
동작 파라미터화 코드 전달하기
- 동작 파라미터화란 아직은 어떻게 실행할 것인지 결정하지 않은 코드 블럭을 의미합니다. 다른 말로는 행위 매개변수화 코드라고도 합니다.
💡 변하는 부분과 변하지 않는 부분을 분리
- 소프트웨어 주요 설계 원칙 중 하나는 변하는 부분과 변하지 않는 부분을 잘 캐치하여 분리하는 것입니다.
- 동작 파라미터화를 사용하면 변하는 부분과 변하지 않는 부분을 분리함으로써 유동적인 요구사항에 대해 효과적으로 대처할 수 있습니다.
💡 변화하는 요구사항 - 빨간 사과 필터링
- 첫번째 요구사항에서 사과 목록 중 빨간색 사과만 필터링하는 기능을 요구한 경우는 아래처럼 하면 가능하지만 추후 요구사항이 변경되어 녹색 사과만 필터링 해달라는 요청이 들어오게 된다면 또 다른 메서드를 구현해야 합니다.
public enum Color {
RED, GREEN
}
@Getter
@AllArgsConstructor
public class Apple {
private Color color;
private int weight;
}
public class Main {
public static void main(String[] args) {
List<Apple> appleList = List.of(new Apple(Color.RED, 150), new Apple(Color.GREEN, 100));
List<Apple> redAppleList = filterRedApple(appleList);
}
// 빨간 사과 목록을 반환하는 함수
public static List<Apple> filterRedApple(List<Apple> appleList) {
List<Apple> result = new ArrayList<>();
for (Apple apple : appleList) {
if (Color.RED == apple.getColor()) {
result.add(apple);
}
}
return result;
}
// 녹색 사과 목록을 반환하는 함수
public static List<Apple> filterGreenApple(List<Apple> appleList) {
List<Apple> result = new ArrayList<>();
for (Apple apple : appleList) {
if (Color.GREEN == apple.getColor()) {
result.add(apple);
}
}
return result;
}
}
💡 유연한 대처 방법 1 - 색을 매개변수로 받기
- 색을 매개변수로 받게 된다면 코드의 중복을 제거할 수 있고 유연하게 대처할 수 있습니다.
public class Main {
public static void main(String[] args) {
List<Apple> appleList = List.of(new Apple(Color.RED, 150), new Apple(Color.GREEN, 100));
List<Apple> redAppleList = filterAppleByColor(appleList, Color.RED);
}
public static List<Apple> filterAppleByColor(List<Apple> appleList, Color color) {
List<Apple> result = new ArrayList<>();
for (Apple apple : appleList) {
if (color == apple.getColor()) {
result.add(apple);
}
}
return result;
}
}
💡 유연한 대처 방법 2 - 동작 파라미터화
- boolean을 반환하는 Predicate 인터페이스를 만들어 각 구현체마다 동작하는 방법을 다르게하여 유연하게 상황을 대처할 수 있도록 합니다.
- 이러한 방법을 전략 디자인 패턴이라 하는데 전략 디자인 패턴이란 전략을 캡슐화하는 전략 패밀리를 정의한 후 런타임에 상황에 맞는 전략을 취할 수 있는 기법입니다. 여기서는 ApplePredicate가 전략 패밀리에 속하고 Green, Red, Weight Predicate 클래스가 각 상황에 맞는 전략입니다.
- 하지만 다양한 전략을 위해서는 각 상황에 맞는 클래스를 선언해야 하는데 전략이 많을수록 클래스의 수가 증가할 수 있습니다.
public interface ApplePredicate {
boolean test(Apple apple);
}
// 녹색 사과를 필터링하는 Predicate
public class AppleGreenColorPredicate implements ApplePredicate {
@Override
public boolean test(Apple apple) {
return Color.GREEN == apple.getColor();
}
}
// 빨간 사과를 필터링하는 Predicate
public class AppleRedColorPredicate implements ApplePredicate {
@Override
public boolean test(Apple apple) {
return Color.RED == apple.getColor();
}
}
// 무거운 사과를 필터링하는 Predicate
public class AppleHeavyWeightPredicate implements ApplePredicate {
@Override
public boolean test(Apple apple) {
return apple.getWeight() >= 150;
}
}
public class Main {
public static void main(String[] args) {
List<Apple> appleList = List.of(new Apple(Color.RED, 150), new Apple(Color.GREEN, 100));
List<Apple> result = filterByApplePredicate(appleList, new AppleGreenColorPredicate());
}
public static List<Apple> filterByApplePredicate(List<Apple> inventory, ApplePredicate applePredicate) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (applePredicate.test(apple)) {
result.add(apple);
}
}
return result;
}
}
💡 유연한 대처 방법 3 - 익명 클래스 사용
- 익명 클래스를 사용하면 클래스 선언과 인스턴스를 동시에 할 수 있습니다. 하지만 코드가 길어질 수 있습니다. 또한 위에서 언급한 클래스의 수가 많아짐을 방지할 수 있으며 java.util.Objects.Predicate 클래스를 사용하면 됩니다.
public class Main {
public static void main(String[] args) {
List<Apple> appleList = List.of(new Apple(Color.RED, 150), new Apple(Color.GREEN, 100));
List<Apple> result = filterByAnonymousClass(appleList, new Predicate<Apple>() {
@Override
public boolean test(Apple apple) {
return Color.GREEN == apple.getColor();
}
});
}
public static List<Apple> filterByAnonymousClass(List<Apple> appleList, Predicate<Apple> p) {
List<Apple> result = new ArrayList<>();
for (Apple apple : appleList) {
if (p.test(apple)) {
result.add(apple);
}
}
return result;
}
}
💡 유연한 대처 방법 4 - 람다 표현식 사용
- 람다 표현식을 사용하면 코드가 간결해지고 가독성을 높일 수 있습니다.
public class Main {
public static void main(String[] args) {
List<Apple> appleList = List.of(new Apple(Color.RED, 150), new Apple(Color.GREEN, 100));
List<Apple> result = filterByLambda(appleList, (Apple apple) -> Color.RED == apple.getColor());
}
public static List<Apple> filterByLambda(List<Apple> appleList, Predicate<Apple> p) {
List<Apple> result = new ArrayList<>();
for (Apple apple : appleList) {
if (p.test(apple)) {
result.add(apple);
}
}
return result;
}
}
💡 유연한 대처 방법 5 - 리스트 형식으로 추상화
- 마지막으로 다양한 상황에서 필터링된 데이터를 List에 담기위하여 리스트 형식을 추상화할 수 있습니다.
public class Main {
public static void main(String[] args) {
List<Apple> appleList = List.of(new Apple(Color.RED, 150), new Apple(Color.GREEN, 100));
List<String> stringList = List.of("Hello", "Java", "Hi");
List<Integer> integerList = List.of(10, 20, 30, 40, 50);
List<Apple> redAppleList = filter(appleList, (Apple apple) -> Color.RED == apple.getColor());
List<String> stringResultList = filter(stringList, (String s) -> s.startsWith("H"));
List<Integer> integerResultList = filter(integerList, (Integer i) -> i > 30);
redAppleList.forEach(System.out::println); // Apple(color=RED, weight=150)
stringResultList.forEach(System.out::println); // Hello, Hi
integerResultList.forEach(System.out::println); // 40, 50
}
public static <T> List<T> filter(List<T> list, Predicate<T> p) {
List<T> result = new ArrayList<>();
for (T t : list) {
if (p.test(t)) {
result.add(t);
}
}
return result;
}
}
✔️ 정리
- 동작 파라미터화란 메서드 내부적으로 다양한 동작을 수행할 수 있도록 코드를 메서드의 매개변수로 전달하는 것을 말합니다.
- 동작 파라미터화를 사용하면 유동적인 요구사항에 유연하게 대응할 수 있으며, 엔지니어링 비용을 줄일 수 있습니다.
- 변하는 것과 변하지 않는 부분을 파악하여 분리함으로써 유연하게 코드를 작성할 수 있습니다.
728x90
반응형
'스터디 > 모던 자바 인 액션' 카테고리의 다른 글
모던 자바 인 액션 - 9장 리펙터링, 테스팅, 디버깅 (0) | 2022.09.11 |
---|---|
모던 자바 인 액션 - 8장 컬렉션 API 개선 (0) | 2022.09.10 |
모던 자바 인 액션 - 6장 스트림으로 데이터 수집 (0) | 2022.09.10 |
모던 자바 인 액션 - 4장 스트림 소개 (0) | 2022.09.04 |
모던 자바 인 액션 - 3장 람다 표현식 (0) | 2022.09.03 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- java userThread와 DaemonThread
- transactional outbox pattern spring boot
- spring boot redisson sorted set
- 트랜잭셔널 아웃박스 패턴 스프링부트
- space based architecture
- spring boot redisson 분산락 구현
- 람다 표현식
- spring boot 엑셀 다운로드
- 트랜잭셔널 아웃박스 패턴 스프링 부트 예제
- service based architecture
- java ThreadLocal
- spring boot redis 대기열 구현
- spring boot excel download paging
- spring boot poi excel download
- redis 대기열 구현
- 자바 백엔드 개발자 추천 도서
- redis sorted set으로 대기열 구현
- redis sorted set
- 레이어드 아키텍처란
- spring boot redisson destributed lock
- spring boot excel download oom
- 공간 기반 아키텍처
- JDK Dynamic Proxy와 CGLIB의 차이
- microkernel architecture
- polling publisher spring boot
- transactional outbox pattern
- @ControllerAdvice
- pipeline architecture
- pipe and filter architecture
- 서비스 기반 아키텍처
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
글 보관함