: 복잡한 객체들을 단계별로 생성할 수 있도록 하는 생성 디자인 패턴
객체의 다양한 유형, 표현 제작이 가능함.
Gof Builder → refactoring guru
: 디렉터 클래스로 빌더를 받아 조립 방법을 정의함.
여러가지 빌드 형식을 처리하는 것에 목적을 둠.
public interface HomeBuilder {
HomeBuilder walls(int walls);
HomeBuilder windows(int windows);
HomeBuilder doors(int doors);
HomeBuilder rooms(int rooms);
HomeBuilder hasHeating(boolean hasHeating);
HomeBuilder hasGarage(boolean hasGarage);
HomeBuilder hasSwimPool(boolean hasSwimPool);
HomeBuilder hasGarden(boolean hasGarden);
Home build();
}
public class Home {
private String name;
private int walls;
private int windows;
private int doors;
private int rooms;
private boolean hasHeating;
private boolean hasGarage;
private boolean hasSwimPool;
private boolean hasGarden;
// getter, setter 코드 생략
@Override
public String toString() {
return "Home{" +
"name='" + name + '\\'' +
", walls=" + walls +
", windows=" + windows +
", doors=" + doors +
", rooms=" + rooms +
", hasHeating=" + hasHeating +
", hasGarage=" + hasGarage +
", hasSwimPool=" + hasSwimPool +
", hasGarden=" + hasGarden +
'}';
}
}
public class DefaultHomeBuilder implements HomeBuilder{
private String name;
private int walls;
private int windows;
private int doors;
private int rooms;
private boolean hasHeating;
private boolean hasGarage;
private boolean hasSwimPool;
private boolean hasGarden;
@Override
public HomeBuilder name(String name) {
this.name = name + "(기본)";
return this;
}
@Override
public HomeBuilder walls(int walls) {
this.walls = walls;
return this;
}
@Override
public HomeBuilder windows(int windows) {
this.windows = windows;
return this;
}
@Override
public HomeBuilder doors(int doors) {
this.doors = doors;
return this;
}
@Override
public HomeBuilder rooms(int rooms) {
this.rooms = rooms;
return this;
}
@Override
public HomeBuilder hasHeating(boolean hasHeating) {
this.hasHeating = hasHeating;
return this;
}
@Override
public HomeBuilder hasGarage(boolean hasGarage) {
this.hasGarage = hasGarage;
return this;
}
@Override
public HomeBuilder hasSwimPool(boolean hasSwimPool) {
this.hasSwimPool = hasSwimPool;
return this;
}
@Override
public HomeBuilder hasGarden(boolean hasGarden) {
this.hasGarden = hasGarden;
return this;
}
@Override
public Home build() {
Home home = new Home();
home.setName(this.name);
home.setWalls(this.walls);
home.setRooms(this.rooms);
home.setWindows(this.windows);
home.setDoors(this.doors);
home.setHasGarden(this.hasGarden);
home.setHasGarage(this.hasGarage);
home.setHasSwimPool(this.hasSwimPool);
home.setHasHeating(this.hasHeating);
return home;
}
}
public class ModernHomeBuilder implements HomeBuilder{
// 필드값 선언문 코드 생략
// 메서드 오버라이딩 코드 생략
}
public class VintageHomeBuilder implements HomeBuilder{
// 필드값 선언문 코드 생략
// 메서드 오버라이딩 코드 생략
}
public class HomeDirector {
private HomeBuilder homeBuilder;
public HomeDirector(HomeBuilder homeBuilder){
this.homeBuilder = homeBuilder;
}
public Home hasGardenHome(){
return homeBuilder
.hasGarden(true)
.name("정원이 있는 집")
.doors(5)
.rooms(3)
.windows(8)
.walls(4)
.build();
}
public Home hasHeatingHome(){
return homeBuilder
.hasHeating(true)
.name("난방기가 있는 따뜻한 집")
.doors(3)
.rooms(3)
.windows(12)
.walls(4)
.build();
}
public Home hasSwimPoolHome(){
return homeBuilder
.hasSwimPool(true)
.name("수영장이 있는 집")
.doors(3)
.rooms(3)
.windows(12)
.walls(4)
.build();
}
}
public class Client {
public static void main(String[] args) {
HomeDirector defaultHomeDirector = new HomeDirector(new DefaultHomeBuilder());
System.out.println(defaultHomeDirector.hasGardenHome());
HomeDirector modernHomeDirector = new HomeDirector(new ModernHomeBuilder());
System.out.println(modernHomeDirector.hasHeatingHome());
HomeDirector vintageHomeDirector = new HomeDirector(new VintageHomeBuilder());
System.out.println(vintageHomeDirector.hasSwimPoolHome());
}
}
// console 결과
Home{name='정원이 있는 집(기본 스타일)', walls=4, windows=8, doors=5, rooms=3, hasHeating=false, hasGarage=false, hasSwimPool=false, hasGarden=true}
Home{name='난방기가 있는 따뜻한 집(모던 스타일)', walls=4, windows=12, doors=3, rooms=3, hasHeating=true, hasGarage=false, hasSwimPool=false, hasGarden=false}
Home{name='수영장이 있는 집(빈티지 스타일)', walls=4, windows=12, doors=3, rooms=3, hasHeating=false, hasGarage=false, hasSwimPool=true, hasGarden=false}
디렉터가 메서드를 템플릿화하여, 인스턴스를 만드는 과정을 단순화.
클라이언트에서는 Director의 메서드를 호출해 코드를 재사용.
Simple Builder
public class Home {
private int walls;
private int windows;
private int doors;
private int rooms;
private boolean hasHeating;
private boolean hasGarage;
private boolean hasSwimPool;
private boolean hasGarden;
// 빌더 객체로만 초기화 될수 있도록 생성자는 private 로 한다.
private Home(){}
public **static** class Builder {
// 필수 필드값
private int walls;
private int windows;
private int doors;
private int rooms;
// 선택 필드값
private boolean hasHeating;
private boolean hasGarage;
private boolean hasSwimPool;
private boolean hasGarden;
// 필수 필드값(매개변수)들은 빌더 생성자를 통해 받게 한다.
public Builder(int walls, int windows, int doors, int rooms){
this.walls = walls;
this.windows = windows;
this.doors = doors;
this.rooms = rooms;
}
public Builder hasHeating(boolean hasHeating) {
this.hasHeating = hasHeating;
return this;
}
public Builder hasGarage(boolean hasGarage) {
this.hasGarage = hasGarage;
return this;
}
public Builder hasSwimPool(boolean hasSwimPool) {
this.hasSwimPool = hasSwimPool;
return this;
}
public Builder hasGarden(boolean hasGarden) {
this.hasGarden = hasGarden;
return this;
}
public Home build() {
Home home = new Home();
home.walls = this.walls;
home.windows = this.windows;
home.doors = this.doors;
home.rooms = this.rooms;
home.hasHeating = this.hasHeating;
home.hasGarage = this.hasGarage;
home.hasSwimPool = this.hasSwimPool;
home.hasGarden = this.hasGarden;
return home;
}
}
}
빌더 클래스가 static inner class로 구현됨.
why?
하나의 대상 객체만을 위해 사용.
오로지 빌더 객체에 의해 초기화되도록.
외부 클래스 인스턴스 없이도 생성하기 위해.
inner class의 외부 참조 메모리 누수 문제.
Lombok @Builder
: Lombok이 지원하는 별도의 어노테이션.
클래스에 @Builder 어노테이션으로 클래스 컴파일 시 내부 빌더 API가 생성됨.
롬복은 심플 빌더 패턴을 다룸!
@Builder
: 빌더 클래스와 반환하는 builder() 메서드 생성
@AllArgsConstructor(access = AccessLovel.PRIVATE)
: 전체 인자를 갖는 생성자 생성. 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 Interface
: 모든 유형의 빌더들에 공통적인 제품 생성 단계 선언
Concrete Builder
: 생성 단계의 다양한 구현 제공.
공통 인터페이스를 따르지 않는 제품도 생산 가능.
Product
: 결과로 나오는 객체들.