동작 파라미터란?
아직은 어떻게 실행할 것인지 결정하지 않은 코드 블록
이러한 코드 블록의 실행은 나중으로 미뤄진다. 예를 들어 나중에 실행될 메서드의 인수로 코드 블록을 전달할 수 있다. 기존 변수와 컬렉션만 인수로 전달하는 것이 아닌 메서드를 인수로 전달한다고 생각하면 될 것이다.
동작 파라미터 사용의 이점은 변화하는 요구사항에 대응하기 쉽다는 것이다. 이유를 알아보자
사과 농장에서 조건에 따라 사과를 리스트화 해서 분류하고 싶은 요구사항이 있다고 가정하자
1. 메소드로 해결
먼저 색과 관련한 enum이 존재한다.
enum Color { RED, GREEE}
녹색사과를 리스트로 만들면 다음과 같을 수 있다
public static List<Apple> filterGreenApplease(List<Apple> inventory) {
List<Apple> list = new ArrayList<>();
for(Apple apple : inventory){
if(GREEN.eqauls(apple.getColor()) {
result.add(apple);
}
}
return result
}
만약 빨간색 사과만 리스트로 만들고 싶다면 어떻게 해야할까? 바로 위 코드를 복사하여 붙여넣기 하여 새로운 메소드를 만들고 GREEN을 RED로 변형해주는 작업을 할 것이다. 필터를 원하는 색생이 늘어날수록 반복되는 코드가 증가하고 복붙 행위에 현타가 올 것이다.
Dont repeat yourself
2. 색을 파라미터화
public static List<Apple> filterGreenApplease(List<Apple> inventory, Color color) {
List<Apple> list = new ArrayList<>();
for(Apple apple : inventory){
if(apple.getColor.equals(color)) {
result.add(apple);
}
}
return result
}
간단을 추상화를 통해 위에 복붙문제를 해결할 수 있다 색상을 인수로 전달받아 그에 맞는 사과를 리스트화 해서 리턴해준다. 하지만 농부가 색 이외에도 무거운사과, 가벼운사과, 예쁜 사과, 못생긴 사과등 다양한 요구사항이 늘어나면 어떻게 해결해야 될까?
3. 동작 파라미터
동작을 파라미터화 하는 방법이 이러한 반복과 변화하는 요구사항에 대응할 수 있다.
프레디케이트 : 참 또는 거짓을 반환하는 함수
먼저 선택 조건을 결정하는 인터페이스를 정의해보자
public interface ApplePredicate {
boolean test (Apple apple);
}
이를 기반으로 다양한 선택 조건을 대표하는 여러 버전의 ApplePredicate를 정의할 수 있다.
public class AppleHeavyWeightPredicate implements ApplePredicate {
public boolean test(Apple apple) {
return apple.getWeight() > 150;
}
} //150그람 이상의 사과
public class AppleGreenColorPredicate implements ApplePredicate {
public boolean test(Apple apple) {
return GREEN.equals(apple.getColor());
}
} //녹색의 사과
이 전략 디자인 패턴은 각 알고리즘을 캡슐화하는 알고리즘 패밀리를 정의둔 다음에 런타임에 알고리즘을 선택하는 기법이다. 여기서는 ApplePredicate가 알고리즘 패밀리고 AppleHeavyWeightPredicate와 AppleGreenColorPredicate가 알고리즘이 된다. ApplePredicate가 어떻게 다양한 동작을 수행하는지 자세히 알아보자
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;
}
이제는 요구사항에 맞게 ApplePredicate를 만들어서 filterApples 메서드로 전달할 수 있다. 이제 사과의 속성과 관련한 모든 변화에 대응할 수 잇는 유연한 코드를 준비한 것이다!!! 이러한 행위를 filterApples 메서드의 동작을 파라미터화 했다고 말한다. 유연한 API를 만들 때 동작 파라미터를 잘 활용하는 것이 중요하다고 생각한다.
그런데 사실 한편으로는 인터페이스를 만들고 여러 클래스를 구현하는 과정이 번거롭게 느껴지고 마찬가지로 현타가 오는 방법이 아닌가 싶기도 하다.
람다
람다 표현식은 익명 클래스와 비슷하다고 생각하면 된다. 동작 파라미터를 이용할 때 람다만큼 간결하게 구현이 가능한 것은 없다. 이러한 람다를 제대로 이해하고 사용하기 위해서 알아야 할 것이 있다.
람다 표현식은 메서드로 전달할 수 있는 익명 함수를 단순화한 것이라고 할 수 있다. 람다 표현식에는 이름은 없지만, 파라미터 리스트, 바디, 반환 형식, 발생할 수 있는 예외 리스트는 가질 수 있다. 람다의 특징은 다음과 같다.
- 익명 : 보통의 메서드와 달리 이름이 없으므로 익명이라 표현한다.
- 함수 : 람다는 메서드처럼 특정 클래스에 종속되지 않으므로 함수라고 부른다.
- 전달 : 람다 표현식을 메서드 인수로 전달하거나 변수로 저장할 수 있다.
- 간결성 : 익명 클래스처럼 많은 자질구레한 코드를 구현할 필요가 없다.
람다 표현식은 파라미터, 화살표, 바디로 이루어져있다.
() -> {} 와 같은 구조
- 표현식 스타일 (parameters) -> expression
- 블록 스타일 (parameters) -> {statements;}
이러한 람다 표현식은 함수형 인터페이스 문맥에서 사용할 수 있다.
함수형 인터페이스
함수형 인터페이스는 하나의 추상 메소드 만을 지정하는 인터페이스이다. 그렇기 때문에 람다 표현식으로 함수형 인터페이스의 추상 메서드 구현을 직접 전달할 수 있으므로 전체 표현식을 함수형 인터페이스의 인스턴스로 취급가능하다(함수형 인터페이스를 구현한 클래스의 인스턴스).
함수 디스크립터
함수형 인터페이스의 유일한 추상메소드는 시그니처라 불린다. 이는 람다 표현식의 시그니처와도 같다. 람다 표현식의 시그니처를 서술하는 메소드를 함수 디스크립터라고 부른다.
람다 표현식은 변수에 할당하거나 함수형 인터페이스를 인수로 받는 메서드로 전달 할 수 있다.
'자바' 카테고리의 다른 글
스트림을 알아보자!!! (4) | 2024.10.09 |
---|---|
람다를 이용하자! (0) | 2024.10.09 |