[디자인 패턴] 빌더 패턴

Narcoker·2023년 8월 2일
0

디자인 패턴

목록 보기
7/8

빌더 패턴

빌더 패턴은 복잡한 객체를 생성하는 방법을 정의하는 디자인 패턴으로,
일반적으로 객체 생성과 객체 표현을 분리하는 목적으로 사용된다.

즉, 동일한 생성 절차를 통해 서로 다른 표현 결과를 만들 수 있다.

구성 요소

빌더(Builder)

생성할 객체의 각 부분을 생성하고 조립하는 방법을 정의하는 인터페이스

디렉터(Director)

빌더 인터페이스의 메서드를 사용하여 객체를 생성하는 절차를 정의

장점

생성자 인자가 많을 때 유용

인자가 많을 경우, 그 순서를 정확히 기억하기 어려워지는데 빌더 패턴을 사용하면 이를 해결할 수 있다.

코드의 가독성과 재사용성

코드의 가독성과 재사용성을 향상시킬 수 있다.

객체 불변성

객체를 불변(Immutable)하게 만들 수 있다.

단점

코드 복잡성 증가

빌더 패턴을 사용하면 클래스 코드가 늘어나고, 복잡해질 수 있다.
간단한 객체에 대해 빌더 패턴을 사용하면 과도한 설계로 이어질 수 있다.

빌더 생성 비용

각 객체를 생성할 때마다 빌더를 생성해야 한다.
따라서 객체가 많이 필요한 경우 빌더 패턴을 사용하면 성능 저하가 일어날 수 있다.

유지보수성 감소

만약 객체의 필드가 수정되면 해당 빌더 클래스도 함께 수정해야 한다.
이는 유지보수 비용을 증가시킬 수 있다.

이러한 단점으로 인해,

빌더 패턴은 객체 생성이 복잡하거나 선택적 인자가 많을 때 주로 사용된다.
그 외의 경우, 일반적인 생성자나 팩토리 메소드를 사용하는 것이 더 간단하고 효율적일 수 있다.

예제

아래 코드에서 User는 복잡한 객체이다.

빌터 패턴 적용 전

아래의 코드에서 User 객체는 선택적인 필드가 많기 때문에,
객체를 생성할 때 매개변수를 모두 명시해야 한다.

public class User {
    // 필수 인자
    private final String firstName;
    private final String lastName;

    // 선택적 인자
    private int age;
    private String phone;
    private String address;

    public User(String firstName, String lastName, int age, String phone, String address) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.phone = phone;
        this.address = address;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }

    public String getPhone() {
        return phone;
    }

    public String getAddress() {
        return address;
    }
}
User user = new User("First", "Last", 30, "12345678", "Fake address 1234");

System.out.println(user.getFirstName());  // Output: First
System.out.println(user.getLastName());  // Output: Last
System.out.println(user.getAge());  // Output: 30
System.out.println(user.getPhone());  // Output: 12345678
System.out.println(user.getAddress());  // Output: Fake address 1234

이 코드는 복잡하고 가독성이 떨어진다.

필드가 많아지면 매개변수의 순서를 헷갈릴 수도 있다.
선택적인 필드가 많아지면 오버로딩된 생성자를 여러 개 만들어야 하는 문제도 생긴다.

이렇게 복잡한 객체를 만들 때 빌더 패턴을 사용하면 코드의 가독성을 높이고, 오류를 줄일 수 있다.

빌더 패턴을 사용 후

UserBuilder는 빌더 역할을 하며, 각 setter 메서드는 빌더 객체 자신을 반환하므로
메서드 체이닝이 가능하다.

public class User {
    // 필수 인자
    private final String firstName;
    private final String lastName;

    // 선택적 인자
    private int age;
    private String phone;
    private String address;

    private User(UserBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.phone = builder.phone;
        this.address = builder.address;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }

    public String getPhone() {
        return phone;
    }

    public String getAddress() {
        return address;
    }

    public static class UserBuilder {
        private final String firstName;
        private final String lastName;
        private int age;
        private String phone;
        private String address;

        public UserBuilder(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }

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

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

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

        public User build() {
            return new User(this);
        }
    }
}
User user = new User.UserBuilder("First", "Last")
                    .age(30)
                    .phone("12345678")
                    .address("Fake address 1234")
                    .build();
                    
System.out.println(user.getFirstName());  // Output: First
System.out.println(user.getLastName());  // Output: Last
System.out.println(user.getAge());  // Output: 30
System.out.println(user.getPhone());  // Output: 12345678
System.out.println(user.getAddress());  // Output: Fake address 1234
profile
열정, 끈기, 집념의 Frontend Developer

0개의 댓글