[JAVA]메서드 체이닝에 대해 알아보자.

nana·2024년 10월 19일
1

JAVA

목록 보기
8/11

0. 서론

가끔 프로그래머스 같은 사이트를 보면 메소드 체이닝을 이용해 한줄로 끝내는 천재들을 많이 볼 수 있다.
메소드체이닝을 이용하면 코드가 간결해 진다는 이점도 있지만,
때로는 가독성 적인 부분에서 이해하기 어려운 코드가 되기도 하여 상황에 따라 적절하게 쓰는 것이 중요하다.

chaining?

말 그대로 "연결성"을 가진 것.

이런식으로 . 을 활용해서 쭉쭉 이어나가는 방식을 뜻하는데 좀 더 좋은 코드, 멋있는 코드를 짜기 위해선 잘 알아둬야 할 것 같다는 생각이 들었다.

1. 메소드 체이닝이란?

여러 메서드 호출을 연결하여 호출하는 프로그래밍 기술.
이를 이용하면 코드를 간결하게 작성 가능하고 가독성을 높일 수 있다.

  • 객체의 메서드를 연속적으로 호출하여 작업을 수행할 수 있으며, 각 메서드는 호출된 객체를 반환하여 다음 메서드 호출을 가능하게 한다.
  • 플루언트 인터페이스(Fluent Interface) / 빌더패턴 (Builder Pattern)을 구현하는데에 자주 사용되며, 간결하고 읽기 쉬운 코드를 작성하는데 도움이 된다.

구조

obj.method1().method2().method3()

플루언트 인터페이스(Fluent Interface)

  • 메소드 체이닝을 기반한 객체 지향 API 인터페이스 메서드.
    소스코드의 가독성을 높이기 위한 목적으로 사용되며 인터페이스 안에 도메인 특화언어(DSL)을 이용하여 작성한다.
  • 각 메서드는 수정된 객체를 반환하여 다음 연산을 계속할 수 있으며, 주로 변경가능한 객체에서 사용한다.
    wiki

2. 빌더 패턴(Builder Pattern)

  • 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 패턴
  • 생성자의 매개변수가 많을 때 객체 생성을 더 쉽고 가독성 있게 만드는 디자인패턴으로
    불변성을 가진 객체를 만들 때 특히 유용하다.

3. Code Refactoring

이번에 피드백 받은 코드를 리팩토링 해 보는 것으로 예제를 대신 해 보겠다.

  public CartResponse addCartProducts(Long customerId, List<CartRequest> cartRequests) {

        List<Cart> carts = getCartList(customerId);

        List<CartDetailResponse> responseProduct = new ArrayList<>();

        for (CartRequest cr : cartRequests) {
            if (carts.isEmpty()) {

                addProductsToCart(customerId, cr.productId(), cr.amount());
                responseProduct.add(setProductDetail(cr.productId(), cr.amount()));
            }
            else{
                Optional<Cart> exists = carts.stream()
                        .filter(c -> c.getProduct().getProductId().equals(cr.productId()))
                        .findFirst();

                exists.ifPresent(cart -> cart.addCartAmount(cr.amount()));

                if (exists.isEmpty()) {
                    addProductsToCart(customerId, cr.productId(), cr.amount());
                }
                responseProduct.add(setProductDetail(cr.productId(), exists.get().getAmount()));
            }

        }
        return new CartResponse(
                customerId,
                responseProduct,
                LocalDateTime.now()
        );
    }

장바구니 시스템 중 상품을 장바구니에 담는 코드이다.
이 중 바꿔야 할 부분은

Optional<Cart> exists = carts.stream()
                        .filter(c -> c.getProduct().getProductId().equals(cr.productId()))
                        .findFirst();

                exists.ifPresent(cart -> cart.addCartAmount(cr.amount()));

                if (exists.isEmpty()) {
                    addProductsToCart(customerId, cr.productId(), cr.amount());
                }

exists.ifPresent~~if(exists.isEmpty())
부분이 ifPresentisEmpty로 중복되는 느낌이 든다.
이걸 간단하게 메서드 체이닝으로 구현하면

exists.ifPresentOrElse(
       cart -> cart.addCartAmount(cr.amount()),
               () -> addProductsToCart(customerId, cr.productId(), cr.amount()));

이렇게 7줄 짜리 코드가 3줄로 줄어들었다!!

ifPresentOrElse라는 메서드를 처음봐서 들어가봤더니

action과 반환 값이 비어있을 경우 실행할 동작을 파라미터로 넘긴다.
action을 실행해서 값이 있으면 action을 실행하고, 없으면 emptyAction을 반환하며
그리고 값이 null이라면 NullPointException를 예외로 던져준다.

4. 결론

Optional의 기능이 참 많은 것 같은데 유용하게 사용할 수 있는 부분이 많은 것 같다.
개발자들이 대부분 실수하는 경우가 NullException인데 Optional의 내장 클래스를 잘 활용하면 이 오류도 줄일 수 있을 것 같다.


참고
[JAVA 자바] 메소드 체이닝이란?

profile
BackEnd Developer, 기록의 힘을 믿습니다.

0개의 댓글