티스토리 뷰

● 도입

출처 - The Red: 25개 백엔드 개발 필수 현업 예제를 통해 마스터하는 JAVA STREAM(fastcampus)

- java의 함수들도 서로 합성할 수 있다.

- 위 그림은 f(x) 함수를 먼저 실행한 후 g(x) 함수를 실행하는 것이다.

java.util.function.Function
<V> Function<V, R> compose(Function<? super V, ? extends T> before)
<V> Function<T, V> andThen(Function<? super R, ? extends V> after)

compose
- parameter로 들어온 함수를 먼저 실행한 후 자기 자신을 실행하도록 합성
- 위 사진이 compose의 예이다.

andThen
- 자신을 먼저 실행한 후 parameter로 들어온 함수를 실행하도록 합성

 

 

● 실습

1. 두 함수를 합성해보자

package com.fastcampus.functionalprogramming.chapter9;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

import com.fastcampus.functionalprogramming.chapter9.model.Order;
import com.fastcampus.functionalprogramming.chapter9.model.OrderLine;
import com.fastcampus.functionalprogramming.chapter9.priceprocessor.OrderLineAggregationPriceProcessor;
import com.fastcampus.functionalprogramming.chapter9.priceprocessor.TaxPriceProcessor;

public class Chapter9Section3 {
	public static void main(String[] args) {
		// 아래의 두 함수를 (x * 2 + 10)으로 합성해보자
		Function<Integer, Integer> multiplyByTwo = x -> x * 2;
		Function<Integer, Integer> addTen = x -> x + 10;
		
		Function<Integer, Integer> composedFunction = multiplyByTwo.andThen(addTen);
		System.out.println(composedFunction.apply(3));
		/*
		 * 순서
		 * (1). multiplyByTwo : 3 * 2
		 * (2). addTen		  : 6 + 10
		 */
	}
}

 

 

2. 각자의 기능을 갖고 있는 함수들을 합성해서 새로운 함수를 만들어보자

- Order를 받아 해당 Order의 가격을 process 해주는 함수를 만들어보자

package com.fastcampus.functionalprogramming.chapter9.model;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

public class Order {
	private long id;
	private LocalDateTime createdAt;
	private long createdByUserId;
	private OrderStatus status;
	private BigDecimal amount;
	private List<OrderLine> orderLines;

	public enum OrderStatus {
		CREATED,
		IN_PROGRESS,
		ERROR,
		PROCESSED
	}

	public long getId() {
		return id;
	}

	public Order setId(long id) {
		this.id = id;
		return this;
	}

	public LocalDateTime getCreatedAt() {
		return createdAt;
	}

	public Order setCreatedAt(LocalDateTime createdAt) {
		this.createdAt = createdAt;
		return this;
	}

	public long getCreatedByUserId() {
		return createdByUserId;
	}

	public Order setCreatedByUserId(long createdByUserId) {
		this.createdByUserId = createdByUserId;
		return this;
	}

	public OrderStatus getStatus() {
		return status;
	}

	public Order setStatus(OrderStatus status) {
		this.status = status;
		return this;
	}

	public BigDecimal getAmount() {
		return amount;
	}

	public Order setAmount(BigDecimal amount) {
		this.amount = amount;
		return this;
	}

	public List<OrderLine> getOrderLines() {
		return orderLines;
	}

	public Order setOrderLines(List<OrderLine> orderLines) {
		this.orderLines = orderLines;
		return this;
	}
}
package com.fastcampus.functionalprogramming.chapter9.model;

import java.math.BigDecimal;

public class OrderLine {
	private long id;
	private OrderLineType type;
	private long productId;
	private int quantity;
	private BigDecimal amount;
	
	public enum OrderLineType {
		PURCHASE,
		DISCOUNT
	}

	public long getId() {
		return id;
	}

	public OrderLine setId(long id) {
		this.id = id;
		return this;
	}
	
	public OrderLineType getType() {
		return type;
	}
	
	public OrderLine setType(OrderLineType type) {
		this.type = type;
		return this;
	}

	public long getProductId() {
		return productId;
	}

	public OrderLine setProductId(long productId) {
		this.productId = productId;
		return this;
	}
	
	public int getQuantity() {
		return quantity;
	}
	
	public OrderLine setQuantity(int quantity) {
		this.quantity = quantity;
		return this;
	}

