Skip to content

Commit 7d959db

Browse files
committed
feat: Add builder pattern
1 parent 0a1a3ac commit 7d959db

File tree

3 files changed

+266
-0
lines changed

3 files changed

+266
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Builder Pattern (빌더 패턴)
2+
>
3+
4+
## 언제 적용할까?
5+
생성자 인자가 많을 때는 Builder Pattern 적용을 고려하라.
6+
7+
## 점층적 생성자 패턴 (telescoping constructor pattern)
8+
```java
9+
/* 모든 파라미터 생성 */
10+
public Person(final String firstName, final String lastName, final String phoneNumber, final String address, final String addressDetail, final Integer age, final String sex, final LocalDate birthDay) {
11+
this.firstName = firstName;
12+
this.lastName = lastName;
13+
this.phoneNumber = phoneNumber;
14+
this.address = address;
15+
this.addressDetail = addressDetail;
16+
this.age = age;
17+
this.sex = sex;
18+
this.birthDay = birthDay;
19+
}
20+
21+
/* firstName, lastName 으로 만 생성 */
22+
public Person(final String firstName, final String lastName) {
23+
this.firstName = firstName;
24+
this.lastName = lastName;
25+
}
26+
27+
```
28+
* 단점)
29+
* 선택적 매개변수가 많을 때 적절히 대응하기 어렵다.
30+
* 매개변수 개수가 많아지면 클라이언트 코드를 작성하거나 읽기 어렵다.
31+
* 각 값의 의미를 헷갈릴 수 있으며, 실수로 매개변수의 순서를 바꿔 건네주게 되면 컴파일 시 알아채지 못하고 런타임에 엉뚱하게 동작할 우려가 있다.
32+
33+
## 자바 빈즈 패턴 (javaBeans pattern)
34+
선택적 매개변수가 많을 댸 활용할 수 있는 대안.
35+
매개변수가 없는 생성자로 객체를 만들고 세터(setter) 메서드들을 호출하여 원하는 매개변수의 값을 설정하는 방식이다.
36+
37+
```java
38+
Person person = new Person();
39+
person.setFirstName(firstName);
40+
person.setLastName(lastName);
41+
person.setPhoneNumber(phoneNumber);
42+
person.setAddress(address);
43+
person.setAddressDetail(addressDetail);
44+
person.setAge(age);
45+
person.setSex(sex);
46+
person.setBirthDay(birthDay);
47+
48+
/* 필요한 데이터만 setter로 만든다. */
49+
person = new Person();
50+
person.setFirstName(firstName);
51+
person.setLastName(lastName);
52+
```
53+
* 장점)
54+
* 인스턴스를 만들기 쉽고, 점층적 생성자 패턴 보다는 코드를 읽기 쉽다.
55+
* 필요에 따른 다양한 생성자를 만들지 않아도 된다.
56+
* 단점)
57+
* 객체 하나를 만들기 위해서는 메서드를 여러개 호출해야하고, 객체가 완전히 생성되기 전까지는 일관성(consistency)이 무너진 상태에 놓인다.
58+
* 일관성이 깨진 객체가 만들어지면, 버그를 심은 코드와 그 버그 떄문에 런타임에 문제를 겪는 코드가... 디버깅이 어렵다!
59+
* 클래스를 불변으로 만들 수 없다.
60+
* 스레드 안전성을 얻으려면 추가 작업을 해야한다.
61+
62+
63+
## 빌더 패턴 (Effective Java 스타일)
64+
파이썬과 스칼라에 있는 명명된 선택적 매개변수 (named optional parameters)를 흉내낸 것으로,
65+
점층적 생성자 패턴의 안전성과 자바빈즈 패턴의 가독성을 겸비한 패턴.
66+
67+
```java
68+
final Person person1 = new Person
69+
.PersonBuilder("FirstName", "LastName", "01022223333", "Address", "AddressDetail", LocalDate.of(2001, 4, 16))
70+
.age(20)
71+
.sex("WOMAN")
72+
.build();
73+
```
74+
* 장점)
75+
* 각 클라이언트 코드는 읽고 쓰기 쉽다.
76+
* 점층적 생성자 패턴의 안전성과 자바빈즈 패턴의 가독성을 겸비
77+
78+
## 정리
79+
생성자나 정적 팩터리가 처리해야 할 매개변수가 많다면 빌더 패턴을 선택하는 것이 낫다.
80+
매개 변수 중 다수가 필수가 아니거나 같은 타입이면 특히 더 더욱!
81+
빌더 패턴은 점층적 생성자보다 클라이언트 코드를 읽고 쓰기가 훨씬 간결하고, 자바빈즈보다 훨씬 안전하다.
82+
83+
# Reference
84+
* [이펙티브 자바 3/E](http://www.yes24.com/Product/Goods/65551284) 아이템2. 생성자에 매개변수가 많다면 빌더를 고려하라.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package com.hyeonah.javalabs.designpattern.builderpattern.step1;
2+
3+
import java.time.LocalDate;
4+
5+
public class Person {
6+
private String firstName;
7+
private String lastName;
8+
private String phoneNumber;
9+
private String address;
10+
private String addressDetail;
11+
private Integer age;
12+
private String sex;
13+
private LocalDate birthDay;
14+
15+
// public Person(final String firstName, final String lastName, final String phoneNumber, final String address, final String addressDetail, final Integer age, final String sex, final LocalDate birthDay) {
16+
// this.firstName = firstName;
17+
// this.lastName = lastName;
18+
// this.phoneNumber = phoneNumber;
19+
// this.address = address;
20+
// this.addressDetail = addressDetail;
21+
// this.age = age;
22+
// this.sex = sex;
23+
// this.birthDay = birthDay;
24+
// }
25+
26+
// public Person(final String firstName, final String lastName) {
27+
// this.firstName = firstName;
28+
// this.lastName = lastName;
29+
// }
30+
31+
public String getFirstName() {
32+
return firstName;
33+
}
34+
35+
public void setFirstName(final String firstName) {
36+
this.firstName = firstName;
37+
}
38+
39+
public String getLastName() {
40+
return lastName;
41+
}
42+
43+
public void setLastName(final String lastName) {
44+
this.lastName = lastName;
45+
}
46+
47+
public String getPhoneNumber() {
48+
return phoneNumber;
49+
}
50+
51+
public void setPhoneNumber(final String phoneNumber) {
52+
this.phoneNumber = phoneNumber;
53+
}
54+
55+
public String getAddress() {
56+
return address;
57+
}
58+
59+
public void setAddress(final String address) {
60+
this.address = address;
61+
}
62+
63+
public String getAddressDetail() {
64+
return addressDetail;
65+
}
66+
67+
public void setAddressDetail(final String addressDetail) {
68+
this.addressDetail = addressDetail;
69+
}
70+
71+
public Integer getAge() {
72+
return age;
73+
}
74+
75+
public void setAge(final Integer age) {
76+
this.age = age;
77+
}
78+
79+
public String getSex() {
80+
return sex;
81+
}
82+
83+
public void setSex(final String sex) {
84+
this.sex = sex;
85+
}
86+
87+
public LocalDate getBirthDay() {
88+
return birthDay;
89+
}
90+
91+
public void setBirthDay(final LocalDate birthDay) {
92+
this.birthDay = birthDay;
93+
}
94+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package com.hyeonah.javalabs.designpattern.builderpattern.step2;
2+
3+
import java.time.LocalDate;
4+
5+
public class Person {
6+
private final String firstName;
7+
private final String lastName;
8+
private final String phoneNumber;
9+
private final String address;
10+
private final String addressDetail;
11+
private final Integer age;
12+
private final String sex;
13+
private final LocalDate birthDay;
14+
15+
private Person(final PersonBuilder builder) {
16+
firstName = builder.firstName;
17+
lastName = builder.lastName;
18+
phoneNumber = builder.phoneNumber;
19+
address = builder.address;
20+
addressDetail = builder.addressDetail;
21+
age = builder.age;
22+
sex = builder.sex;
23+
birthDay = builder.birthDay;
24+
}
25+
26+
public String getFirstName() {
27+
return firstName;
28+
}
29+
30+
public String getAddress() {
31+
return address;
32+
}
33+
34+
public Integer getAge() {
35+
return age;
36+
}
37+
38+
public String getSex() {
39+
return sex;
40+
}
41+
42+
public static class PersonBuilder {
43+
/**
44+
* required parameters
45+
*/
46+
private final String firstName;
47+
private final String lastName;
48+
private final String phoneNumber;
49+
private final String address;
50+
private final String addressDetail;
51+
private final LocalDate birthDay;
52+
53+
/**
54+
* optional parameters
55+
* initialized to default values(선택적 인자는 기본값으로 초기화)
56+
*/
57+
private Integer age = 0;
58+
private String sex = "MAN";
59+
60+
public PersonBuilder(final String firstName,
61+
final String lastName,
62+
final String phoneNumber,
63+
final String address,
64+
final String addressDetail,
65+
final LocalDate birthDay) {
66+
this.firstName = firstName;
67+
this.lastName = lastName;
68+
this.phoneNumber = phoneNumber;
69+
this.address = address;
70+
this.addressDetail = addressDetail;
71+
this.birthDay = birthDay;
72+
}
73+
74+
public PersonBuilder age(final Integer age) {
75+
this.age = age;
76+
return this;
77+
}
78+
79+
public PersonBuilder sex(final String sex) {
80+
this.sex = sex;
81+
return this;
82+
}
83+
84+
public Person build() {
85+
return new Person(this);
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)