세 번째 복습 리뷰는 FP 마지막 스터디 에서 진행했던 새로운 코딩 패턴에 대해 다뤄보려고 합니다.


관련 내용은 아래 포스팅을 참고하세요 :-)



한 번 진행했던 실습 내용에 대해, 기능별로 나눠 포스팅을 진행해보겠습니다.


디폴트 메소드와 Optional 의 경우 관련 포스팅에 내용이 더욱 자세히 나와있습니다.

그렇기 때문에 따로 진행하지는 않겠습니다.



1. 조건부 실행


FP 첫 시간에 배웠던 것 중 한 가지는 함수를 파라미터로 넘길 수 있다는 것이었습니다. 


조건부 실행은 이 메커니즘을 응용한 방법으로 특정 조건이 되었을 때, 어떤 행위를 수행할지 파라미터를 넘기는 것을 의미합니다.


이런 행위를 왜 하는가에 대해 생각해볼 때 다음과 같은 요구사항을 생각해볼 수 있습니다. 


1
2
3
4
5
6
7
8
9
10
/**
  * 특정 행위를 수행하는 함수1.
  * 
  * <pre>
  *     실패했을 때 errorValue 를 이용해서 뭔가를 수행하는 듯.
  * </pre>
  * 
  * @param errorValue
  */
public void func1(String errorValue);
cs


그래서, 이 메소드를 이용하는 곳을 살펴보니 아래와 같았습니다.


1
2
3
4
5
6
7
// 에러 값을 미리 생산.
// errorValueCreator 의 실행시간은 3초.
// 실행시간을 줄일 수는 없어보임.
String errorValue = errorValueCreator();
 
// 결국, 실패하나 성공하나 무조건 errorValueCreator 가 실행되는 상황..
func1(errorValue);
cs


func1 을 실행하기 위해서는 errorValue 를 구해야하는 상황이며, 이는 func1 의 결과가 성공하나 실패하나 무조건 errorValueCreator 를 실행해야함을 의미합니다.


물론 이 방법을 우회할 수 있는 방법은 많으나, 조건부 실행에서는 다음과 같은 방법을 제시합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
  * 특정 행위를 수행하는 함수1.
  * 
  * <pre>
  *     실패했을 때 errorValue 을 생산하는 함수를 인자로 받음.
  * </pre>
  * 
  * @param errorValue
  */
public void func1(Supplier<String> errorValueSupplier);
 
// 동적 파라미터화 이용.
// errorValueCreator 는 내부적으로 실패했을 때만 실행함을 보장.
func1(() -> errorValueCreator());
cs


즉 실패 시 어떤 행위를 할지를 동적 파라미터화 형태로 받음으로, 실패할 때만 errorValueCreator 가 실행되도록 조정할 수 있어 보입니다.


또한, 동적 파라미터화는 다형성을 내포하고 있기 때문에 다양한 errorValueCreator 를 제작하여 파라미터로 넘길 수 있을 것 처럼 보이네요. 


이러한 조건부 실행을 사용하는 예제는 Optional::orElseGet 입니다.

Optional 이 비어있을 때, orElse 에 디폴트 값을 미리 넣는 반면, orElseGet 는 데이터가 비어있을 때 디폴트 값을 생성하는 함수를 실행하도록 합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// orElse 사용.
String name1 = Optional.ofNullable(testVO).
                flatMap(TestVO::toTestVO2Optional).
                flatMap(TestVO.TestVO2::toTestVO3Optional).
                flatMap(TestVO.TestVO3::toTestVO4Optional).
                flatMap(TestVO.TestVO4::toNameOptional).
                orElse(GetDefaultResult());
                
// orElseGet 사용.
String name2 = Optional.ofNullable(testVO).
                flatMap(TestVO::toTestVO2Optional).
                flatMap(TestVO.TestVO2::toTestVO3Optional).
                flatMap(TestVO.TestVO3::toTestVO4Optional).
                flatMap(TestVO.TestVO4::toNameOptional).
                orElseGet(() ->GetDefaultResult());
cs


두 메소드는 미묘하지만, 실행이 다릅니다.



2. 커링 함수 


커링 함수는 함수를 완성시키지 않고, 파라미터를 받아 또 다른 함수를 만드는 기법입니다.

조금 더 쉽게 표현하면, 메소드의 결과가 함수임을 말합니다.


이를테면, 이런거?


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
/**
 * 이름에 타이틀을 붙이는 함수 제작
 *
 * @param title
 * @return
 */
public static UnaryOperator<String> GetTitleFunction(
            String title) {
    return (value) -> String.format("%s %s", title, value);
}
 
// 멋있는 이라는 타이틀을 붙여주는 function..
UnaryOperator<String> awesome_func = GetTitleFunction("Awesome Guy");
// 아름다운 이라는 타이틀을 붙여주는 function..
UnaryOperator<String> beautiful_func = GetTitleFunction("Beautiful Lady");
 
System.out.println( beautiful_func.apply("강현지"));
System.out.println( awesome_func.apply("남두현"));
System.out.println( awesome_func.apply("유덕형"));
System.out.println( awesome_func.apply("유형주"));
 
// CONSOLE LOG
// Beautiful Lady 강현지
// Awesome Guy 남두현
// Awesome Guy 유덕형
// Awesome Guy 유형주
cs


동작을 값으로 가진다는 메커니즘은 이런 아이디어를 또 만들어내는군요. @.@


이를 보고, 쓸모 없어보인다고 생각하면 오산!


커링함수들의 출력이 함수형 인터페이스란 것을 생각한다면,

Stream API 의 파이프라인에 들어갈 함수들에 대한 모듈화를 해줄 수 있음을 의미합니다.


1
2
3
Arrays.asList("강현지""남두현""유덕형""유형주").
    stream().
    map(GetTitleFunction("More Developer style person"));
cs


이렇게 말이죠!!!!!!



이 것으로 FP 스터디에 다루고자 했던 모든 내용은 끝났으며, 처음 4월에 생각했던 OOP & FP 의 목표는 마무리되었습니다.


여기까지 달려온 여러분 모두 수고하셨습니다.



이 곳까지 왔을 때, 


4월의 그 때보다 성장 했기를 바라며,  


 Effective 시리즈로 지금 이 시점보다 진보하길


기도합니다.



Good-Bye [OOP & FP].

반응형
Posted by N'