빌더 패턴의 활용과 장점

빌더 패턴의 활용과 장점

  • 빌더 패턴 기본 사용법

    • 클래스 위에 @Builder

      • 빌더 패턴 사용을 위해 @AllArgsConstructor가 default하게 적용된 것과 마찬가지
    • @AllArgsConstructor(access = AccessLevel.PRIVATE)로 빌더 외의 생성자 감추는 걸 권장

      import lombok.AccessLevel;
      import lombok.AllArgsConstructor;
      import lombok.Builder;
      import lombok.Getter;
      
      @AllArgsConstructor(access = AccessLevel.PRIVATE)
      @Builder
      @Getter
      public class User {
        private final String id;
        private final String password;
        private final String name;
        private final String email;
        private final int age;
      }
      
  • User 클래스 파일

    • @AllArgsConstructor(access = AccessLevel.PRIVATE)

    • @Builder

    • @Getter

      //
      // Source code recreated from a .class file by IntelliJ IDEA
      // (powered by FernFlower decompiler)
      //
      
      package com.ssafy.hw.step2;
      
      public class User {
        private final String id;
        private final String password;
        private final String name;
        private final String email;
        private final int age;
      
        public static UserBuilder builder() {
            return new UserBuilder();
        }
      
        private User(String id, String password, String name, String email, int age) {
            this.id = id;
            this.password = password;
            this.name = name;
            this.email = email;
            this.age = age;
        }
      
        public String getId() {
            return this.id;
        }
      
        public String getPassword() {
            return this.password;
        }
      
        public String getName() {
            return this.name;
        }
      
        public String getEmail() {
            return this.email;
        }
      
        public int getAge() {
            return this.age;
        }
      
        public static class UserBuilder {
            private String id;
            private String password;
            private String name;
            private String email;
            private int age;
      
            UserBuilder() {
            }
      
            public UserBuilder id(String id) {
                this.id = id;
                return this;
            }
      
            public UserBuilder password(String password) {
                this.password = password;
                return this;
            }
      
            public UserBuilder name(String name) {
                this.name = name;
                return this;
            }
      
            public UserBuilder email(String email) {
                this.email = email;
                return this;
            }
      
            public UserBuilder age(int age) {
                this.age = age;
                return this;
            }
      
            public User build() {
                return new User(this.id, this.password, this.name, this.email, this.age);
            }
      
            public String toString() {
                return "User.UserBuilder(id=" + this.id + ", password=" + this.password + ", name=" + this.name + ", email=" + this.email + ", age=" + this.age + ")";
            }
        }
      }
      
  • builder(필수값1, 필수값2, ...) 따로 정의해 필수 값 강제하기

      import lombok.AccessLevel;
      import lombok.AllArgsConstructor;
      import lombok.Builder;
      import lombok.Getter;
    
      @AllArgsConstructor(access = AccessLevel.PRIVATE)
      @Builder
      @Getter
      public class User {
          private final String id;    // 필수값
          private final String password; // 필수값
          private final String name;
          private final String email;
          private final int age;
    
          public static UserBuilder builder(String id, String password) {
              return new UserBuilder()
                  .id(id)
                  .password(password);
          }
      }
    
      //클라이언트 코드
      public class UserTest {
    
          public static void main(String[] args) {
    
              User user1 = User.builder("1", "1")
                  .name("user1")
                  .email("user1@user.com")
                  .age(27)
                  .build();
      }
    
  • 빌더 패턴에서 변수 값 초기화하는 방법

    • 생성자 따로 정의하고 생성자에 @Builder 추가하기

      • 빌더가 따로 정의된 생성자를 사용함

        • 초기화 가능
      import lombok.Builder;
      import lombok.Getter;
      
      // @AllArgsConstructor(access = AccessLevel.PRIVATE) 생성자 따로 정의
      @Getter
      public class User {
        private final String id;    // 필수값
        private final String password; // 필수값
        private final String name;
        private final String email;
        private final int age;
      
        @Builder
        private User(
            String id,
            String password,
            String name,
            String email,
            int age
        ) {
            this.id = "초기화 값" + id;
            this.password = "초기화 값" + password;
            this.name = name;
            this.email = email;
            this.age = age;
        }
      
        public static UserBuilder builder(String id, String password) {
            return new UserBuilder()
                .id(id)
                .password(password);
        }
      }
      
    • 파라미터에 넘어가는 값만 빌더 체인이 생성됨

      • 파라미터에 age를 삭제하면 클라이언트에서 age 값 설정 불가
      import lombok.Builder;
      import lombok.Getter;
      
      // @AllArgsConstructor(access = AccessLevel.PRIVATE) 생성자 따로 정의
      @Getter
      public class User {
        private final String id;    // 필수값
        private final String password; // 필수값
        private final String name;
        private final String email;
        private final int age;
      
        @Builder
        private User(
            String id,
            String password,
            String name,
            String email
            // int age
        ) {
            this.id = "초기화 값" + id;
            this.password = "초기화 값" + password;
            this.name = name;
            this.email = email;
            this.age = 29; // age는 무조건 29로 초기화
        }
      
        public static UserBuilder builder(String id, String password) {
            return new UserBuilder()
                .id(id)
                .password(password);
        }
      }
      
  • 빌더 패턴의 장점

    1. 생성자 오버로딩 불필요 등 필요한 데이터만 설정할 수 있음

    2. 변수가 추가 되어도 기존 코드에 영향을 주지 않아 유연성을 확보할 수 있음

    3. 어떤 변수 값으로 어떤 파라미터가 넘어가는지 명확해 가독성을 높일 수 있음

       User user1 = User.builder("id", "password")
                       .name("박주원")
                       .email("devprofessionalism@gmail.com")
                       .age(29)
                       .build();
      
    4. 불변 객체로 생성해 변경 가능성을 최소화할 수 있음

  • 참고자료