	public BigDecimal getAmount() {
		return amount;
	}

	public OrderLine setAmount(BigDecimal amount) {
		this.amount = amount;
		return this;
	}
}
package com.fastcampus.functionalprogramming.chapter9.priceprocessor;

import java.math.BigDecimal;
import java.util.function.Function;

import com.fastcampus.functionalprogramming.chapter9.model.Order;
import com.fastcampus.functionalprogramming.chapter9.model.OrderLine;

// 전체 가격을 합한 후 해당 가격을 order에 set 해주는 Processor
public class OrderLineAggregationPriceProcessor implements Function<Order, Order> {

	@Override
	public Order apply(Order order) {
		return order.setAmount(order.getOrderLines().stream()
				.map(OrderLine::getAmount)
				.reduce(BigDecimal.ZERO, BigDecimal::add));
	}
}
package com.fastcampus.functionalprogramming.chapter9.priceprocessor;

import java.math.BigDecimal;
import java.util.function.Function;

import com.fastcampus.functionalprogramming.chapter9.model.Order;

// 현재 가격에 세율을 적용하는 Processor
public class TaxPriceProcessor implements Function<Order, Order>{
	private final BigDecimal taxRate;
	
	public TaxPriceProcessor(BigDecimal taxRate) {
		this.taxRate = taxRate;
	}
	
	@Override
	public Order apply(Order order) {
		return order.setAmount(order.getAmount()
				.multiply(taxRate.divide(new BigDecimal(100)).add(BigDecimal.ONE)));
		// cf)
		// 세금 계산식은 굳이 이해를 하지 말자, 어차피 이게 메인도 아니다.
		// 무엇보다 사실 봐도 잘 모르겠다.
	}
}
package com.fastcampus.functionalprogramming.chapter9;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

import com.fastcampus.functionalprogramming.chapter9.model.Order;
import com.fastcampus.functionalprogramming.chapter9.model.OrderLine;
import com.fastcampus.functionalprogramming.chapter9.priceprocessor.OrderLineAggregationPriceProcessor;
import com.fastcampus.functionalprogramming.chapter9.priceprocessor.TaxPriceProcessor;

public class Chapter9Section3 {
	public static void main(String[] args) {
		// 각자의 기능을 갖고 있는 함수들을 합성해서 새로운 함수를 만들어보자
		// 목표 : order를 받아 해당 order의 가격을 process 해주는 함수를 만들어보자
		/*
		 * 현재 가격을 process 해주는 함수가 2개 존재하는 상황이다.
		 * 1. OrderLine의 가격 총합을 Order에 set 해주는 함수
		 * 2. Tax Rate를 적용해 Order 가격에 반영하는 함수
		 */
		Order unprocessedOrder = new Order()
								.setId(1001L)
								.setOrderLines(Arrays.asList(
										new OrderLine().setAmount(BigDecimal.valueOf(1000)),	// 1000원 짜리 주문
										new OrderLine().setAmount(BigDecimal.valueOf(2000))));	// 2000원 짜리 주문
		
		// 두 개의 PriceProcessor를 return 받았다.
		List<Function<Order, Order>> priceProcessors = getPriceProcessors();
		
		// getPriceProcessors method를 통해 받은 PriceProcessor 들을 하나로 합쳐서 '합성된 PriceProcessor'로 만들자
		Function<Order, Order> mergedPriceProcessors = priceProcessors.stream()
				.reduce(Function.identity(), Function::andThen); // Function::andThen을 이용해 코드를 더 간단하게
		// .reduce(Function.identity(), (priceProcessor1, priceProcessor2) -> priceProcessor1.andThen(priceProcessor2));
		/*
		 * Function.identity()를 이용해 reduce 작업의 초기값 제공
		 * 초기값 = Order를 받아 그대로 Order를 return 하는 Function<Order, Order> (다른 작업은 없다.)
		 */
				
		Order processedOrder = mergedPriceProcessors.apply(unprocessedOrder);
		System.out.println(processedOrder.getAmount());
	}
	
	// 두 개의 PriceProcessor를 return 하는 함수
	public static List<Function<Order, Order>> getPriceProcessors() {
		return Arrays.asList(
				new OrderLineAggregationPriceProcessor(), 
				new TaxPriceProcessor(new BigDecimal("9.375"))); // "9.375" = 적용할 세율
	}
}

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
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 31
글 보관함