π λΉλ(Builder) ν¨ν΄ - μλ²½ λ§μ€ν°νκΈ°
Builder Pattern
λΉλ ν¨ν΄(Builder Pattern)μ 볡μ‘ν κ°μ²΄μ μμ± κ³Όμ κ³Ό νν λ°©λ²μ λΆλ¦¬νμ¬ λ€μν ꡬμ±μ μΈμ€ν΄μ€λ₯Ό λ§λλ μμ± ν¨ν΄μ΄λ€. μμ±μμ λ€μ΄κ° λ§€κ° λ³μλ₯Ό λ©μλλ‘ νλνλ λ°μλ€μ΄κ³ λ§μ§λ§μ ν΅ν© λΉλν΄μ κ°μ²΄λ₯Ό μμ±νλ λ°©μμ΄λ€.
μ΄ν΄νκΈ° μ¬μ΄ μ¬λ‘λ‘ μμ νλ²κ±°λ₯Ό λ€ μ μλ€. μμ νλ²κ±°λ₯Ό μ£Όλ¬Έν λ λΉ΅μ΄λ ν¨ν° λ± μμ¬λ£λ€μ μ£Όλ¬Ένλ μ¬λμ΄ λ§μλλ‘ κ²°μ λλ€. μ΄λ μ¬λμ μΉμ¦λ₯Ό λΉΌλ¬λΌκ³ ν μ μκ³ μ΄λ μ¬λμ ν λ§ν λ₯Ό λΉΌλ¬λΌκ³ ν μ μλ€. μ΄μ²λΌ μ νμ μμ¬λ£λ€μ λ³΄λ€ μ μ°νκ² λ°μ λ€μν νμ μ μΈμ€ν΄μ€λ₯Ό μμ±ν μ μμ΄, ν΄λμ€μ μ νμ 맀κ°λ³μκ° λ§μ μν©μμ μ μ©νκ² μ¬μ©λλ€.
λΉλ ν¨ν΄ νμ λ°°κ²½
μ μΈ΅μ μμ±μ ν¨ν΄
μ μΈ΅μ μμ±μ ν¨ν΄(Telescoping Constructor Pattern)μ νμ 맀κ°λ³μμ ν¨κ» μ ν 맀κ°λ³μλ₯Ό 0κ°, 1κ°, 2κ° .. λ°λ ννλ‘, μ°λ¦¬κ° λ€μν 맀κ°λ³μλ₯Ό μ λ ₯λ°μ μΈμ€ν΄μ€λ₯Ό μμ±νκ³ μΆμλ μ¬μ©νλ μμ±μλ₯Ό μ€λ²λ‘λ© νλ λ°©μμ΄λ€.
class Hamburger {
// νμ 맀κ°λ³μ
private int bun;
private int patty;
// μ ν 맀κ°λ³μ
private int cheese;
private int lettuce;
private int tomato;
private int bacon;
public Hamburger(int bun, int patty, int cheese, int lettuce, int tomato, int bacon) {
this.bun = bun;
this.patty = patty;
this.cheese = cheese;
this.lettuce = lettuce;
this.tomato = tomato;
this.bacon = bacon;
}
public Hamburger(int bun, int patty, int cheese, int lettuce, int tomato) {
this.bun = bun;
this.patty = patty;
this.cheese = cheese;
this.lettuce = lettuce;
this.tomato = tomato;
}
public Hamburger(int bun, int patty, int cheese, int lettuce) {
this.bun = bun;
this.patty = patty;
this.cheese = cheese;
this.lettuce = lettuce;
}
public Hamburger(int bun, int patty, int cheese) {
this.bun = bun;
this.patty = patty;
this.cheese = cheese;
}
...
}
public static void main(String[] args) {
// λͺ¨λ μ¬λ£κ° μλ νλ²κ±°
Hamburger hamburger1 = new Hamburger(2, 1, 2, 4, 6, 8);
// λΉ΅κ³Ό ν¨ν° μΉμ¦λ§ μλ νλ²κ±°
Hamburger hamburger2 = new Hamburger(2, 1, 1);
// λΉ΅κ³Ό ν¨ν° λ² μ΄μ»¨λ§ μλ νλ²κ±°
Hamburger hamburger3 = new Hamburger(2, 0, 0, 0, 0, 6);
}
νμ§λ§ μ΄λ¬ν λ°©μμ ν΄λμ€ μΈμ€ν΄μ€ νλλ€μ΄ λ§μΌλ©΄ λ§μ μλ‘ μμ±μμ λ€μ΄κ° μΈμμ μκ° λμ΄λ λͺλ²μ§Έ μΈμκ° μ΄λ€ νλμλμ§ νκ°λ¦΄ κ²½μ°κ° μκΈ°κ² λλ€. λ§μΌ μ¬λ¬ μ’ λ₯μ νλ²κ±°λ₯Ό μμ±νκΈ° μν΄ Hamburger μμ±μμ λͺλ²μ§Έ μΈμκ° μμμΆμ κ°―μμΈμ§ ν λ§ν μ κ°―μμΈμ§ νμ ν νμκ° μλ€.
λν 맀κ°λ³μ νΉμ±μ μμλ₯Ό λ°λΌμΌ νκΈ° λλ¬Έμ μμ 'λΉ΅κ³Ό λ² μ΄μ»¨λ§ μλ νλ²κ±°'λ₯Ό μν κ²½μ° μ΅μ§λ‘ νλΌλ―Έν°μ 0μ μ λ¬ν΄μΌ λλ€. μμ±μλ‘λ§μΌλ‘λ νλλ₯Ό μ νμ μΌλ‘ μλ΅ν μ μλ λ°©λ²μ΄ μκΈ° λλ¬Έμ΄λ€.
κ·Έλ¦¬κ³ λ¬΄μλ³΄λ€ νμ μ΄ λ€μν μλ‘ μμ±μ λ©μλ μκ° κΈ°νκΈμμ μΌλ‘ λμ΄λ κ°λ μ±μ΄λ μ μ§λ³΄μ μΈ‘λ©΄μμ μ’μ§ μλ€.
μλ° λΉ(Java Beans) ν¨ν΄
μ΄λ¬ν λ¨μ μ 보μνκΈ° μν΄ Setter λ©μλλ₯Ό μ¬μ©ν μλ° λΉ(Bean) ν¨ν΄μ΄ κ³ μ λμλ€. 맀κ°λ³μκ° μλ μμ±μλ‘ κ°μ²΄ μμ±ν Setter λ©μλλ₯Ό μ΄μ©ν΄ ν΄λμ€ νλμ μ΄κΉκ°μ μ€μ νλ λ°©μμ΄λ€.
class Hamburger {
// νμ 맀κ°λ³μ
private int bun;
private int patty;
// μ ν 맀κ°λ³μ
private int cheese;
private int lettuce;
private int tomato;
private int bacon;
public Hamburger() {}
public void setBun(int bun) {
this.bun = bun;
}
public void setPatty(int patty) {
this.patty = patty;
}
public void setCheese(int cheese) {
this.cheese = cheese;
}
public void setLettuce(int lettuce) {
this.lettuce = lettuce;
}
public void setTomato(int tomato) {
this.tomato = tomato;
}
public void setBacon(int bacon) {
this.bacon = bacon;
}
}
public static void main(String[] args) {
// λͺ¨λ μ¬λ£κ° μλ νλ²κ±°
Hamburger hamburger1 = new Hamburger();
hamburger1.setBun(2);
hamburger1.setPatty(1);
hamburger1.setCheese(2);
hamburger1.setLettuce(4);
hamburger1.setTomato(6);
hamburger1.setBacon(8);
// λΉ΅κ³Ό ν¨ν° μΉμ¦λ§ μλ νλ²κ±°
Hamburger hamburger2 = new Hamburger();
hamburger2.setBun(2);
hamburger2.setPatty(1);
hamburger2.setCheese(2);
// λΉ΅κ³Ό ν¨ν° λ² μ΄μ»¨λ§ μλ νλ²κ±°
Hamburger hamburger3 = new Hamburger();
hamburger3.setBun(2);
hamburger2.setPatty(1);
hamburger3.setBacon(8);
}
κΈ°μ‘΄ μμ±μ μ€λ²λ‘λ©μμ λνλ¬λ κ°λ μ± λ¬Έμ μ μ΄ μ¬λΌμ§κ³ μ νμ μΈ νλΌλ―Έν°μ λν΄ ν΄λΉλλ Setter λ©μλλ₯Ό νΈμΆν¨μΌλ‘μ¨ μ μ°μ μΌλ‘ κ°μ²΄ μμ±μ΄ κ°λ₯ν΄μ‘λ€. νμ§λ§ μ΄λ¬ν λ°©μμ κ°μ²΄ μμ± μμ μ λͺ¨λ κ°λ€μ μ£Όμ νμ§ μμ μΌκ΄μ±(consistency) λ¬Έμ μ λΆλ³μ±(immutable) λ¬Έμ κ° λνλκ² λλ€.
1) μΌκ΄μ± λ¬Έμ
νμ 맀κ°λ³μλ κ°μ²΄κ° μ΄κΈ°νλ λ λ°λμ μ€μ λμ΄μΌ νλ κ°μ΄λ€. νμ§λ§ κ°λ°μκ° κΉλΉ‘νκ³ setBun() μ΄λ setPatty() λ©μλλ₯Ό νΈμΆνμ§ μμλ€λ©΄ μ΄ κ°μ²΄λ μΌκ΄μ±μ΄ 무λμ§ μνκ° λλ€. μ¦, κ°μ²΄κ° μ ν¨νμ§ μμ κ²μ΄λ€. λ§μΌ λ€λ₯Έκ³³μμ νλ²κ±° μΈμ€ν΄μ€λ₯Ό μ¬μ©νκ² λλ€λ©΄ λ°νμ μμΈκ° λ°μν μλ μλ€.
μ΄λ κ°μ²΄λ₯Ό μμ±νλ λΆλΆκ³Ό κ°μ μ€μ νλ λΆλΆμ΄ 물리μ μΌλ‘ λ¨μ΄μ Έ μμ΄μ λ°μνλ λ¬Έμ μ μ΄λ€. λ¬Όλ‘ μ΄λ μ΄λμ λ μμ±μ(Constructor)μ κ²°ν©νμ¬ κ·Ήλ³΅μ ν μ μλ€. νμ§λ§ λ€μμ μκ°ν λΆλ³μ±μ λ¬Έμ λλ¬Έμ μλ° λΉμ¦ ν¨ν΄μ μ§μν΄μΌ νλ€.
2) λΆλ³μ± λ¬Έμ
μλ° λΉμ¦ ν¨ν΄μ Setter λ©μλλ κ°μ²΄λ₯Ό μ²μ μμ±ν λ νλκ°μ μ€μ νκΈ° μν΄ μ‘΄μ¬νλ λ©μλμ΄λ€. νμ§λ§ κ°μ²΄λ₯Ό μμ±νμμλ μ¬μ ν μΈλΆμ μΌλ‘ Setter λ©μλλ₯Ό λ ΈμΆνκ³ μμΌλ―λ‘, νμ κ³Όμ μμ μΈμ μ΄λμ λκ΅°κ° Setter λ©μλλ₯Ό νΈμΆν΄ ν¨λΆλ‘ κ°μ²΄λ₯Ό μ‘°μν μ μκ² λλ€. μ΄κ²μ λΆλ³ν¨μ 보μ₯ν μ μλ€κ³ μκΈ°νλ€.
λ§μΉ μμ±λ νλ²κ±°μ μ€κ°μ μΉμ¦λ₯Ό κ΅μ²΄νλ€κ³ νλ²κ±°λ₯Ό λ§ λΆλ¦¬νλ κ²κ³Ό κ°μ μ΄μΉμ΄λ€ (μ λ§ λ¨μ΄μ§κ²)
λΉλ(Builder) ν¨ν΄
λΉλ ν¨ν΄μ μ΄λ¬ν λ¬Έμ λ€μ ν΄κ²°νκΈ° μν΄ λ³λμ Builder ν΄λμ€λ₯Ό λ§λ€μ΄ λ©μλλ₯Ό ν΅ν΄ step-by-step μΌλ‘ κ°μ μ
λ ₯λ°μ νμ μ΅μ’
μ μΌλ‘ build() λ©μλλ‘ νλμ μΈμ€ν΄μ€λ₯Ό μμ±νμ¬ λ¦¬ν΄νλ ν¨ν΄μ΄λ€.
λΉλ ν¨ν΄ μ¬μ©λ²μ μ μ μ΄ν΄λ³΄λ©΄, StudentBuilder λΉλ ν΄λμ€μ λ©μλλ₯Ό 체μ΄λ(Chaining) ννλ‘ νΈμΆν¨μΌλ‘μ¨ μμ°μ€λ½κ² μΈμ€ν΄μ€λ₯Ό ꡬμ±νκ³ λ§μ§λ§μ build() λ©μλλ₯Ό ν΅ν΄ μ΅μ’
μ μΌλ‘ κ°μ²΄λ₯Ό μμ±νλλ‘ λμ΄μμμ λ³Ό μ μλ€.
public static void main(String[] args) {
// μμ±μ λ°©μ
Hamburger hamburger = new Hamburger(2, 3, 0, 3, 0, 0);
// λΉλ λ°©μ
Hamburger hamburger = new Hamburger.Builder(10)
.bun(2)
.patty(3)
.lettuce(3)
.build();
}
λΉλ ν¨ν΄μ μ΄μ©νλ©΄ λμ΄μ μμ±μ μ€λ²λ‘λ© μ΄κ±°λ₯Ό νμ§ μμλ λλ©°, λ°μ΄ν°μ μμμ μκ΄μμ΄ κ°μ²΄λ₯Ό λ§λ€μ΄λ΄ μμ±μ μΈμ μμλ₯Ό νμ ν νμλ μκ³ μλͺ»λ κ°μ λ£λ μ€μλ νμ§ μκ² λλ€. μ μΈ΅μ μμ±μ ν¨ν΄κ³Ό μλ°λΉμ¦ ν¨ν΄ λ κ°μ§μ μ₯μ λ§μ μ·¨νμλ€κ³ λ³Ό μ μλ€.
λΉλ ν¨ν΄ ꡬ쑰
λΉλ ν¨ν΄ ꡬν μ체λ λμ΄λκ° μ΄λ ΅μ§ μμΌλ λΉ λ₯΄κ³ μ½κ² ꡬμ±μ΄ κ°λ₯νλ€.
μλ₯Όλ€μ΄ λ€μκ³Ό κ°μ Student ν΄λμ€μ λν κ°μ²΄ μμ±λ§μ λ΄λΉνλ λ³λμ λΉλ ν΄λμ€λ₯Ό λ§λ€λ €κ³ νλ€.
class Student {
private int id;
private String name = "μ무κ°";
private String grade = "freshman";
private String phoneNumber = "010-0000-0000";
public Student(int id, String name, String grade, String phoneNumber) {
this.id = id;
this.name = name;
this.grade = grade;
this.phoneNumber = phoneNumber;
}
@Override
public String toString() {
return "Student { " +
"id='" + id + '\'' +
", name=" + name +
", grade=" + grade +
", phoneNumber=" + phoneNumber +
" }";
}
}
λΉλ ν΄λμ€ κ΅¬ννκΈ°
λ¨Όμ Builder ν΄λμ€λ₯Ό λ§λ€κ³ νλ λ©€λ² κ΅¬μ±μ λ§λ€κ³ μ νλ Student ν΄λμ€ λ©€λ² κ΅¬μ±κ³Ό λκ°μ΄ ꡬμ±νλ€.
class StudentBuilder {
private int id;
private String name;
private String grade;
private String phoneNumber;
}
κ·Έλ¦¬κ³ κ° λ§΄λ²μλν Setter λ©μλλ₯Ό ꡬνν΄μ€λ€. μ΄λ κ°λ μ±μ μ’κ² νλ©΄μλ κΈ°μ‘΄ Setterμμ λ€λ₯Έ νΉμ±μ κ°μ§κ³ μλ μ μ μ리기 μν΄μ, set λ¨μ΄λ λΉΌμ£Όκ³ μ¬ννκ² λ©€λ²μ΄λ¦μΌλ‘λ§ λ©μλλͺ μ μ§μ΄μ€λ€.
class StudentBuilder {
private int id;
private String name;
private String grade;
private String phoneNumber;
public StudentBuilder id(int id) {
this.id = id;
return this;
}
public StudentBuilder name(String name) {
this.name = name;
return this;
}
public StudentBuilder grade(String grade) {
this.grade = grade;
return this;
}
public StudentBuilder phoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
return this;
}
}
μ¬κΈ°μ μ£Όλͺ©ν λΆλΆμ κ° Setter ν¨μ λ§μ§λ§ λ°ν κ΅¬λ¬ΈμΈ return this λΆλΆμ΄λ€. μ¬κΈ°μ thisλ StudentBuilder κ°μ²΄ μμ μ λ§νλ€. μ¦, λΉλ κ°μ²΄ μμ μ 리ν΄ν¨μΌλ‘μ¨ λ©μλ νΈμΆ ν μ°μμ μΌλ‘ λΉλ λ©μλλ€μ 체μ΄λ(Chaining) νμ¬ νΈμΆν μ μκ² λλ€. ex) new StudentBuilder().id(κ°).name(κ°)
λ§μ§λ§μΌλ‘ λΉλμ λͺ©νμλ μ΅μ’
Student κ°μ²΄λ₯Ό λ§λ€μ΄μ£Όλ build λ©μλλ₯Ό ꡬμ±ν΄μ€λ€. λΉλ ν΄λμ€μ νλλ€μ Student μμ±μμ μΈμμ λ£μ΄μ€μΌλ‘μ¨ λ©€λ² κ΅¬μ±μ΄ μλ£λ Student μΈμ€ν΄μ€λ₯Ό μ»κ² λλ κ²μ΄λ€.
class StudentBuilder {
private int id;
private String name;
private String grade;
private String phoneNumber;
public StudentBuilder id(int id) { ... }
public StudentBuilder name(String name) { ... }
public StudentBuilder grade(String grade) { ... }
public StudentBuilder phoneNumber(String phoneNumber) { ... }
public Student build() {
return new Student(id, name, grade, phoneNumber); // Student μμ±μ νΈμΆ
}
}
λΉλ ν΄λμ€ μ€ννκΈ°
μ΄λ κ² κ΅¬μ±ν λΉλ κ°μ²΄λ₯Ό μ€ννλ©΄ μλμ κ°μ μ±μ§μ μ½λκ° κ΅¬νλκ² λλ€.
public static void main(String[] args) {
Student student = new StudentBuilder()
.id(2016120091)
.name("μκΊ½μ ")
.grade("Senior")
.phoneNumber("010-5555-5555")
.build();
System.out.println(student);
}
λΉλ ν¨ν΄ λ€μ΄λ° νμ
λΉλ ν¨ν΄μ λ©€λ² μ€μ λ©μλ λ€μ΄λ° λ°©μμλ λνμ μΌλ‘ 3κ°μ§ μ λ μ‘΄μ¬νλ€.
- λ©€λ²μ΄λ¦()
- setλ©€λ²μ΄λ¦()
- withλ©€λ²μ΄λ¦()
Student student = new StudentBuilder(2016120091)
.name("νκΈΈλ")
.grade("freshman")
.phoneNumber("010-5555-5555")
.build();
Student student = new StudentBuilder(2016120091)
.setName("νκΈΈλ")
.setGrade("freshman")
.setPhoneNumber("010-5555-5555")
.build();
Student student = new StudentBuilder(2016120091)
.withName("νκΈΈλ")
.withGrade("freshman")
.withPhoneNumber("010-5555-5555")
.build();
μ΄μ€ κ·Έλ₯ λ©€λ²μ΄λ¦μΌλ‘λ§ λ©μλλͺ μ μ§λ 첫λ²μ§Έ λ€μ΄λ° λ°©μμ΄ μΆμ²λμ΄μ§λ€.
λλ²μ§Έ λ€μ΄λ° λ°©μμ μ ν΅μ μΈ μλ°(Java) μ€λ¬μ΄ λ€μ΄λ° νμμΈλ° μΌλ° Setter λ©μλμ νκΉλ¦΄ μμ§κ° μλ€.
μΈλ²μ§Έλ Setterμ ꡬλΆν€ μν΄ 'with' λΌλ ν€μλλ₯Ό μ¬μ©νκ²μ΄λ©°, λΉλ μ§μ° μμ± λ°©μμμ 미리 λΉλλ₯Ό μ€μ ν λ μ°μ΄κΈ°λ νλ€.
Builder ν¨ν΄ μ₯λ¨μ μ΄μ 리
λΉλ ν¨ν΄ μ₯μ
1. κ°μ²΄ μμ± κ³Όμ μ μΌκ΄λ νλ‘μΈμ€λ‘ νν
μμ±μ λ°©μμΌλ‘ κ°μ²΄λ₯Ό μμ±νλ κ²½μ°λ 맀κ°λ³μκ° λ§μμ§μλ‘ κ°λ μ±μ΄ κΈκ²©νκ² λ¨μ΄μ§λ€. ν΄λμ€ λ³μκ° 4κ° μ΄μλ§ λμ΄λ κ° μΈμ μμ λ§λ€ μ΄ κ°μ΄ μ΄λ€ λ©€λ²μ ν΄λΉλλμ§ λ°λ‘ νμ μ΄ νλ€λ€.
λ°λ©΄ λ€μκ³Ό κ°μ΄ λΉλ ν¨ν΄μ μ μ©νλ©΄ μ§κ΄μ μΌλ‘ μ΄λ€ λ°μ΄ν°μ μ΄λ€ κ°μ΄ μ€μ λλμ§ νλμ νμ ν μ μκ² λλ€. νΉν μ°μλ λμΌ νμ μ λ§€κ° λ³μλ₯Ό λ§μ΄ μ€μ ν κ²½μ°μ λ°μν μ μλ μ€μ μ€λ₯μ κ°μ μ€μλ₯Ό λ°©μ§ν μ μλ€.
// μμ±μ λ°©μ
Student student1 = new Student(2016120091, "νκΈΈλ", "freshman", "010-5555-5555");
// λΉλ λ°©μ
Student student2 = new StudentBuilder()
.id(2016120091)
.name("μκΊ½μ ")
.grade("Senior")
.phoneNumber("010-5555-5555")
.build();
λ€λ§ λΉλ ν¨ν΄μ΄ νμνκ²λ μ μλμ λ¬λ¦¬, μμ¦μλ μΈν 리μ μ΄λ μ΄ν΄λ¦½μ€ κ°μ μ λ§ν IDEμμ μλμ κ°μ΄ μμ±μ 맀κ°λ³μμ λν 미리보기 ννΈ κΈ°λ₯μ μ 곡ν΄μ£ΌκΈ° λλ¬Έμ μ΄ λΆλΆμ μμ¦ νΈλ λμλ λ§μ§ μμ μλ μλ€.
2. λν΄νΈ 맀κ°λ³μ μλ΅μ κ°μ μ μΌλ‘ μ§μ
λ³Έλ λν΄νΈ 맀κ°λ³μλΌλ 건 μΈμ κ°μ μ€μ ν΄μ€λ λκ³ μ€μ μνκ³ μλ΅ν΄λ λλκ²μ λ§νλ€. κ·Έλ°λ° νμ΄μ¬μ΄λ μλ°μ€ν¬λ¦½νΈμ λ¬λ¦¬ μλ° μΈμ΄μμ κΈ°λ³Έμ μΌλ‘ λ©μλμ λν λν΄νΈ 맀κ°λ³μλ₯Ό μ§μνμ§ μλλ€.
λ°λΌμ λν΄νΈ 맀κ°λ³μλ₯Ό ꡬννκΈ° μν΄μ ν΄λμ€ νλ λ³μμ μ΄κΉκ°μ 미리 μΈν νκ³ , μ΄κΉκ°μ΄ μΈν λ νλ μΈμλ₯Ό μ μΈμν¨ μμ±μλ₯Ό λ°λ‘ ꡬννλ μμΌλ‘ μ€κ³ν΄μΌ νλ€. νμ§λ§ μ΄λ κ²°κ΅ μ§λμΉ μμ±μ μ€λ²λ‘λ© μ΄κ±°λ₯Ό ν΅ν λ³Έλμ λ¬Έμ μ μ νκ·ν κΌ΄μ΄ λλ€.
class Student {
private int id;
private String name;
private String grade = "freshman"; // λν΄νΈ 맀κ°λ³μ μν
private String phoneNumber;
public Student(int id, String name, String grade, String phoneNumber) {
...
}
// λν΄νΈ 맀κ°λ³μλ₯Ό μ μΈν μΈμλ€μ λ°λ μμ±μ μ€λ²λ‘λ©
public Student(int id, String name, String phoneNumber) {
...
}
@Override
public String toString() {
return "Student { " +
"id='" + id + '\'' +
", name=" + name +
", grade=" + grade +
", phoneNumber=" + phoneNumber +
" }";
}
}
λΉλ ν¨ν΄μμλ λν΄νΈ 맀κ°λ³μλ₯Ό ꡬννλ λ°©λ²μ λκ°λ€. λ€λ§ λΉλλΌλ κ°μ²΄ μμ± μ μ© ν΄λμ€λ₯Ό κ²½μ νμ¬ μ΄μ©ν¨μΌλ‘μ¨ λν΄νΈ 맀κ°λ³μκ° μ€μ λ νλλ₯Ό μ€μ νλ λ©μλλ₯Ό νΈμΆνμ§ μλ λ°©μμΌλ‘ λ§μΉ λν΄νΈ 맀κ°λ³μλ₯Ό μλ΅νκ³ νΈμΆνλ ν¨κ³Όλ₯Ό κ°μ μ μΌλ‘ ꡬνν μ μκ² λλ€.
class StudentBuilder {
private int id;
private String name;
private String grade = "freshman"; // λν΄νΈ 맀κ°λ³μ μν
private String phoneNumber;
...
}
// λν΄νΈ νλμΈ gradeλ₯Ό μ μΈνκ³ λΉλ κ΅¬μ± λ° μΈμ€ν΄μ€ν
Student student1 = new StudentBuilder(2016120091)
.name("νκΈΈλ")
.phoneNumber("010-5555-5555")
.build();
System.out.println(student1);
3. νμ λ©€λ²μ μ νμ λ©€λ²λ₯Ό λΆλ¦¬ κ°λ₯
κ°μ²΄ μΈμ€ν΄μ€λ λͺ©μ μ λ°λΌ μ΄κΈ°νκ° νμμΈ λ©€λ² λ³μκ° μκ³ μ νμ μΈ λ©€λ² λ³μκ° μμ μ μλ€.
λ§μΌ Student ν΄λμ€μ id νλκ° μΈμ€ν΄μ€ν ν λ λ°λμ νμμ μΌλ‘ κ°μ μ§μ ν΄ μ£Όμ΄μΌ νλ νμ λ©€λ² λ³μλΌκ³ κ°μ ν΄λ³΄μ. μ΄λ₯Ό κΈ°μ‘΄ μμ±μ λ°©μμΌλ‘ ꡬννλ €λ©΄ μ΄κΈ°νκ° νμμΈ λ©€λ² λ³μλ§μ μν μμ±μλ₯Ό μ μνκ³ μ νμ μΈ λ©€λ² λ³μμ λμνλ μμ±μλ₯Ό μ€λ²λ‘λ©μ ν΅ν΄ μ΄κ±°νκ±°λ, νΉμ μ 체 λ©€λ²λ₯Ό μΈμλ‘ λ°λ μμ±μλ§μ μ μΈνκ³ λ§€κ°λ³μμ nullμ λ°λμμΌλ‘ ꡬμ±νμ¬μΌ νλ€.
class Student {
// μ΄κΈ°ν νμ λ©€λ²
private int id;
// μ΄κΈ°ν μ νμ λ©€λ²
private String name;
private String grade;
private String phoneNumber;
public Student(int id, String name, String grade, String phoneNumber) {
this.id = id;
this.name = name;
this.grade = grade;
this.phoneNumber = phoneNumber;
}
}
Student student = new Student(2010234455, null, null, null);
μ΄λ νλμ λ΄λ λ³λ‘ μ’μ§ μμ λ°©λ²μμ μμ μμ κ²μ΄λ€.
λ°λΌμ λΉλ ν΄λμ€λ₯Ό ν΅ν΄ μ΄κΈ°νκ° νμμΈ λ©€λ²λ λΉλμ μμ±μλ‘ λ°κ² νμ¬ νμ λ©€λ²λ₯Ό μ€μ ν΄μ£Όμ΄μΌ λΉλ κ°μ²΄κ° μμ±λλλ‘ μ λνκ³ , μ νμ μΈ λ©€λ²λ λΉλμ λ©μλλ‘ λ°λλ‘ νλ©΄, μ¬μ©μλ‘ νμ¬κΈ νμ λ©€λ²μ μ ν λ©€λ²λ₯Ό ꡬλΆνμ¬ κ°μ²΄ μμ±μ μ λν μ μλ€.
class StudentBuilder {
// μ΄κΈ°ν νμ λ©€λ²
private int id;
// μ΄κΈ°ν μ νμ λ©€λ²
private String name;
private String grade;
private String phoneNumber;
// νμ λ©€λ²λ λΉλμ μμ±μλ₯Ό ν΅ν΄ μ€μ
public StudentBuilder(int id) {
this.id = id;
}
// λλ¨Έμ§ μ ν λ©€λ²λ λ©μλλ‘ μ€μ
public StudentBuilder name(String name) {
this.name = name;
return this;
}
public StudentBuilder grade(String grade) {
this.grade = grade;
return this;
}
public StudentBuilder phoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
return this;
}
public Student build() {
return new Student(id, name, grade, phoneNumber);
}
}
Student student1 =
new StudentBuilder(2016120091) // νμ λ©€λ²
.name("νκΈΈλ") // μ ν λ©€λ²
.build();
Student student2 =
new StudentBuilder(2016120091) // νμ λ©€λ²
.name("μκΊ½μ ") // μ ν λ©€λ²
.grade("freshman") // μ ν λ©€λ²
.build();
Student student3 =
new StudentBuilder(2016120091) // νμ λ©€λ²
.name("μ£Όλͺ½") // μ ν λ©€λ²
.grade("Senior") // μ ν λ©€λ²
.phoneNumber("010-5555-5555") // μ ν λ©€λ²
.build();
4. κ°μ²΄ μμ± λ¨κ³λ₯Ό μ§μ°ν μ μμ
κ°μ²΄ μμ±μ λ¨κ³λ³λ‘ ꡬμ±νκ±°λ κ΅¬μ± λ¨κ³λ₯Ό μ§μ°νκ±°λ μ¬κ·μ μΌλ‘ μμ±μ μ²λ¦¬ ν μ μλ€. μ¦, λΉλλ₯Ό μ¬μ¬μ© ν¨μΌλ‘μ¨ κ°μ²΄ μμ±μ μ£Όλμ μΌλ‘ μ§μ°ν μ μλ κ²μ΄λ€.
// 1. λΉλ ν΄λμ€ μ μ© λ¦¬μ€νΈ μμ±
List<StudentBuilder> builders = new ArrayList<>();
// 2. κ°μ²΄λ₯Ό μ΅μ’
μμ± νμ§λ§κ³ μ΄κΉκ°λ§ μΈν
ν λΉλλ§ μμ±
builders.add(
new StudentBuilder(2016120091)
.name("νκΈΈλ")
);
builders.add(
new StudentBuilder(2016120092)
.name("μκΊ½μ ")
.grade("senior")
);
builders.add(
new StudentBuilder(2016120093)
.name("λ°νκ±°μΈ")
.grade("sophomore")
.phoneNumber("010-5555-5555")
);
// 3. λμ€μ λΉλ 리μ€νΈλ₯Ό μννμ¬ μ΅μ’
κ°μ²΄ μμ±μ μ£Όλ
for(StudentBuilder b : builders) {
Student student = b.build();
System.out.println(student);
}
6. μ΄κΈ°ν κ²μ¦μ λ©€λ²λ³λ‘ λΆλ¦¬
λ§μΌ μμ±μλ‘ λΆν° λ©€λ²κ°μ λ°λ ννλΌλ©΄, κ° μμ±μ 맀κ°λ³μμ λν κ²μ¦ λ‘μ§μ μμ±μ λ©μλ λ§λ€ 볡μ‘νκ² κ΅¬ννμ¬μΌ νλ€. μ΄λ μμ±μμ ν¬κΈ°κ° λΉλν΄μ§κ² λλ κ²°κ³Όλ₯Ό λ³κ² λλ€.
class Student {
...
// κ° λ§€κ°λ³μμ λν κ²μ¦μ νλμ μμ±μ λͺ¨λ μ²λ¦¬νκ³ μλ€
public Student(int id, String name, String grade, String phoneNumber) {
if (!grade.equals("freshman") && !grade.equals("sophomore") && !grade.equals("junior") && !grade.equals("senior")) {
throw new IllegalArgumentException(grade);
}
if (!phoneNumber.startsWith("010")) {
throw new IllegalArgumentException(phoneNumber);
}
this.id = id;
this.name = name;
this.grade = grade;
this.phoneNumber = phoneNumber;
}
}
λΉλλ₯Ό μ΄μ©νλ©΄ μμ±λ κ°μ²΄μ λ©€λ² λ³μμ μ΄κΈ°νμ κ²μ¦μ κ°κ°μ λ©€λ²λ³λ‘ λΆλ¦¬ν΄μ μμ±ν μ μλ€. λΉλμ κ°κ°μλ©€λ² μ€μ λ©μλμμ κ²μ¦ κ³Όμ μ λΆλ΄ν¨μΌλ‘μ¨ μ μ§ λ³΄μλ₯Ό μ©μ΄νκ² νλ κ²μ΄λ€.
class StudentBuilder {
...
public StudentBuilder(int id) {
this.id = id;
}
public StudentBuilder name(String name) {
this.name = name;
return this;
}
public StudentBuilder grade(String grade) {
if (!grade.equals("freshman") && !grade.equals("sophomore") && !grade.equals("junior") && !grade.equals("senior")) {
throw new IllegalArgumentException(grade);
}
this.grade = grade;
return this;
}
public StudentBuilder phoneNumber(String phoneNumber) {
if (!phoneNumber.startsWith("010")) {
throw new IllegalArgumentException(phoneNumber);
}
this.phoneNumber = phoneNumber;
return this;
}
public Student build() {
return new Student(id, name, grade, phoneNumber);
}
}
λ¬Όλ‘ μ΄λ¬ν νμμ νν Getter & Setter νμμμλ λ§μ΄ μ΄μ©λλ ν¨ν΄μ΄κΈ°λ νλ€. νμ§λ§ μ΄λ ν΄λμ€μ Setter λ©μλλ₯Ό ꡬννλ€λ λ§μ κ°μ²΄ λ©€λ²μ λ³κ²½ κ°λ₯μ±μ μ΄μ΄λκ²κ³Ό κ°μ λΆλ³μ± λ¬Έμ κ° ν°μ§κ² λλ€. (λ°λ‘ λ€μμ μ€λͺ )
7. λ©€λ²μ λν λ³κ²½ κ°λ₯μ± μ΅μνλ₯Ό μΆκ΅¬
λ§μ κ°λ°μλ€μ΄ μλ° νλ‘κ·Έλλ°μ νλ©΄μ λ©€λ²μ κ°μ ν λΉν λ νν μ¬μ©νλ κ²μ΄ Setter λ©μλμΈλ°, κ·Έμ€ ν΄λμ€ λ§΄λ² μ΄κΈ°νλ₯Ό Setterμ ν΅ν΄ ꡬμ±νλ κ²μ λ§€μ° μ’μ§ μμ λ°©λ²μ΄λ€. μ¦, μ΄ λΆλΆμ μμ λΉλ ν¨ν΄ νμ λ°°κ²½μμ λ€λ£¨μλ Java Beans PatternμΈ Setter λ©μλλ₯Ό ν΅ν΄ λ©€λ² μ΄κΈ°νλ₯Ό νμ§ λ§μμΌ νλ μ΄μ μ λν μ’ λ κ³ μμ€ μ μΈ λ΄μ©μ΄λ€.
μΌλ°μ μΌλ‘ νλ‘κ·Έλ¨μ κ°λ°νλλ° μμ΄ λ€λ₯Έ μ¬λκ³Ό νμ ν λ κ°μ₯ μ€μμλλ μ μ€ νλκ° λ°λ‘ λΆλ³(immutalbe) κ°μ²΄μ΄λ€. λΆλ³ κ°μ²΄λ κ°μ²΄ μμ± μ΄ν λ΄λΆμ μνκ° λ³νμ§ μλ κ°μ²΄μ΄λ€. λΆλ³ κ°μ²΄λ μ€λ‘μ§ μ½κΈ°(get) λ©μλλ§μ μ 곡νλ©° μ°κΈ°(set)λ μ 곡νμ§ μλλ€. λνμ μΌλ‘ μλ°μμ final ν€μλλ₯Ό λΆμΈ λ³μκ° λ°λ‘ λΆλ³μ΄λ€.
νμ μμ λΆλ³ κ°μ²΄λ₯Ό μ΄μ©ν΄ κ°λ°ν΄μΌ νλ μ΄μ λ‘λ λ€μκ³Ό κ°λ€.
- λΆλ³ κ°μ²΄λ Thread-Safe νμ¬ λκΈ°νλ₯Ό κ³ λ €νμ§ μμλ λλ€
- λ§μΌ κ°λ³ κ°μ²΄λ₯Ό ν΅ν΄ μμ μ νλ λμ€ μμΈ(Exception)κ° λ°μνλ©΄ ν΄λΉ κ°μ²΄κ° λΆμμ ν μνμ λΉ μ§ μ μμ΄ λ λ€λ₯Έ μλ¬λ₯Ό μ λ°ν μ μλ μνμ±μ΄ μκΈ° λλ¬Έμ΄λ€.
- λΆλ³ κ°μ²΄λ‘ ꡬμ±νλ©΄ λ€λ₯Έ μ¬λμ΄ κ°λ°ν ν¨μλ₯Ό μνμμ΄ μ΄μ©μ 보μ₯ν μ μμ΄ νμ μλ μ μ§λ³΄μμλ μ μ©νλ€.
λ°λΌμ ν΄λμ€λ€μ κ°λ³μ μ΄μ¬μΌ νλ λ§€μ° νλΉν μ΄μ κ° μμ§ μλ ν λ°λμ λΆλ³μΌλ‘ λ§λ€μ΄μΌ νλ€. λ§μ½ ν΄λμ€λ₯Ό λΆλ³μΌλ‘ λ§λλ κ²μ΄ λΆκ°λ₯νλ€λ©΄ κ°λ₯ν λ³κ²½ κ°λ₯μ±μ μ΅μνν΄μΌ νλ€.
μλ₯Όλ€μ΄ κ²½μ°μ λ°λΌ λ³μμ final ν€μλλ₯Ό λΆμΌμ μλ μν©μ΄ μκΈΈ μλ μλ€. μ΄λλ Setter λ©μλ μ체λ₯Ό ꡬννμ§ μμμΌλ‘μ λΆλ³ κ°μ²΄λ₯Ό κ°μ μ μΌλ‘ ꡬμ±μ΄ κ°λ₯νλ€.κ·Έλ¬λ©΄ κ²°κ΅μ λλ λμ μμ±μλ₯Ό μ΄μ©νλΌλ κ²μΈλ° μμλ μ§λμΉ μμ±μ μ€λ²λ‘λ© λ¬Έμ κ° λ°μνκ² λλ€. κ·Έλμ μ°κ΅¬λκ²μ΄ λΉλ ν΄λμ€μ΄λ€.
μ¦, μ΅μ’ μ 리νμλ©΄ λΉλ ν¨ν΄μ μμ±μ μμ΄ μ΄λ κ°μ²΄μ λν΄ 'λ³κ²½ κ°λ₯μ±μ μ΅μν' λ₯Ό μΆκ΅¬νμ¬ λΆλ³μ±μ κ°κ² ν΄μ£Όκ² λλ κ²μ΄λ€.
λΉλ ν¨ν΄ λ¨μ
1. μ½λ 볡μ‘μ± μ¦κ°
μ°μ λΉλ ν¨ν΄μ μ μ©νλ €λ©΄ Nκ°μ ν΄λμ€μ λν΄ Nκ°μ μλ‘μ΄ λΉλ ν΄λμ€λ₯Ό λ§λ€μ΄μΌ ν΄μ, ν΄λμ μκ° κΈ°νκΈμμ μΌλ‘ λμ΄λ κ΄λ¦¬ν΄μΌ ν ν΄λμ€κ° λ§μμ§κ³ κ΅¬μ‘°κ° λ³΅μ‘ν΄μ§ μ μλ€. λν μ νμ 맀κ°λ³μλ₯Ό λ§μ΄ λ°λ κ°μ²΄λ₯Ό μμ±νκΈ° μν΄μλ λ¨Όμ λΉλ ν΄λμ€λΆν° μ μν΄μΌνλ€. λ€λ§ μ΄λΆλΆμ μ¬λ λμμΈ ν¨ν΄μ΄ κ°μ§λ λ¨μ μ΄κΈ°λ νλ€.
2. μμ±μ 보λ€λ μ±λ₯μ λ¨μ΄μ§λ€.
λ§€λ² λ©μλλ₯Ό νΈμΆνμ¬ λΉλλ₯Ό κ±°μ³ μΈμ€ν΄μ€ν νκΈ° λλ¬Έμ μ΄μ©λ©΄ λΉμ°ν λ§μΌμ§λ λͺ¨λ₯Έλ€. λΉλ‘ μμ± λΉμ© μ체λ ν¬μ§λ μμ§λ§, μ΄ν리μΌμ΄μ μ μ±λ₯μ κ·ΉμΌλ‘ μ€μμλλ μν©μ΄λΌλ©΄ λ¬Έμ κ° λ μ μλ€.
3. μ§λμΉ λΉλ λ¨μ©μ κΈμ§
ν΄λμ€μ νλμ κ°μκ° 4κ° λ³΄λ€ μ κ³ , νλμ λ³κ²½ κ°λ₯μ±μ΄ μλ κ²½μ°λΌλ©΄ μ°¨λΌλ¦¬ μμ±μλ μ μ ν©ν 리 λ©μλλ₯Ό μ΄μ©νλ κ²μ΄ λ μ’μ μ μλ€. λΉλ ν¨ν΄μ μ½λκ° λ€μ μ₯ν©νκΈ° λλ¬Έμ΄λ€. λ°λΌμ ν΄λμ€ νλμ κ°―μμ νλ λ³κ²½ κ°λ₯μ±μ μ€μ μΌλ‘ λ³΄κ³ ν¨ν΄μ μ μ© μ 무λ₯Ό κ°λ €μΌνλ€.
λ€λ§ API λ μκ°μ΄ μ§λ μλ‘ λ§μ 맀κ°λ³μλ₯Ό κ°λ κ²½ν₯μ΄ μκΈ° λλ¬Έμ μ μ΄μ λΉλ ν¨ν΄μΌλ‘ μμνλ νΈμ΄ λμ λκ° λ§λ€κ³ λ§νλ κ²½ν₯λ μλ€.
Builder λμμΈ ν¨ν΄ μ’ λ₯
λΉλ ν¨ν΄μλ μ¬ν λμμΈ ν¨ν΄κ³Όλ λ€λ₯΄κ² λκ°μ§ λμμΈ μ’ λ₯κ° μ‘΄μ¬νλ€. GOFμ λμμΈ ν¨ν΄μμ μκ°νλ λΉλ ν¨ν΄κ³Ό μ΄νν°λΈ μλ°(Effective Java) μ± μμ μκ°νλ λΉλ ν¨ν΄ κ΅¬μ‘°κ° μλ‘ λ€λ₯΄κΈ° λλ¬Έμ΄λ€.
- μ΄νν°λΈ μλ°μ λΉλ ν¨ν΄ : μμ±μ μ§μ ν΄μΌ ν μΈμκ° λ§μλ μ¬μ©. κ°μ²΄μ μΌκ΄μ± λΆλ³μ±μ΄ λͺ©μ .
- GoFμ λΉλ ν¨ν΄ : κ°μ²΄μ μμ± λ¨κ³ μμλ₯Ό κ²°μ ν΄λκ³ κ° λ¨κ³λ₯Ό λ€μνκ² κ΅¬ννκ³ μΆμλ μ¬μ©.
μΌλ¨ λ μ± μ κ΄μ μ΄ λ€λ₯΄κ³ GoFμ λμμΈ ν¨ν΄μ 1994λ μ λ°λ§€λμκ³ μ΄νν°λΈ μλ°κ° 2001λ μ λμ€μ λμκΈ° λλ¬Έμ΄λΌκ³ μκ° λλ€.
μ¬ν λΉλ ν¨ν΄ (Effective Java)
λ³΄ν΅ κ°λ°μλ€μ΄ λΉλ ν¨ν΄μ λ§ν λ μ μλλ κ²μ΄ μ΄νν°λΈ μλ°μμ μκ°ν λΉλ ν¨ν΄μ΄λ€. GOF λΉλ ν¨ν΄κ³Ό ꡬλΆνκΈ° μν΄ μ¬ν λΉλ ν¨ν΄(Simple Builder Pattern) μ΄λΌκ³ λ λΆλ¦¬μ΄λ€.
μ¬ν λΉλ ν¨ν΄μ μμ±μκ° λ§μ κ²½μ° λλ λ³κ²½ λΆκ°λ₯ν λΆλ³ κ°μ²΄κ° νμν κ²½μ° μ½λμ κ°λ μ±κ³Ό μΌκ΄μ±, λΆλ³μ±μ μ μ§νλ κ²μ μ€μ μ λλ€. μ¬ν λΉλ ν¨ν΄μ μμμ μ°λ¦¬κ° λ°°μ΄ λΉλ ν¨ν΄κ³Ό μ°¨μ΄κ° κ±°μ μλ€. λ€λ§ λΉλ(Builder) ν΄λμ€κ° ꡬνν ν΄λμ€μ μ μ λ΄λΆ ν΄λμ€(Static Inner Class)λ‘ κ΅¬νλλ€λ μ μ΄ λ€λ₯΄λ€.
λΉλ ν΄λμ€κ° static inner classλ‘ κ΅¬νλλ μ΄μ λ‘λ λ€μκ³Ό κ°λ€.
첫 λ²μ§Έ, νλμ λΉλ ν΄λμ€λ νλμ λμ κ°μ²΄ μμ±λ§μ μν΄ μ¬μ©λλ€. κ·Έλμ λ ν΄λμ€λ₯Ό 물리μ μΌλ‘ κ·Έλ£Ήνν¨μΌλ‘μ¨ λ ν΄λμ€κ°μ κ΄κ³μ λν νμ μ μ½κ² ν μ μλ€.
λ λ²μ§Έ, λμ κ°μ²΄λ μ€λ‘μ§ λΉλ κ°μ²΄μ μν΄ μ΄κΈ°ν λλ€. μ¦, μμ±μλ₯Ό μΈλΆμ λ ΈμΆμν€λ©΄ μλκΈ° λλ¬Έμ μμ±μλ₯Ό privateλ‘ νκ³ , λ΄λΆ λΉλ ν΄λμ€μμ private μμ±μλ₯Ό νΈμΆν¨μΌλ‘μ¨ μ€λ‘μ§ λΉλ κ°μ²΄μ μν΄ μ΄κΈ°ν λλλ‘ μ€κ³ ν μ μλ€.
μΈ λ²μ§Έ, inner classλ₯Ό μ°λ©΄ μ’μ건 μκ² λλ° μ νν static μΌλ‘ μ μΈν΄μ£Όμ΄μΌ νλλ©΄, μ μ λ΄λΆ ν΄λμ€λ μΈλΆ ν΄λμ€μ μΈμ€ν΄μ€ μμ΄λ μμ±ν μ μλλ°, λ§μΌ μΌλ° λ΄λΆ ν΄λμ€λ‘ ꡬμ±νλ€λ©΄ λ΄λΆ ν΄λμ€λ₯Ό μμ±νκΈ°λ μ μ μΈλΆ ν΄λμ€λ₯Ό μΈμ€ν΄μ€ν ν΄μΌ νλ€. λΉλκ° μ΅μ’ μ μΌλ‘ μμ±ν ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό λ¨Όμ μμ±ν΄μΌ νλ€λ©΄ λͺ¨μμ΄ μκΈ°κΈ° λλ¬Έμ΄λ€.
λ€ λ²μ§Έ, λ©λͺ¨λ¦¬ λμ λ¬Έμ λλ¬Έμ staticμΌλ‘ λ΄λΆ ν΄λμ€λ₯Ό μ μν΄μ£Όμ΄μΌ νλ€. μμΈν건 λ€μ ν¬μ€ν μ μ°Έκ³ νκΈΈ λ°λλ€.
Simple λΉλ ν¨ν΄ ꡬννκΈ°
- λΉλ ν΄λμ€λ₯Ό Static Nested Classλ‘ μ μνλ€.
- λΉλλ₯Ό ν΅ν΄ μΈμ€ν΄μ€ν νκΈ° λλ¬Έμ λμ κ°μ²΄ μμ±μλ privateλ‘ μ μνλ€.
- λΉλ ν΄λμ€μ μμ±μλ publicμΌλ‘ νλ©°, νμ νλΌλ―Έν°μ λν΄ μμ±μμ νλΌλ―Έν°λ‘ λ°λλ€.
- μ νμ νλΌλ―Έν°μ λν΄μλ λ©μλλ‘ μ 곡νλ€. μ΄λ λ©μλμ λ°νκ°μ λΉλ κ°μ²΄ μμ (this) μ΄μ΄μΌ νλ€.
- λ§μ§λ§ λ¨κ³λ‘ μ΅μ’
κ°μ²΄λ₯Ό μμ±νλ
build()λ©μλλ₯Ό μ μνμ¬ ν΄λΌμ΄μΈνΈμκ² μ΅μ’ μμ±λ κ²°κ³Όλ¬Όμ μ 곡νλ€. - μ΄λ μμ±μμ μΈμλ‘ λΉλ μΈμ€ν΄μ€ μκΈ°μμ μ μ λ¬νκ³ , λμ κ°μ²΄ μμ±μμμ λΉλ μΈμ€ν΄μ€μ νλλ₯Ό κ°κ° λμ νμ¬ μ΅μ’ μμ±λ³Έμ΄ λμ€κ² λλ€.
class Person {
// final ν€μλλ‘ νλλ€μ λΆλ³ κ°μ²΄λ‘ λ§λ λ€.
private final String name;
private final String age;
private final String gender;
private final String job;
private final String birthday;
private final String address;
// μ μ λ΄λΆ λΉλ ν΄λμ€
public static class Builder {
// νμ νλΌλ―Έν°
private final String name;
private final String age;
// μ ν νλΌλ―Έν°
private String gender;
private String job;
private String birthday;
private String address;
// νμ νλΌλ―Έν°λ λΉλ μμ±μλ‘ λ°κ² νλ€
public Builder(String name, String age) {
this.name = name;
this.age = age;
}
// μ ν νλΌλ―Έν°λ κ° λ©μλλ₯Ό ν΅ν΄ μ μνλ€
public Builder gender(String gender) {
this.gender = gender;
return this;
}
public Builder job(String job) {
this.job = job;
return this;
}
public Builder birthday(String birthday) {
this.birthday = birthday;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
// λμ κ°μ²΄μ private μμ±μλ₯Ό νΈμΆνμ¬ μ΅μ’
μΈμ€ν΄μ€ν νλ€
public Person build() {
return new Person(this); // λΉλ κ°μ²΄ μμ μ λκΈ΄λ€.
}
}
// private μμ±μ - μμ±μλ μΈλΆμμ νΈμΆλλκ²μ΄ μλ λΉλ ν΄λμ€μμλ§ νΈμΆλκΈ° λλ¬Έμ
private Person(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.gender = builder.gender;
this.job = builder.gender;
this.birthday = builder.birthday;
this.address = builder.address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
", gender='" + gender + '\'' +
", job='" + job + '\'' +
", birthday='" + birthday + '\'' +
", address='" + address + '\'' +
'}';
}
}
public static void main(String[] args) {
Person person = new Person
.Builder("νκΈΈλ", "26") // static inner class μ΄κΈ°ν (νμ νλΌλ―Έν°)
.gender("man") // μ ν νλΌλ―Έν°
.job("Warrior")
.birthday("1800.10.10")
.address("μ‘°μ ")
.build();
System.out.println(person);
}
λλ ν° λΉλ ν¨ν΄ (GOF)
GOFμμ μ μνκ³ μλ λμμΈ ν¨ν΄μ 볡μ‘ν κ°μ²΄μ μμ± μκ³ λ¦¬μ¦κ³Ό 쑰립 λ°©λ²μ λΆλ¦¬νμ¬ λΉλ 곡μ μ ꡬμΆνλκ²μ΄ λͺ©μ μ΄λ€. λΉλλ₯Ό λ°μ 쑰립 λ°©λ²μ μ μν ν΄λμ€λ₯Ό DirectorλΌκ³ λΆλ₯Έλ€.
μ¬ν λΉλ ν¨ν΄μ νλμ λμ κ°μ²΄μ λν μμ±λ§μ λͺ©μ μ λμ§λ§, λλ ν° λΉλ ν¨ν΄μ μ¬λ¬κ°μ§μ λΉλ νμμ μ μ°νκ² μ²λ¦¬νλ κ²μ λͺ©μ μ λλ€. μ΄μ°λ³΄λ©΄ μΌλ°μ μΈ λΉλ ν¨ν΄μ κ³ λν μν¨ ν¨ν΄μ΄λΌκ³ λ³Ό μ λ μλ€.
Director λΉλ ν¨ν΄ ꡬ쑰
- Builder : λΉλ μΆμ ν΄λμ€
- ConcreteBuilder : Builderμ ꡬν체. Product μμ±μ λ΄λΉνλ€.
- Director : Builderμμ μ 곡νλ λ©μλλ€μ μ¬μ©ν΄ μ ν΄μ§ μμλλ‘ Product μμ±νλ νλ‘μΈμ€λ₯Ό μ μ
- Product : Directorκ° Builderλ‘ λ§λ€μ΄λΈ κ²°κ³Όλ¬Ό.
μ΄λ¬ν ꡬ쑰λ ν΄λΌμ΄μΈνΈκ° μ§μ λΉλμ λͺ¨λ APIλ₯Ό μ¬μ©νλ κ² μλ, Directorμ ν΅ν΄μ κ°λ¨νκ² μΈμ€ν΄μ€λ₯Ό μ»μ΄μ¬ μ μκ³ μ½λλ₯Ό μ¬μ¬μ©ν μ μλλ‘ νλ€.
Director λΉλ ν¨ν΄ ꡬννκΈ°
λ€μ μμ λ μΌλ°μ μΈ μλ° λ°μ΄ν°λ₯Ό μ μ₯νκ³ μλ Data κ°μ²΄λ₯Ό Builder μΈν°νμ΄μ€λ₯Ό ν΅ν΄ μ μ ν λ¬Έμμ΄ ν¬λ§·μΌλ‘ λ³ννλ μμ μ΄λ€.
- PlainTextBuilder : Data μΈμ€ν΄μ€μ λ°μ΄ν°λ€μ νμ΄ν ν μ€νΈ ννλ‘ λ§λλ API
- JSONBuilder : Data μΈμ€ν΄μ€μ λ°μ΄ν°λ€μ JSON ννλ‘ λ§λλ API
- XMLBuilder : Data μΈμ€ν΄μ€μ λ°μ΄ν°λ€μ XML ννλ‘ λ§λλ API
μ΄λ κ° λ¬Έμμ΄ ν¬λ§·μΌλ‘ λ³ννλ νλ‘μΈμ€λ₯Ό Director κ°μ²΄κ° λ΄λΉνκ² λλ€. ν΄λΌμ΄μΈνΈλ Directorλ₯Ό μ΄μ©νμ¬ κ°λ¨ν λ©μλ νΈμΆλ§μΌλ‘ 볡μ‘ν λΉλ 곡μ κ³Όμ μ μνμμμ΄ κ²°κ³Όλ¬Όμ μ»μ μ μλ€.
class Data {
private String name;
private int age;
public Data(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
abstract class Builder {
// μμν μμ ν΄λμ€μμ μ¬μ©νλλ‘ protected μ κ·Όμ μ΄μ μ§μ
protected Data data;
public Builder(Data data) {
this.data = data;
}
// Data κ°μ²΄μ λ°μ΄ν°λ€μ μνλ ννμ λ¬Έμμ΄ ν¬λ§·μ ν΄μ£Όλ λ©μλλ€ (머리 - μ€κ° - λ νμ)
public abstract String head();
public abstract String body();
public abstract String foot();
}
// Data λ°μ΄ν°λ€μ νλ²ν λ¬Έμμ΄λ‘ λ³νν΄μ£Όλ λΉλ
class PlainTextBuilder extends Builder {
public PlainTextBuilder(Data data) {
super(data);
}
@Override
public String head() {
return "";
}
@Override
public String body() {
StringBuilder sb = new StringBuilder();
sb.append("Name: ");
sb.append(data.getName());
sb.append(", Age: ");
sb.append(data.getAge());
return sb.toString();
}
@Override
public String foot() {
return "";
}
}
// Data λ°μ΄ν°λ€μ JSON ννμ λ¬Έμμ΄λ‘ λ³νν΄μ£Όλ λΉλ
class JSONBuilder extends Builder {
public JSONBuilder(Data data) {
super(data);
}
@Override
public String head() {
return "{\n";
}
@Override
public String body() {
StringBuilder sb = new StringBuilder();
sb.append("\t\"Name\" : ");
sb.append("\"" + data.getName() + "\",\n");
sb.append("\t\"Age\" : ");
sb.append(data.getAge());
return sb.toString();
}
@Override
public String foot() {
return "\n}";
}
}
// Data λ°μ΄ν°λ€μ XML ννμ λ¬Έμμ΄λ‘ λ³νν΄μ£Όλ λΉλ
class XMLBuilder extends Builder {
public XMLBuilder(Data data) {
super(data);
}
@Override
public String head() {
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
sb.append("<DATA>\n");
return sb.toString();
}
@Override
public String body() {
StringBuilder sb = new StringBuilder();
sb.append("\t<NAME>");
sb.append(data.getName());
sb.append("<NAME>");
sb.append("\n\t<AGE>");
sb.append(data.getAge());
sb.append("<AGE>");
return sb.toString();
}
@Override
public String foot() {
return "\n</DATA>";
}
}
// κ° λ¬Έμμ΄ ν¬λ§· λΉλ κ³Όμ μ ν
νλ¦Ών μν¨ λλ ν°
class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
// μΌμ’
μ λΉλ ν
νλ¦Ώ λ©μλλΌ λ³΄λ©΄ λλ€
public String build() {
StringBuilder sb = new StringBuilder();
// λΉλ ꡬν체μμ μ μν μμ± μκ³ λ¦¬μ¦μ΄ μ€νλ¨
sb.append(builder.head());
sb.append(builder.body());
sb.append(builder.foot());
return sb.toString();
}
}
public static void main(String[] args) {
// 1. ν¬λ§·ν μλ° λ°μ΄ν° μμ±
Data data = new Data("νκΈΈλ", 44);
// 2. μΌλ° ν
μ€νΈλ‘ ν¬λ§·νμ¬ μΆλ ₯νκΈ°
Builder builder1 = new PlainTextBuilder(data);
Director director1 = new Director(builder1);
String result1 = director1.build();
System.out.println(result1);
// 3. JSON νμμΌλ‘ ν¬λ§·νμ¬ μΆλ ₯νκΈ°
Builder builder2 = new JSONBuilder(data);
Director director2 = new Director(builder2);
String result2 = director2.build();
System.out.println(result2);
// 4. XML νμμΌλ‘ ν¬λ§·νμ¬ μΆλ ₯νκΈ°
Builder builder3 = new XMLBuilder(data);
Director director3 = new Director(builder3);
String result3 = director3.build();
System.out.println(result3);
}
μ΄μ²λΌ Directorλ ν νλ¦Ών ν λ©μλλ₯Ό ν΅ν΄ μΌκ΄λ νλ‘μΈμ€λ‘ μΈμ€ν΄μ€λ₯Ό λ§λλ λΉλ κ³Όμ μ λ¨μν νκ³ , ν΄λΌμ΄μΈνΈ μͺ½μμ Directorκ° μ 곡νλ λ©μλλ₯Ό νΈμΆνλ―λ‘μ¨ μ½λλ₯Ό μ¬μ¬μ©ν μ μκ² λλ€.
μ¦, Builder λ λΆνμ λ§λ€κ³ , Directorλ γ uilderκ° λ§λ λΆνμ μ‘°ν©ν΄ μ νμ λ§λ λ€κ³ ν μ μλ€.
GOFμ λΉλ ν¨ν΄μ μ¬λ¬ λμμΈ ν¨ν΄μ 짬λ½
μ§κΈ κΉμ§ ꡬνν΄λ³Έ GOFμ λλ ν° λΉλ ν¨ν΄μ μ΄μ° 보면 λΉλ κ³Όμ μ μΆμν λ° λ¨μνν Facade ν¨ν΄κ³Ό λΉλ κ³Όμ μ½λλ₯Ό ν νλ¦Ώνν Template Method ν¨ν΄ κ·Έλ¦¬κ³ μνλ λ¬Έμμ΄ νμμ κ° λΉλ μ λ΅ μκ³ λ¦¬μ¦μ μ μν Strage ν¨ν΄μ μ§¬λ½ μν¨ λμμΈ ν¨ν΄μ΄λΌκ³ λ³Όμλ μλ€.
Lombokμ @Builder
κ°λ°μκ° μ’λ νΈνκ² λΉλ ν¨ν΄μ μ΄μ©νκΈ° μν€ Lombokμμλ λ³λμ μ΄λ Έν μ΄μ μ μ§μνλ€. ν΄λμ€μ @Builder μ΄λ Έν μ΄μ λ§ λΆμ¬μ£Όλ©΄ ν΄λμ€λ₯Ό μ»΄νμΌ ν λ μλμΌλ‘ ν΄λμ€ λ΄λΆμ λΉλ APIκ° λ§λ€μ΄μ§λ€.
λ¨, 둬볡μ @Builderλ GOFμ λλ ν° λΉλκ° μλ μ¬ν λΉλ ν¨ν΄μ λ€λ£¬λ€λ μ μ μ μνμ.
λΉλ μ΄λ Έν μ΄μ ꡬννκΈ°
- @Builder : PersonBuilder λΉλ ν΄λμ€μ μ΄λ₯Ό λ°ννλ builder() λ©μλ μμ±
- @AllArgsConstructor(access = AccessLevel.PRIVATE) : @Builder μ΄λ Έν μ΄μ μ μ μΈνλ©΄ μ 체 μΈμλ₯Ό κ°λ μμ±μλ₯Ό μλμΌλ‘ λ§λλλ°, μ΄λ₯Ό private μμ±μλ‘ μ€μ
- @ToString : toString() λ©μλ μλ μμ±
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.ToString;
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@ToString
class Person {
private final String name;
private final String age;
private final String gender;
private final String job;
private final String birthday;
private final String address;
}
public static void main(String[] args) {
Person person = Person.builder()
.name("νκΈΈλ")
.age("26")
.gender("man") // μ ν νλΌλ―Έν°
.job("Warrior")
.birthday("1800.10.10")
.address("μ‘°μ ")
.build();
}
νμ νλΌλ―Έν° λΉλ ꡬννκΈ°
@Builder μ΄λ
Έν
μ΄μ
μΌλ‘ λΉλ ν¨ν΄μ ꡬννλ©΄ νμ νλΌλ―Έν° μ μ©μ μ§μ ν΄μ€μκ° μλ€. λ°λΌμ λμ κ°μ²΄ μμ λ³λμ builder() μ μ λ©μλλ₯Ό ꡬνν¨μΌλ‘μ¨, λΉλ κ°μ²΄λ₯Ό μμ±νκΈ° μ μ νμ νλΌλ―Έν°λ₯Ό μ€μ νλλ‘ μ λν μ μκ³ , λν νλΌλ―Έν° κ²μ¦ λ‘μ§λ μΆκ°ν΄μ€ μ μλ€.
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@ToString
class Person {
private final String name;
private final String age;
private final String gender;
private final String job;
private final String birthday;
private final String address;
// νμ νλΌλ―Έν° λΉλ λ©μλ ꡬν
public static PersonBuilder builder(String name, String age) {
// λΉλμ νλΌλ―Έν° κ²μ¦
if(name == null || age == null)
throw new IllegalArgumentException("νμ νλΌλ―Έν° λλ½");
// νμ νλΌλ―Έν°λ₯Ό 미리 λΉλν λΉλ κ°μ²΄λ₯Ό λ°ν (μ§μ° λΉλ μ리)
return new PersonBuilder().name(name).age(age);
}
}
public static void main(String[] args) {
Person person = Person.builder("νκΈΈλ", "26") // νμ νλΌλ―Έν°
.gender("man") // μ ν νλΌλ―Έν°
.job("Warrior")
.birthday("1800.10.10")
.address("μ‘°μ ")
.build();
System.out.println(person);
}
μ€λ¬΄μμ μ°Ύμ보λ Builder ν¨ν΄
Java
- java.lang.StringBuilderμ append()
- java.lang.StringBufferμ append()
- java.nio.ByteBufferμ put() - CharBuffer, ShortBuffer, IntBuffer, LongBuffer, FloatBuffer, DoubleBuffer λ λ§μ°¬κ°μ§
- javax.swing.GroupLayout.Groupμ addComponent()
- java.lang.Appendableμ ꡬν체
- java.util.stream.Stream.Builder
StringBuilder
μλ°μ λ¬Έμμ΄ ν΄λμ€νλ©΄ λ°°μ°λ StringBuilderκ° μ΄λ¦μμ 보λ―μ΄ κ·Έ μμ΄λ€.
λΉλμ ν΄λΉνλ StringBuilderλ₯Ό μμ±νκ³ , λΉλκ° μ 곡νλ append λ©μλλ‘ νλΌλ―Έν°λ₯Ό ꡬμ±νκ³ , μ΅μ’ μ μΌλ‘ toStringμ νΈμΆν΄μ String κ°μ²΄λ₯Ό μμ±νλ μΌλ ¨μ κ³Όμ μ΄ λΉλ ν¨ν΄μ΄κΈ° λλ¬Έμ΄λ€.
public static void main(String[] args) {
String result = new StringBuilder()
.append("hello ")
.append("world!")
.toString(); // build()
System.out.println(result);
}
StreamBuilder
Stream APIκ° μ 곡νλ StreamBuilderλ λ§μ°¬κ°μ§μ΄λ€. StreamBuilderλ₯Ό μ¬μ©νλ©΄ Streamμ λ€μ΄κ° μμλ₯Ό add ν μ μκ³ , μ΅μ’ μ μΌλ‘ buildλ₯Ό νΈμΆν΄μ stream κ°μ²΄λ₯Ό μμ±νλ€.
public static void main(String[] args) {
Stream.Builder<String> stringBuilder = Stream.builder();
Stream<String> stream = stringBuilder.add("hello").add("world!").add("bye..").build();
stream.forEach(System.out::println);
}
Spring Framework
μ€νλ§ νλ μμν¬μμ UriComponents μΈμ€ν΄μ€λ₯Ό Uricomponentsbuilderλ₯Ό ν΅ν΄μ λ§λ€ μ μλ€. uriλ₯Ό νλμ½λ©ν΄μ λ§λλ κ²λ³΄λ€ μμ νκ² λ§λ€ μ μλ€.
public static void main(String[] args) {
UriComponents uriComponents = UriComponentsBuilder.newInstance()
.scheme("https")
.host("kangworld.tistory.com")
.build();
System.out.println(uriComponents);
}
# μ°Έκ³ μλ£
μ΄νν°λΈ μλ° Effective Java 3/E
μ½λ©μΌλ‘ νμ΅νλ GoFμ λμμΈ ν¨ν΄ - λ°±κΈ°μ
https://refactoring.guru/design-patterns/builder
https://www.youtube.com/watch?v=_GCiJAFU2DU