티스토리 뷰

728x90
반응형

빌더 패턴이란?


  • 자바에서는 클래스를 인스턴스화 하는 방법에는 점층적 생성자 패턴, 자바 빈즈 패턴, 빌더 패턴이 존재합니다.

 

 

점층적 생성자 패턴이란?


User Class
  • 필수 매개변수를 받는 생성자를 생성하고, 선택 매개변수 1개, 선택 매개변수 2개 등 선택 매개변수를 추가로 받는 생성자를 매개변수 개수만큼 생성자를 늘리는 방식입니다.
  • 마치 생성자가 점층적으로 늘어나는 생성자를 가지도록 한 디자인 패턴을 말합니다.
public class User {

    private String name;      // 필수
    private int age;          // 필수
    private String phone;     // 선택
    private String email;     // 선택
    private String address;   // 선택

    // 필수 데이터를 가지는 생성자
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 선택 데이터 phone이 추가된 생성자
    public User(String name, int age, String phone) {
        this.name = name;
        this.age = age;
        this.phone = phone;
    }

    // 선택 데이터 email이 추가된 생성자
    public User(String name, int age, String phone, String email) {
        this.name = name;
        this.age = age;
        this.phone = phone;
        this.email = email;
    }

    // 모든 매개변수를 가지는 생성자
    public User(String name, int age, String phone, String email, String address) {
        this.name = name;
        this.age = age;
        this.phone = phone;
        this.email = email;
        this.address = address;
    }
}

 

단점
  • 매개변수가 많아질수록 많은 조합이 만들어지고, 생성자 수가 많아집니다. 이렇게 된다면 코드의 가독성도 떨어지고 효율성이 없게 됩니다.
  • 클래스를 인스턴스화하는 과정에서 매개변수가 제대로 맞는지 확인해야 하므로 불편함이 있습니다.
public class Example {
    public static void main(String[] args) {
        User 홍길동 = new User("홍길동", 20, "010-1234-5678");
        User 이순신 = new User("이순신", 20, "010-1234-5678", "admin@admin.com");
    }
}

 

자바 빈즈 패턴이란?


  • 매개변수가 없는 생성자(기본 생성자)로 객체를 만든 후 setter 메서드를 호출하여 원하는 매개변수의 값을 설정하는 방식입니다.
public class User {

    private String name;
    private int age;
    private String phone;
    private String email;
    private String address;   

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

public class Example {
    public static void main(String[] args) {
        User 홍길동 = new User();
        홍길동.setName("홍길동");
        홍길동.setPhone("010-1234-5678");
        홍길동.setEmail("admin@admin.com");
        홍길동.setAge(20);
        홍길동.setAddress("서울특별시");

        User 이순신 = new User();
        이순신.setName("이순신");
        이순신.setPhone("010-1234-5678");
        이순신.setEmail("admin@admin.com");
        이순신.setAge(20);
        이순신.setAddress("서울특별시");
    }
}
장점
  • 클래스를 인스턴스화하고 값을 세팅하는 상황에서 가독성이 좋습니다.
단점
  • 하나의 인스턴스를 만들기까지 메서드를 여러번 호출해야하고, setter 메서드가 있기 때문에 불변의 객체를 만들 수 없습니다.

 

빌더 패턴이란?


  • 매개변수를 세팅해주는 메서드의 리턴 타입을 Builder 객체로 지정함으로써, 메서드 체이닝 기법을 적용하고, 메개변수를 다 넣은 경우 build() 메서드를 호출하여 객체를 생성합니다.
  • 빌더 패턴을 사용하면 어느 필드에 어떤 값을 채워야할지 알 수 있으며, 데이터 일관성, 객체 불변성 등을 만족시키며 코드의 가독성을 높일 수 있습니다.

 

빌더 패턴 구조


Builder
  • 객체를 생성하는 추상 인터페이스
Concrete Builder
  • Builder의 구현 클래스, 다른 객체를 생성할 수 있도록 하는 구체적인 클래스, 객체를 만들기 위해 부품을 생성하고 조립합니다.
Director
  • Director 클래스는 객체 생성의 정확한 순서를 다루는 부분에 책임이 있습니다. 이 클래스는 Concrete Builder를 인자로 받아서 필요한 동작을 수행합니다.
Product
  • Builder를 이용해서 Director가 만들어낸 최종 객체

 

필수값이 없는 Builder 패턴 예제


@ToString
public class User {

    private String name;
    private int age;
    private String phone;
    private String email;
    private String address;

    private User(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.phone = builder.phone;
        this.email = builder.email;
        this.address = builder.address;
    }


    // 빌더 호출
    // 외부에서 User.builder()로 접근할 수 있도록 static으로 생성
    public static Builder builder() {
        return new Builder();
    }


    public static class Builder {
        private String name;
        private int age;
        private String phone;
        private String email;
        private String address;

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public Builder phone(String phone) {
            this.phone = phone;
            return this;
        }

        public Builder email(String email) {
            this.email = email;
            return this;
        }

        public Builder address(String address) {
            this.address = address;
            return this;
        }

        // build() 메서드를 호출하면 this가 반환
        // // this => Builder
        public User build() {
            return new User(this);
        }
    }
}

public class Example {
    public static void main(String[] args) {
        User 홍길동 = User.builder()
                .name("홍길동")
                .age(20)
                .phone("010-1234-5678")
                .email("admin@admin.com")
                .address("서울특별시")
                .build();

        System.out.println(홍길동);
        // User(name=홍길동, age=20, phone=010-1234-5678, email=admin@admin.com, address=서울특별시)
    }
}

 

필수값이 있는 Builder 패턴 예제


@ToString
public class User {
    private String name;
    private int age;
    private String phone;
    private String email;
    private String address;

    private User(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.phone = builder.phone;
        this.email = builder.email;
        this.address = builder.address;
    }

    public static class Builder {
        private final String name;   // 필수
        private final int age;       // 필수
        private final String phone;  // 필수
        private String email;
        private String address;

        public Builder(String name, int age, String phone) {
            this.name = name;
            this.age = age;
            this.phone = phone;
        }

        public Builder email(String email) {
            this.email = email;
            return this;
        }

        public Builder address(String address) {
            this.address = address;
            return this;
        }

        // build() 메서드를 호출하면 this가 반환
        // // this => Builder
        public User build() {
            return new User(this);
        }
    }
}

public class Example {
    public static void main(String[] args) {
        User user = new User.Builder("홍길동", 25, "010-1234-5678")
                .address("서울특별시")
                .build();

        System.out.println(user);
        // User(name=홍길동, age=25, phone=010-1234-5678, email=null, address=서울특별시)
    }
}

 

 

Lombok의 @Builder 어노테이션
  • 긴 코드를 어노테이션하나로 정리가능합니다. 멋있다
@ToString
@Builder
public class User {

    private String name;
    private int age;
    private String phone;
    private String email;
    private String address;
}

public class Example {
    public static void main(String[] args) {
        User 홍길동 = User.builder()
                .name("홍길동")
                .age(20)
                .phone("010-1234-5678")
                .email("admin@admin.com")
                .address("서울특별시")
                .build();

        System.out.println(홍길동);
        // User(name=홍길동, age=20, phone=010-1234-5678, email=admin@admin.com, address=서울특별시)
    }
}
728x90
반응형