반응형
Notice
Recent Posts
Recent Comments
Link
«   2025/09   »
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
Archives
Today
Total
관리 메뉴

웹풀스택 공부 중

14 - 5. Java - Builder & 정적 팩토리 메서드 본문

웹개발/Java

14 - 5. Java - Builder & 정적 팩토리 메서드

lukeit 2024. 11. 4. 13:05

생성자에 매개변수가 많다면 빌더를 사용하는건 어떠한가?

Builder

객체 생성의 모든 경우의 수를 지원한다

  • 매개변수가 많은 상황에서 생성자 혹은 정적 팩토리 메소드보다 더 유용하게 사용할 수 있다

    • 생성자가 넘겨줄 값을 지연시킬 수 있다
      • 한번에 값을 넘겨줄 필요 없이, 계속해서 넘긴 후, 설정이 끝났을 떄 생성이 가능하다
      • 순서대로 마음껏 값을 넣을 수 있다!
  • Builder 패턴은 3가지로 분리되어 호출된다

    • 빌더 정의 → 필드 설정 → 객체 생성

      1. 빌더 정의

         Member.MebmerBuilder builder = Member.builder()
      2. 필드 설정

         builder.name("Luke").email("Luke@example.com")
      3. 객체 생성

         Member luke = builder.build();
      • 흔히 보이는 Builder 패턴은 아래와 같다. 모든 스텝이 합쳐진 상태

          Member luke = Member.builder();
                                      .email("Luke@exampe.com")
                                      .name("Luke")
                                      .build();
  • Builder의 장점

    • 내가 원하는 필드만 설정할 수 있다

    • 생성자와 달리 필드값 주입 순서에 구애받지 않는다

    • 필드값 주입 역할을 마음껏 분리할 수 있다

      • 원하는 시점과 상황에 필드 설정이 가능하다

        • 예시 - 다른 부분을 따로 설정 (조건부)해서 만들어줄 수 있다

          String type = "THANKS_MESSAGE"; // "HELLO_MESSAGE"
          
          // (1) 빌더 정의
          MessageSender.MessageSenderBuilder builder = MessageSender.builder();
          
          // (2) 필드 설정
          // (2.1) 공통 부분을 먼저 설정하고
          builder
                .receiver("Aaron")
                .sender("Baron")
                .type(type);
          
          // (2.2) 다른 부분은 따로 설정한다 (조건부)
          if (type.equals("THANKS_MESSAGE")) {
            builder
                    .title("감사합니다")
                    .message("정말 감사합니다");
          }
          if (type.equals("HELLO_MESSAGE")) {
            builder
                    .title("안녕하세요")
                    .message("정말 반갑습니다");
          }
          
          // (3) 객체 생성
          MessageSender sender = builder.build();
  • @Builder.Default 를 통해 필드 설정이 없을 경우 객채 생성 시 설정해줄 필드 기본값을 세팅해줄 수 있다!

      @Builder
      public class Member {
          private Integer id;
          @Builder.Default
          private String name = "Unnamed";
          private int age;
          @Builder.Default
          private String email = "Undefined";
      }
  • @Singular : Collection (List, Set, Map)에 값을 한번에 넣지 않고, 하나씩 주입할 수 있도록 하는게 가능하다

    • Collection에서 Singular List로 만들어서 하나의 element만 넣어주면 collection으로 만들어준다

      @Builder
      public class Member {
        private Integer id;
        private String name;
        private int age;
        private String email;
        @Singular
        private List<String> favorites;
      }
      
      Member baron = Member.builder()
            .name("Baron")
            .email("baron@example.com")
            .favorite("Book")
            .favorite("Cook")
            .build();
    • 여기서 왜 .favorite만 해도 되는가?

      • @Singular를 사용했을때, 두가지 Method가 생성된다
        1. A method to add a single item to the list
          1. you use .favorite() to add a single item to the existing library
        2. A method to add all items from a collection
          1. you use .favorites() to add a whole collection
  • Custom Builder + Validation Logic

      @Builder
      public class Member {
          private Integer id;
          private String name;
          private int age;
          private String email;
    
          public static class MemberBuilder {
              public MemberBuilder age(int age) {
                  if (age >= 30) {
                      throw new RuntimeException("30세 이상은 설정 불가능합니다.");
                  }
                  this.age = age;
                  return this;
              }
          }
      }

Static Factory Method (정적 팩토리 메서드)

객체 생성 방법을 매우 좁게 정의한다

  • Factory Method = 객체를 생성 및 반환하는것

    • 생성자 대신 정적 팩토리 메서드를 사용하는걸 고려해야한다!
  • 정적 팩토리 메서드를 통한 객체 생성의 장점

    1. 메서드 이름을 가질 수 있음
      1. 생성 목적을 이름에 표현할 수 있어 가독성이 좋아진다
    2. 호출할 때 마다 새로운 객체를 생성할 필요가 없음
      1. 싱글턴, 혹은 생성해야할 객체 갯수에 제약을 둘 수 있다
    3. 하위 자료형 객체를 반환할 수 있음
      1. 상속 사용시 이점이지만 상속보단 조합을 쓰기에 큰 장점은 아니다
    4. 객체 생성을 캡슐화 할 수 있음
  • Naming Convension

    • from : 하나의 매개 변수를 받아서 객체를 생성
    • of : 여러개의 매개 변수를 받아서 객체를 생성
    • getInstance or instance : 인스턴스를 생성한다, 이전에 반환했던 것과 같을 수 있다
    • newInstance or create : 새로운 인스턴스를 생성한다
    • get[OtherType] : 다른 타입의 인스턴스를 생성한다, 이전에 반환했던 것과 같을 수 있다
    • new[OtherType] : 다른 타입의 새로운 인스턴스를 생성한다
  • 예시

      @AllArgsConstructor(access = AccessLevel.PRIVATE)
      public class Member {
          private Integer id;
          private String name;
          private int age;
          private String email;
    
          public static Member from(MemberCreateRequestDto requestDto) {
              return new Member(
                      null,
                      requestDto.getName(),
                      0,
                      requestDto.getEmail()
              );
          }
      }
    
      MemberCreateRequestDto requestDto = new MemberCreateRequestDto("Baron", "baron@example.com");
      //      생성자가 Private 가 되었으므로 외부에서 호출이 불가하다.
      //      Member aaron = new Member(1, "Aaron", 10, "aaron@example.com");
      Member baron = Member.from(requestDto);
반응형

'웹개발 > Java' 카테고리의 다른 글

15 - 3. Java - Static  (0) 2024.11.04
15 - 1. Java - Lombok  (0) 2024.11.04
14 - 4. Java - Object 생성자  (0) 2024.11.04
14 - 3. Java의 OOP 문법 - Encapsulation + Inheritence  (0) 2024.11.04
14 - 2. Java - JVM  (0) 2024.11.04