ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Effective Java 공부하기] 2. 생성자에 매개변수가 많다면 빌더를 고려하라
    Java 2022. 3. 29. 00:12
    반응형

    생성자에 매갭변수가 많다면 빌더를 고려하라


    클래스의 인스턴스를 생성하기 위해서 생성자를 이용하는 것이 일반적이다.

    Student student = new Student(1L, "장규민", 10);

    생성자의 매개변수가 예시처럼 간단할 때는 생성자를 통한 인스턴스 생성 방법은 좋은 선택이 될 수 있지만 10개가 넘는 생성자 매개변수가 존재하고 매개변수의 타입마저 연달아 늘어서 있다면 코드를 작성할 때 휴먼에러로 이러질 수 있다.

    특히, 매개변수의 타입이 같아서 개발자가 실수한다면 컴파일 시, 오류를 잡아내지 못하기에 한참동안 방황할 수도 있을 것 같다.

    // 매개변수가 많아져 눈에 들어오지 않는다.
    Student student = new Student(1L, "장규민", 10, 179, 71, 100, 234, "01099700790", 12034, 634, 1234, 623, 1234, 523, 524); 

    물론 원하는 속성의 값만 초기화 하기 위해 점층적 생성자 패턴을 사용하여 생성자 매개변수를 줄일수도 있다.

    // 초기화를 원하는 속성을 점층적 생성자 패턴
    public Student(Long studentId, String name, int height, int weight) {
            this.studentId = studentId;
            this.name = name;
            this.height = height;
            this.weight = weight;
        }
    
    
    Student student = new Student(1L, "장규민", 179, 71);

    하지만 이마저의 매개변수도 길어질 여지는 충분히 있다.


    JavaBeans Pattern

    생성자 방법의 첫번째 대안으로는 자바빈즈 패턴(JavaBeans pattern)이 있다. 우리가 익숙하게 사용하는 Getter, Setter 메서드를 통해 인스턴스 속성에 접근하고 변경할 수 있다.

    public class Student {
    
        private Long studentId;
        private String name;
        private int age;
        private int height;
        private int weight;
        private String phoneNo;
    
        public Student() {
        }    
    
        public Long getStudentId() {
            return studentId;
        }
    
        public void setStudentId(Long studentId) {
            this.studentId = studentId;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public int getHeight() {
            return height;
        }
    
        public void setHeight(int height) {
            this.height = height;
        }
    
        public int getWeight() {
            return weight;
        }
    
        public void setWeight(int weight) {
            this.weight = weight;
        }
    
        public String getPhoneNo() {
            return phoneNo;
        }
    
        public void setPhoneNo(String phoneNo) {
            this.phoneNo = phoneNo;
        }
    }
    Student s = new Student();
    s.setStudentId(1L);
    s.setName("장규민");

    매개변수가 길게 나열된 생성자 패턴보다는 Setter 메서드를 통해 필요한 속성에 직접 값을 설정할 수 있으므로 직관적으로 보인다. 하지만 Effective Java 에서는 하나의 객체를 만드는데 여러개의 메서드가 호출되어야 하고 객체가 완전히 생성되기 전까지 일관성(consistency)가 무너진 상태로 놓이기에 큰 단점이 될 수 있다고 한다. 이 말은 즉슨 메서드의 호출을 이용한 객체 속성의 설정은 소스 이곳저곳에서 사용될 우려가 있어 런타임 오류 시, 디버깅이 매우 힘든다는 것이다. 때문에 실제로 운영되는 서비스에서는 Setter 메서드의 사용을 최대한 자제하기도 한다.


    Builder Pattern

    • 점측적 생성자 패턴의 안전성 + 자바빈즈 패턴의 가독성
    • 불변의 클래스
    public class Student {
    
        private Long studentId;
        private String name;
        private int age;
        private int height;
        private int weight;
        private String phoneNo;
    
        public Student(Builder builder) {
            studentId = builder.studentId;
            name = builder.name;
            age = builder.age;
            height = builder.height;
            weight = builder.weight;
            phoneNo = builder.phoneNo;
        }
    
        public static class Builder {
    
            private Long studentId;
            private String name;
            private int age = 0;
            private int height = 0;
            private int weight = 0;
            private String phoneNo = null;
    
            public Builder studentId(Long studentId) {
                this.studentId = studentId;
                return this;
            }
    
            public Builder name(String name) {
                this.name = name;
                return this;
            }
    
            public Builder age(int age) {
                this.age = age;
                return this;
            }
    
            public Builder height(int height) {
                this.height = height;
                return this;
            }
    
            public Builder weight(int weight) {
                this.weight = weight;
                return this;
            }
    
            public Builder phoneNo(String phoneNo) {
                this.phoneNo = phoneNo;
                return this;
            }
    
            public Student builder() {
                return new Student(this);
            }
    
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            // 플루언트(fluent) API 또는 메서드 연쇄(method chaining)
            new Student.Builder()
                    .studentId(1L)
                    .name("장규민")
                    .height(182)
                    .weight(120)
                    .builder();
    
        }
    }
    
    반응형

    댓글

Designed by Tistory.