본문 바로가기
공부/프로그래밍

[java] 빌더 패턴(Builder Pattern) 주의점과 사용이유

by demonic_ 2019. 10. 18.
반응형

어제 서비스를 개선하고 테스트를 돌렸는데 문제가 발생했다.

 

분석해보니 평소 쓰던 build 패턴을 사용하는 것에서 문제가 있었다.

 

구조는 다음과 같다.

import lombok.Builder;
import lombok.Getter;
import lombok.ToString;

@Getter
@ToString
public class BuildTest {
    private String name;
    private int age;
    private String addr;
    private String phone;
    private String memberYn = "Y";


    @Builder
    public BuildTest(String name, int age, String addr, String phone) {
        this.name = name;
        this.age = age;
        this.addr = addr;
        this.phone = phone;
    }
}

 

회원유무(memberYn)의 경우 필수값이기 떄문에 디폴트 선언을 해두었다.

 

그리고 빌더 패턴을 이용해 객체를 생성했다.

BuildTest buildTest = BuildTest.builder()
                .name("홍길동")
                .age(20)
                .phone("01012345678")
                .addr("서울시")
                .build();


### 결과
BuildTest(name=홍길동, age=20, addr=서울시, phone=01012345678, memberYn=Y)

 

그런데 회원여부를 객체생성시 파라미터로 받을 수 있도록 수정할 일이 있었다. 그래서 기존코드를 수정했다.

...
	@Builder
    public BuildTest(String name, int age, String addr, String phone, String memberYn) {
        this.name = name;
        this.age = age;
        this.addr = addr;
        this.phone = phone;
        this.memberYn = memberYn;
    }
...

 

테스트는 위와 동일한 코드로 실행했다.

BuildTest buildTest = BuildTest.builder()
                .name("홍길동")
                .age(20)
                .phone("01012345678")
                .addr("서울시")
                .build();


### 결과
BuildTest(name=홍길동, age=20, addr=서울시, phone=01012345678, memberYn=null)

 

기본값으로 설정한 "Y"는 없어지고 null로 생성되었다.

그래서 null로 발생한 문제로 인해 테스트가 실패되었다.

 

이에 따른 해결방법은 생성자를 추가하는 것이다(memberYn을 받는것과 받지않은것 각각 만들기)

 

수정한 예는 다음과 같다

 

	...
	// memberYn 이 없는 생성자
    @Builder
    public BuildTest(String name, int age, String addr, String phone) {
        this.name = name;
        this.age = age;
        this.addr = addr;
        this.phone = phone;
    }

	// memberYn 이 있는 생성자
    @Builder
    public BuildTest(String name, int age, String addr, String phone, String memberYn) {
        this.name = name;
        this.age = age;
        this.addr = addr;
        this.phone = phone;
        this.memberYn = memberYn;
    }
    ...

 

테스트 해본 결과 기본값인 "Y"가 들어가 생성되어 있다. 그래서 반드시 값이 있어야 하는 필드의 경우는 좀더 신경써서 생성할 필요가 있다.

 

 

이쯤되니 빌더 패턴을 왜 사용하는지 다시금 살펴보게 되었다.

 

빌더 패턴은 setter 메소드가 없는 객체를 생성하여 변경불가능하게 하는데 좋다. 한번 만들어진 객체를 이리저리 수정하지 못하게 고정시켜놓음으로써 제 역할을 다 할 수 있도록 돕는것이 빌더 패턴이다.

 

변경불가능하게 만드는 이유는 변수가 공유되면서 발생할 문제를 사전에 예방하는 것이다. 상태값 A가 들어가 있는 객체가 상황에따라 B나 C로 변경되어야 한다면 매번 사용될때마다 디버깅이 필요하고, 다른사람에게 인수인계 할때도 상황에 따른 설명을 해줘야한다. 이는 유지보수 차원에서 많은 비용을 발생시킨다.

 

 

그리고 시작한김에 체크로직을 만들어 넣어두었다. 최근에 읽은 <오브젝트>에서는 다음의 문구가 있다.

 

 

객체의 응집도를 높이기 위해서는 객체 스스로 자신의 데이터를 책임져야 한다.

 

생성된 객체는 자기의 데이터를 명확히 가지고 있는지 점검할 의무가 있다. 객체를 생성만하고 다른곳에서 정합성을 검증한다면 코드가 지저분해지는 것도 있지만, 유지보수 할때도 일일히 찾아가봐야 하는 번거로움이 있다. 저자의 말처럼 '객체는 자신의 데이터를 스스로 처리하는 자율적인 존재'가 되어야 한다. 해서 자기 데이터에 책임을 질 수 있도록 추가했다.

반응형

댓글