빌더 패턴(Builder Pattern)

박세건·2024년 5월 21일
0

디자인 패턴

목록 보기
7/17
post-thumbnail

빌더 패턴이란, 객체의 생성과정과 표현방법을 분리해서 다양하게 이루어진 인스턴스를 만드는 생성패턴
매개 변수로 값을 하나하나 받아서 진행하고 마지막으로 통합 빌드 해서 객체를 생성

수제 햄버거로 예시를 들자, 수제 햄버거 이기에 사용자가 원하는 순서나 먹고 싶지않은 재료들이 있을 것이다. 이처럼 선택적으로 속성들을 우연하게 받아서 인스턴스를 생성할 수 있게 하는 것이 빌더 패턴이다.

탄생 배경

  • 일부 속성을 갖는 인스턴스를 생성해주기 위해서는 각각의 조건에 맞는 생성자를 구현해 놓아야한다.
    • 생성자 메서드가 증가하기 떄문에 비효율
      그렇다면 Java Beans 패턴은?

Java Beans 패턴 : 빈 객체를 만들고 setter를 사용해서 인스턴스 생성

  • 개발자의 실수로 인한 문제점 발생 가능성이 높음
    • setter를 빼먹음
  • 불변성 문제
    • setter를 노출하게되면 협업과정에서 누군가 setter 메서드를 사용해서 객체를 조작할 수 있게되고 이는 추후에 큰 문제를 일으킨다.

사용방식

생성하고자 하는 객체의 Builder 클래스를 만들고 이 클래스는 하나의 메서드당 하나의 속성을 지정해주고 원하는 속성 값 배정이 끝난 후에 객체를 생성

Student 객체

class Student {
    private int id;
    private String name = "아무개";
    private String grade = "freshman";
    private String phoneNumber = "010-0000-0000";

    public Student(int id, String name, String grade, String phoneNumber) {
        this.id = id;
        this.name = name;
        this.grade = grade;
        this.phoneNumber = phoneNumber;
    }
    
    @Override
    public String toString() {
        return "Student { " +
                "id='" + id + '\'' +
                ", name=" + name +
                ", grade=" + grade +
                ", phoneNumber=" + phoneNumber +
                " }";
    }
}

StudentBuilder 객체

class StudentBuilder {
    private int id;
    private String name;
    private String grade;
    private String phoneNumber;

    public StudentBuilder id(int id) {
        this.id = id;
        return this;
    }

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

    public StudentBuilder grade(String grade) {
        this.grade = grade;
        return this;
    }

    public StudentBuilder phoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
        return this;
    }
    public Student build() {
        return new Student(id, name, grade, phoneNumber); // Student 생성자 호출
    }

}

중요하게 봐야할 점은 각각의 메서드마다 return this 를 통해서 자신의 객체를 호출하게되고 이를 통해서 체이닝 기술이 사용할 수 있게된다.

  • 체이닝 : new StudentBuilder().id(값).name(값)...

마지막에 객체를 생성할때에는 build()라는 메서드를 실행시켜서 원하느 인스턴스를 반환한다.

사용 방법

public static void main(String[] args) {

    Student student = new StudentBuilder()
                .id(2016120091)
                .name("임꺽정")
                .grade("Senior")
                .phoneNumber("010-5555-5555")
                .build();

    System.out.println(student);
}

장점

  • 객체 생성 과정을 일관된 프로세스로 표현
    • 이전의 생성자 방식은 인자의 순서에 따라 어떤 속성값이 할당되어야하는지 파악 힘듬
    • 빌더패턴을 사용하면 순서에 상관없이 할당 가능
  • 디폴트 매개변수 생략을 간접적으로 지원
    • 디폴트 매개변수를 지정하면 이전의 방식에서는 두개의 생성자를 구현해야함
    • 빌더패턴을 사용하면 빌더객체의 멤버값에만 할당해놓으면됨
  • 필수 멤버와 선택적 멤버를 분리 가능
    • 필수적으로 입력되어야하는 멤버가 존재할 때 여러 생성자 생성 or null 값을 넣어줘야함
    • 빌더패턴을 사용하면 빌더 클래스의 생성자를 통해 편리하게 구현가능
      • 빌더 생성자에 필수 멤버가 포함된 생성자를 생성
          new StudentBuilder(2016120091) // 필수 멤버
          .name("홍길동") // 선택 멤버
          .build();
      			```
  • 객체 생성 단계를 지연할 수 있음
  • 빌더 클래스를 List에 저장시켜놓고 생성을 지연시켜서 추후에 사용할 수 있음
  • 초기화 검증을 멤버별(속성별)로 분리
    • 빌더 클래스의 멤버를 지정하는 메서드를 사용할때 매개변수로 들어온 값이 적절한 값인지를 검증하는 기능을 추가하여 사용할 수 있다
    • setter를 통해서 구현할 수 있지만 변경을 최소화 해야하기때문에 좋지않다
  • 멤버에 대한 변경 가능성 최소화 추구
    • setter를 통한 변경의 위험성을 방지할 수 있다.

단점

  • 코드의 복잡성 증가
    • 하나의 클래스마다 하나의 빌더클래스가 따로 필요하기때문에 코드양이 증가하게된다.
  • 생성자 보다 성능이 좋지 않다.
    • 생성자를 통한 직접적인 생성보다 빌더를 거쳐서 생성하기기때문에 성능은 떨어진다.
  • 빌더 남용은 좋지 않다.
    • 필드의 개수가 적을 때에는 생성자나 정적팩토리 메서드를 사용하는 것이 좋을 수 있다.

단점

  • 코드 복잡성 증가
  • 생성자보다는 성능은 떨어진다
  • 지나친 빌더 남용은 금지
profile
멋있는 사람 - 일단 하자

0개의 댓글

Powered by GraphCDN, the GraphQL CDN