ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [자바/Java] 자바 빌더 패턴(Builder Pattern) 알아보기
    Java 2021. 7. 18. 01:59

    오늘은 빌더 패턴 (Builder Pattern)에 대하여 알아볼 것이다.

     

    Person DTO

    public class Person{
    
      private String name;        
      private int age;                
      private String address;   
    
      public Person(String name){
         this.name = name;
      }
    
      public Person(String name, int age){
        this.name = name;
        this.age = age;
      }
    
      public Person(String name, int age, String address){
        this.name = name;
        this.age = age;
        this.address = address;
      }
    }

    위와 같은 클래스를 DTO로 활용한다고 가정하면 동작은 잘하겠지만,

    여러 문제점들이 있을 수 있다.

     

    1. 추가로 멤버 변수가 늘어날수록 생성자가 많아진다.
    2. 인스턴스화 할 때 파라미터를 실수로 입력할 가능성이 있다.
    3. 코드의 가독성이 떨어진다.

     

    2, 3번의 문제를 예를들면 아래와 같다.

    Person person1 = new Person("daejeon", 10, "kim");
    Person person2 = new Person("park", 10, "seoul");

    person1은 이름을 넣어야할 위치에 주소 정보를 넣었지만 아무 에러없이 동작을 할 것이다.

    그렇기 때문에 문제가 되고, 멤버 변수의 종류가 늘어나면 늘어날수록 직관적으로 생성자에 입력한 인자들이 어떤 값인지

    확인하기 어렵다.

     

    이러한 패턴을 점층적 생성자 패턴이라고 한다.

     

    점층적 생성자 패턴의 단점을 보완하기 위해 자바 빈즈(beans) 패턴이 나온다.

    쉽게 접할 수 있는 getter, setter를 활용한 것이 바로 자바 빈즈 패턴이다.

     

    자바 빈즈 패턴

    public class Person{
    
      private String name;        
      private int age;                
      private String address;   
    
      public void setName(String name){
      	this.name = name
      }
      
      public void setAge(int age){
      	this.age = age
      }
      
      public void setAddress(String address){
      	this.address = address
      }
    }

    이런 식으로 작성해서 사용하면 가독성을 해결할 수 있다.

    Person person = new Person();
    person.setName("hong");
    person.setAge(10);
    person.setAddress("daejeon");

    훨씬 더 직관적으로 값을 주입할 수 있고,

    필요한 시점에 값을 주입할 수도 있다.

     

    하지만 필요한 시점에 값을 주입할 수도 있다는 것이 단점이 될 수 있다.

    필요한 시점에 값을 주입할 수 있다는 것은 객체 일관성이 깨질 수 있음을 말한다.

    Person을 인스턴스로 만들고 여러번 수정이 가능하기 때문에 원치 않는 인스턴스의 값을 받을 수 있다.

     

    이것을 방지하기 위해 빌더 패턴을 활용할 수 있다.

     

    자바 빌더 패턴

    public class Person {
        private final String name;        
        private final int age;                
        private final String address;
    
        Person(String name, int age, String address) {
            this.name = name;
            this.age = age;
            this.address = address;
        }
    
        public static Person.PersonBuilder builder() {
            return new Person.PersonBuilder();
        }
    
        public static class PersonBuilder {
            private String name;        
            private int age;                
            private String address;
    		
            public Person.PersonBuilder name(String name) {
                this.name = name;
                return this;
            }
            
            public Person.PersonBuilder age(int age) {
                this.age = age;
                return this;
            }
    
            public Person.PersonBuilder address(String address) {
                this.address = address;
                return this;
            }
    
            public Person build() {
                return new Person(this.name, this.age, this.address);
            }
        }
    }

    위 코드를 보면 알 수 있듯이 Person의 멤버 변수를 final로 두고 내부의 PersonBuilder라는 클래스를 만들고 그 클래스를

    통해 Person을 new하고 있다.

     

    이런식으로 하면 아래와 같은 코드로 새로운 Person의 인스턴스를 만들 수 있다.

    Person person = new Person.builder()
                            .name("hong")
                            .age(10)
                            .build();

    필요에 따라 원하는 값을 메서드 체이닝을 통해 주입할 수 있고 해당 변수들은 final로 선언했기 때문에,

    값이 변하지 않음을 보장받을 수 있다.

     

    위 과정을 살펴보면 무조건 빌더 패턴이 좋은 것 같지만 그런것만은 아니다.

     

    1. 해당 인스턴스를 생성하고 멤버 변수 값을 변경할 수 없다.
    2. 코드량이 많아진다.(물론 이 점은 롬복으로 해결이 가능..)

    그렇기 때문에 상황에 맞게 적절히 패턴을 도입해서 사용해야 될 것 같다.

     

    끝!

    댓글