1. 소개
Java 8부터 우리는 Java에서 하나 또는 두 개의 매개변수 함수를 정의할 수 있으므로 매개변수로 전달하여 해당 동작을 다른 함수에 주입할 수 있습니다. 그러나 매개변수가 더 많은 함수의 경우 Vavr 과 같은 외부 라이브러리에 의존합니다 .
또 다른 옵션은 커링을 사용하는 것입니다 . 커링과 기능적 인터페이스를 결합하여 사용자가 모든 입력을 제공하도록 하는 읽기 쉬운 빌더를 정의할 수도 있습니다.
이 예제에서는 커링을 정의하고 사용법을 제시합니다 .
2. 간단한 예
여러 매개변수가 있는 문자의 구체적인 예를 살펴보겠습니다.
간소화된 첫 번째 버전에는 본문과 인사말만 필요합니다.
class Letter {
private String salutation;
private String body;
Letter(String salutation, String body){
this.salutation = salutation;
this.body = body;
}
}
2.1. 방법에 의한 생성
이러한 객체는 다음 메서드를 사용하여 쉽게 만들 수 있습니다.
Letter createLetter(String salutation, String body){
return new Letter(salutation, body);
}
2.2. BiFunction 으로 생성
위의 방법은 잘 작동하지만 함수형 스타일로 작성된 항목에 이 동작을 제공해야 할 수도 있습니다. Java 8부터 이러한 목적으로 BiFunction을 사용할 수 있습니다.
BiFunction<String, String, Letter> SIMPLE_LETTER_CREATOR
= (salutation, body) -> new Letter(salutation, body);
2.3. 일련의 함수로 생성
우리는 또한 이것을 각각 하나의 매개변수를 가진 일련의 함수로 다시 말할 수 있습니다:
Function<String, Function<String, Letter>> SIMPLE_CURRIED_LETTER_CREATOR
= salutation -> body -> new Letter(salutation, body);
인사말이 함수에 매핑되는 것을 볼 수 있습니다 . 결과 함수는 새 Letter 개체에 매핑됩니다. 반환 유형이 BiFunction 에서 어떻게 변경되었는지 확인하십시오 . 우리는 Function 클래스 만 사용하고 있습니다 . 이러한 일련의 함수로의 변환을 커링(currying)이라고 합니다.
3. 고급 예제
커링의 이점을 보여주기 위해 Letter 클래스 생성자를 더 많은 매개변수로 확장해 보겠습니다.
class Letter {
private String returningAddress;
private String insideAddress;
private LocalDate dateOfLetter;
private String salutation;
private String body;
private String closing;
Letter(String returningAddress, String insideAddress, LocalDate dateOfLetter,
String salutation, String body, String closing) {
this.returningAddress = returningAddress;
this.insideAddress = insideAddress;
this.dateOfLetter = dateOfLetter;
this.salutation = salutation;
this.body = body;
this.closing = closing;
}
}
3.1. 방법에 의한 생성
이전과 마찬가지로 메서드를 사용하여 개체를 만들 수 있습니다.
Letter createLetter(String returnAddress, String insideAddress, LocalDate dateOfLetter,
String salutation, String body, String closing) {
return new Letter(returnAddress, insideAddress, dateOfLetter, salutation, body, closing);
}
3.2. 랜덤의 인수에 대한 함수
Arity는 함수가 취하는 매개변수의 수를 측정한 것입니다. Java는 nullary ( Supplier ), unary ( Function ) 및 binary( BiFunction ) 에 대한 기존 기능 인터페이스를 제공 하지만 그게 전부입니다. 새로운 기능 인터페이스를 정의하지 않고는 6개의 입력 매개변수가 있는 함수를 제공할 수 없습니다.
Currying은 우리의 탈출구입니다. 랜덤의 인수를 단일 함수 시퀀스로 변환합니다 . 예를 들어 다음을 얻습니다.
Function<String, Function<String, Function<LocalDate, Function<String,
Function<String, Function<String, Letter>>>>>> LETTER_CREATOR =
returnAddress
-> closing
-> dateOfLetter
-> insideAddress
-> salutation
-> body
-> new Letter(returnAddress, insideAddress, dateOfLetter, salutation, body, closing);
3.3. 자세한 유형
분명히 위의 유형은 가독성이 좋지 않습니다. 이 양식에서는 '적용'을 여섯 번 사용하여 편지를 만듭니다 .
LETTER_CREATOR
.apply(RETURNING_ADDRESS)
.apply(CLOSING)
.apply(DATE_OF_LETTER)
.apply(INSIDE_ADDRESS)
.apply(SALUTATION)
.apply(BODY);
3.4. 사전 채우기 값
이 함수 체인을 사용하여 첫 번째 값을 미리 채우고 문자 개체의 후속 완성을 위해 함수를 반환하는 도우미를 만들 수 있습니다.
Function<String, Function<LocalDate, Function<String, Function<String, Function<String, Letter>>>>>
LETTER_CREATOR_PREFILLED = returningAddress -> LETTER_CREATOR.apply(returningAddress).apply(CLOSING);
이것이 유용하려면 원래 함수에서 매개변수의 순서를 신중하게 선택하여 덜 구체적인 것이 첫 번째 매개변수가 되도록 해야 합니다.
4. 빌더 패턴
친숙하지 않은 유형 정의와 표준 적용 방법 의 반복 사용을 극복하기 위해 올바른 입력 순서에 대한 단서가 없음을 의미하며 빌더 패턴을 사용할 수 있습니다 .
AddReturnAddress builder(){
return returnAddress
-> closing
-> dateOfLetter
-> insideAddress
-> salutation
-> body
-> new Letter(returnAddress, insideAddress, dateOfLetter, salutation, body, closing);
}
일련의 기능 대신 일련의 기능 인터페이스를 사용합니다 . 위 정의의 반환 유형은 AddReturnAddress 입니다 . 다음에서는 중간 인터페이스만 정의하면 됩니다.
interface AddReturnAddress {
Letter.AddClosing withReturnAddress(String returnAddress);
}
interface AddClosing {
Letter.AddDateOfLetter withClosing(String closing);
}
interface AddDateOfLetter {
Letter.AddInsideAddress withDateOfLetter(LocalDate dateOfLetter);
}
interface AddInsideAddress {
Letter.AddSalutation withInsideAddress(String insideAddress);
}
interface AddSalutation {
Letter.AddBody withSalutation(String salutation);
}
interface AddBody {
Letter withBody(String body);
}
따라서 이것을 사용하여 편지를 만드는 것은 매우 자명합니다.
Letter.builder()
.withReturnAddress(RETURNING_ADDRESS)
.withClosing(CLOSING)
.withDateOfLetter(DATE_OF_LETTER)
.withInsideAddress(INSIDE_ADDRESS)
.withSalutation(SALUTATION)
.withBody(BODY));
이전과 마찬가지로 문자 객체를 미리 채울 수 있습니다.
AddDateOfLetter prefilledLetter = Letter.builder().
withReturnAddress(RETURNING_ADDRESS).withClosing(CLOSING);
인터페이스는 채우기 순서를 보장 합니다 . 따라서 미리 채울 수 없습니다 .
5. 결론
커링을 적용하는 방법을 살펴보았으므로 표준 Java 기능 인터페이스에서 지원하는 제한된 수의 매개변수에 제약을 받지 않습니다. 또한 처음 몇 개의 매개변수를 쉽게 미리 채울 수 있습니다. 또한 이를 사용하여 읽기 쉬운 빌더를 만드는 방법을 배웠습니다.
항상 그렇듯이 전체 코드 샘플은 GitHub에서 사용할 수 있습니다 .