모던 자바 인 액션 2장: 동작 파라미터화 코드 전달하기

dev_314·2023년 1월 8일
0

모던 자바 인 액션

목록 보기
2/6

모던 자바 인 액션 2장을 학습하고 정리한 내용입니다.

2장. 동작 파라미터화 코드 전달하기

동작 파라미터화는 아직은 어떻게 실행할 것인지 결정하지 않은 코드 블록을 의미한다.

이 코드 블록은 나중에 프로그램에서 호출한다.

예를 들어 나중에 실행될 메서드의 인수로 코드 블록이 전달될 수 있다. 코드 블록에 따라 메서드의 동작이 파라미터화된다.

기존에는 goAndBuy() 메서드를 통해, '나가서 사는' 행동만 처리할 수 있었는데,
'동작 파리미터화'를 통해 동작을 파라미터처럼 사용할 수 있다.

go(Buy) // goAndBuy -> go
go(Rent) // goAndRent -> go
go(check) // goAndCheck -> go

동작 파라미터화를 이용하면 빈번한 요구사항 변경에 효과적으로 대응할 수 있다.

2.1 변화하는 요구사항에 대응하기

  1. 초록색 사과만 필터링 하고 싶음
  2. 다른 색깔로 필터링 하고 싶음 -> 색깔을 메서드의 파라미터로 사용
  3. 무게를 기준으로 필터링하고 싶음 -> 무게를 메서드의 파라미터로 사용
  4. 색깔 + 무게를 기준으로 필터링하고 싶음 -> 색깔, 무게를 파라미터로 사용
  5. 다른 기준이 필터링 조건에 추가됨 -> 메서드 파라미터가 계속 늘어남 -> 가독성 저하, DRY(don't repeat yourself) 원칙 준수 X

2.2 동작 파리미터화

Strategy pattern 적용해서 가독성, 유연성 확보

public interface ApplePredict {
	boolean test (Apple apple);
}

public class AppleWeightPredict implements ApplePredict {
	@Override
    public boolean test(Apple apple) {
    	return apple.getWeight() > 150;
    }
}

public class AppleColorPredict implements ApplePredict {
	@Override
    public boolean test(Apple apple) {
    	return apple.getColor() == Color.GREEN;
    }
}

// 사용
public List<Apple> filterApples(List<Apple> apples, ApplePredict p) {
	List<Apple> filteredApples = new ArrayList<>();
    for (Apple apple : apples) {
    	if(p.test(apple)) {
        	filteredApples.add(apple);
        }
    }
    return filteredApples;
}

파라미터로 전달한 ApplePredict 객체에 따라 filterApples 메서드의 작동 방식이 달라졌다.

2.3 복잡한 과정 간소화

Strategy Pattern의 단점

  1. 인터페이스를 구현하는 클래스를 조건마다 만들어야 함 -> 조건이 늘어나면?
  2. 로직과 관련 없는 코드(클래스, 메서드 선언부 등)가 존재 -> 개선 필요

2.3.1 Annonymous Class로 개선

List<Apple> redApples = filterApple(apples, new ApplePredict() {
	@Override
    public boolean test(Apple apple) {
    	return apple.getColor() == Color.RED;
    }
}) 

익명 클래스를 통해 따로 클래스를 정의할 필요는 없어졌지만, 여전히 불필요한 코드는 남아있다.

2.3.3 람다 표현식으로 개선

자바 8의 람다 표현식을 통해 다음처럼 간단하게 표현할 수 있다.

List<Apple> result = filterApples(inventory, (Apple apple) -> app.getColor == Color.RED));

유연성 측면에서

값 파라미터화 < 클래스, 익명 클래스, 람다

코드 간결성 측면에서

값 파라미터화 < 클래스 < 익명 클래스 < 람다

2.3.4 리스트 형식으로 개선

제네릭을 적용해서 확장성을 향상시켜보자

public interface Predict<T> {
	boolean test(T t);
}

public List<T> filter(List<T> list, Predict<T> p) {
	List<T> filtered = new ArrayList<>();
    for (T t : list) {
    	if (p.test(t)) {
        	filtered.add(t);
        }
    }
    return filtered;
}

List<Apple> redApples = filter(apples, (Apple apple) -> apple.getColor() == Color.RED);
List<Integer> oddNumbers = filter(numbers, (Integer number) -> number % 2 == 1);

동작 파라미터화는 변화하는 요구사항에 쉽게 적응하는 유용한 패턴임을 알 수 있다.

profile
블로그 이전했습니다 https://dev314.tistory.com/

0개의 댓글