ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [이펙티브 자바] 아이템2. 생성자에 매개변수가 많다면 빌더를 고려하라
    기타/북스터디 2022. 12. 12. 21:18

    1. 왜 생성자에 매개변수가 많으면 빌더를 고려해야할까?

    많은 매개변수를 가지고 있는 생성자에서 선택적 매개변수가 많다면 적절히 대응하기 어렵다.

    -> 선택적 매개변수에 의미있는 값을 넣어주는 것이 아니라면 null, empty string, 0등의 값을 넣어줘야한다.

     

    생성자를 호출하는 client단에서 불필요한 값을 넣어주는 것 외에 해결할 수 있는 방법은 무엇일까?

    점증적 생성자 패턴(telescoping constructor pattern)을 떠올릴 수 있다.

    점증적 생성자 패턴(telescoping constructor pattern)이란?
    생성자를 필수 매개변수 1개만 받는 생성자, 필수 매개변수 1개와 선택 매개변수 1개를 받는 생성자, 선택 매개변수 2개를 받는 생성자 등에 형태로 매개변수 개수만큼 생성자를 늘리는 방식
    즉, 필수인자를 받는 생성자 하나 정의, 선택적 인자를 받는 생성자를 하나씩 추가해가면서 정의하는 것

     

    하지만, 점증적 생성자 패턴도 결국에는 매개변수가 늘어난다면 클래스에서 가지는 생성자는 무한히 늘어나고 client단에서는 코드를 작성하거나 읽기 어려워지는 단점이 있다.

    - 생성자 호출코드에서 각 값의 의미를 헷갈릴 수 있음

    - 타입이 같은 매개변수가 연속해 있어 잘못 값을 대입하면 버그로 이어질 수 있음

     

    점증적 생성자 패턴이외에 다른 방법은 없을까?

    다른 대안이 자바빈즈 패턴(JavaBeans Pattern)을 생각해볼 수 있다.

    자바빈즈 패턴(JavaBeans Pattern)이란?
    매개변수가 없는 생성자로 객체를 만든 후, setter메서드들을 호출해 원하는 매개변수의 값을 설정하는 방식

     

    단점으로는 client단에서 객체를 만들려면 setter를 하나하나 호출하기에 코드가 길어지기는 했지만 점증적 생성자 패턴의 단점은 해결할 수 있다.

    또 다른 자바빈즈 패턴의 단점으로는 객체가 완전히 생성되지 전까지는 일관성이 무너진 상태에 놓이게 된다.

    -> 내가 이해한 바로는 생성자 호출 후에 setter로 객체의 속성을 전부 채워주기 전까지는 일관성이 무너진 상태라고 표현한 것이 아닐까?라는 말을 한 것같다.

    (왜 thread safe하지 않다고 말하는지는 조금 더 생각해봐야겠다.)

     

     

    2. 마지막 대안인 빌더패턴에 대해 알아보자.

    빌더패턴은 클라이언트가 필요한 객체를 직접 만드는 대신에 필수 매개변수만으로 생성자를 호출해 빌더(Builder)객체를 얻은 후에 원하는 선택 매개변수들을 설정하고 build메서드를 호출하여 객체를 얻는 방식이다.

    public class Car {
         private final int door;
         private final int wheel;
         private final String color;
         private final String brand;
         private final String name;
         private final boolean Hi-pass;
         private final boolean automation;
     
     	public static class Builder {
        	// 필수 파라미터
            private final int door;
         	private final int wheel;
            
            // 선택 파라미터
            private String color = "";
         	private String brand = "";
         	private String name = "";
         	private boolean Hi-pass = false;
         	private boolean automation = true;
            
            public Builder(int door, int wheel) {
                this.door = door;
                this.wheel = wheel;
            }
            
            public Builder color(String color) {
                this.color = color;
                return this;
            }
            
            public Builder brand(String brand) {
                this.brand = brand;
                return this;
            }
            
            ...
            
            public Car build() {
                return new Car(this);
            }
        }
        
        private Car(Builder builder) {
        	door = builder.door;
            wheel = builder.wheel;
            color = builder.color;
            brand = builder.brand;
            name = builder.name;
            Hi-pass = builder.Hi-pass;
            automation = builder.automation;
        }
    }

     

    빌더패턴은 점층적 생성자 패턴의 안정성과 자바빈즈 패턴의 가독성을 겸비한 좋은 방안이지만 이 역시도 단점은 존재한다.

    클래스 내부에 멤버 정적 클래스인 Builder를 생성해주어야하고 bulild메서드와 메스더 체이닝을 통해 선택 파라미터를 주입시켜주기 위한 메서드도 선언해주어야한다.

    우리가 빌더패턴이라는 방안에 도달하기까지 생각한 상황은 매개변수가 많은 생성자인 경우로 매개변수가 적다면 굳이 빌더패턴을 고집할 필요까지는 없다.


    <참고자료>

    - 이펙티브 자바 Effective Java 3/E

    - 백기선님 유튜브 강의 (https://youtu.be/OwkXMxCqWHM)

     

    댓글

Designed by Tistory.