객체 생성 방법에는 3가지 패턴이 존재한다.
- 점층적 생성자 패턴
- 자바빈 패턴
- Builder 패턴
/**
*
* 객체 생성 방법
* 1. 점층적 생성자 패턴(하나씩 하나씩 새로운 생성자 생성하는방법)
* 2. 자바빈 패턴
* 3. Builder 패턴
*
*/
public class BuilderPatternDesc {
public static void main(String[] args) {
TestVO vo = new TestVO();
1. prop1만 결정
2. prop2, prop3 결정
3. prop1, prop3 결정
4. prop1, prop2, prop3 결정
}
}
1. 점층적 생성자 패턴
이런식으로 생성자를 하나하나 늘려가면서 만드는 것을 점층적 생성자 패턴이라고 함.
점층적 생성자의 단점
- 원하는(실질적으로 두가지 방법이 동일하지만 파라미터 이름이 다르기에) 파라미터를 중복해서 쓸 수 없다.
2. 타입 안정성이 없다.
3번처럼 타입 안정성이 없다
무슨말이냐 하면 파라미터의 순서를 반드시 지켜야지 원하는 곳에 원하는 값이 들어가게 된다.
실수로 순서를 바꾸게 되면 원하지 않는 변수에 원하지 않는 값이 들어가게 된다.
2. 자바빈 패턴
자바빈 규약에 따라(setter) 만드는 방법
자바빈 패턴의 단점
- 귀찮다... 일일이 setter로 값을 정해주어야 한다. 그리고 코드가 길어진다.
- 중복된다. 변수명.set 까지의... 별 것 아니지만 계속해서 중복된다.
- 이뮤터블을 만들 수 없다.(변하지 않는 값) setter를 쓰기 때문에 계속해서 값을 변경 시킬 수 있다.
이러한 단점들을 보완하기 위해 나온 것이 builder 패턴이다.
3. builder 패턴
1번째 특징 : builder의 경우 객체의 생성을 전담하는 builder가 필요하다.
2번째 특징 : 체인구조 항상 return this를 해준다. javaScript와 유사
getter만 존재한다.
코드 (TestVO)
package kr.or.ddit.designpattern.builder; import java.io.Serializable; public class TestVO implements Serializable{ private String prop1; private String prop2; private String prop3; // 빌더는 생성자 중 모든 변수를 받는 생성자가 필요하다. private TestVO(String prop1, String prop2, String prop3) { super(); this.prop1 = prop1; this.prop2 = prop2; this.prop3 = prop3; } public String getProp1() { return prop1; } public String getProp2() { return prop2; } public String getProp3() { return prop3; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((prop1 == null) ? 0 : prop1.hashCode()); result = prime * result + ((prop2 == null) ? 0 : prop2.hashCode()); result = prime * result + ((prop3 == null) ? 0 : prop3.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; TestVO other = (TestVO) obj; if (prop1 == null) { if (other.prop1 != null) return false; } else if (!prop1.equals(other.prop1)) return false; if (prop2 == null) { if (other.prop2 != null) return false; } else if (!prop2.equals(other.prop2)) return false; if (prop3 == null) { if (other.prop3 != null) return false; } else if (!prop3.equals(other.prop3)) return false; return true; } @Override public String toString() { return "TestVO [prop1=" + prop1 + ", prop2=" + prop2 + ", prop3=" + prop3 + "]"; } public static TestVOBuilder builder() { // 객체 생성을 builder 내부에서 한다. return new TestVOBuilder(); } public static class TestVOBuilder{ private TestVOBuilder() {} private String prop1; private String prop2; private String prop3; public TestVOBuilder prop1(String pro1) { this.prop1 = prop1; return this; } public TestVOBuilder prop2(String pro2) { this.prop2 = prop2; return this; } public TestVOBuilder prop3(String pro3) { this.prop3 = prop3; return this; } public TestVO build() { // TestVO vo2 = TestVO.builder().prop2("prop2").prop3("prop3").build(); // 이렇게 사용해도 prod1에는 null이 자동으로 들어가게 된다. return new TestVO(prop1, prop2, prop3); } } }
TestVO 자체는 getter와 모든 변수를 가진 생성자를 만들어 두고
inner class로 내부에서 데이터를 가공한다.
***하단에 hashCode(), equals, toString을 만들어줌.
이렇게 builder를 호출해서 TestVOBuilder를 생성 →
prod1,2,3에 접근, 마지막 build()메서드를 이용해서 TestVO의 3가지 변수들에게 값을 하나하나 담아준다.
이렇게 빌더를 이용해서 사용할 수 잇다.
다만 setter가 없기 때문에 한번 선언한 값을 변경할 수 없다.
**** 참고 ****
lombok 라이브러리를 이용하면 훨씬 편하게 작성할 수 있다.
lombok의 설명을 읽어보면 이러한 경우를 위해 사용법까지 자세하게 나와있다.
이 네가지만 작성해 주면
변수 세가지만 작성해도 lombok이 알아서 builder를 만들어 준다.
Builder 는 모든 변수를 받는 생성자를 필요로 한다.
하지만 새로운 객체를 생성할 때(new 할때) 기본 생성자가 필요함.
그래서 NOARGSCONSTRUCTOR를 사용
하지만 오류남.
그러면 ALLARGSCONSTRUCTOR 만들어서 사용하면 됨.
Uploaded by Notion2Tistory v1.1.0