복합 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 패턴.
// Basic
class Student(id: number, name: string, major: string, age: number, address: string) {
id : number;
name : string;
major : string;
age : number;
address: string;
constructor() {
this.id = id;
this.name = name;
this.major = major;
this.age = age;
this.address = address;
}
}
const student = new Student(20220103, '조준석', '정보통신', null, '서울시 노원구...');
클래스 내에 오버로딩을 통해서 생성자를 여러 개 작성하는 것을 말한다.
public class Member {
private String name; // 필수
private int age; // 필수
private String address; // 선택
private String phone; // 선택
private String email; // 선택
// 필수 매개변수를 가지는 생성자
public Member(String name, int age) {
this(name, age, null, null, null);
}
// 선택 매개변수 address가 추가된 생성자
public Member(String name, int age, String address) {
this(name, age, address, null, null);
}
// 선택 매개변수 phone이 추가된 생성자
public Member(String name, int age, String address, String phone) {
this(name, age, address, phone, null);
}
// 모든 매개변수를 가지는 생성자
public Member(String name, int age, String address, String phone, String email) {
this.name = name;
this.age = age;
this.address = address;
this.phone = phone;
this.email = email;
}
}
Member member1 = new Member("홍길동", 56);
// { name: "홍길동", age: 56, address: null, phone: null, email: null }
Member member2 = new Member("조준석", 29, "서울시 노원구", "01012345678");
// { name: "조준석", age: 29, address: "서울시 노원구", phone: "01012345678", email: null }
매개변수가 없는 생성자로 객체를 만든 후, Setter 메서드를 호출해 원하는 매개변수의 값을 설정하는 방식이다.
public class Member {
private final String name;
private final int age;
private final String address;
private final String phone;
private final String email;
public Member() {}
// Setter 메서드
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setAddress (String address) {
this.address = address;
}
public void setPhone(String phone) {
this.phone = phone;
}
public void setEmail(String email) {
this.email = email;
}
}
Member member = new Member();
member.setName('조준석');
member.setAge(29);
// { name: "조준석", age: 29 }
// 객체 일관성이 깨질 수 있으며, 불변성 객체를 만들 수 없다.
// 단순 생성자로 만들 때 예시
const student = new Student(null, '조준석', null, 29, null);
// Builder Pattern 호출 예시
const student = Student.builder().name('조준석').age(29);
구현 예제는 커피를 구성하는 객체를 생성자만 이용해 만드는 방법(AS-IS)과, Builder 패턴(TO-BE)을 이용해 만드는 방법을 나타낸 예제 입니다. 예제를 보면 Builder 패턴의 장점을 별다른 설명 없이 한눈에 파악할 수 있습니다.
// 생성자를 이용해 만드는 방법 (AS-IS)
class Coffee {
ice: boolean;
whippingCream: boolean;
milk: boolean;
numOfShots: number;
addRequest: string;
constructor(
ice: boolean,
whippingCream: boolean,
milk: boolean,
numOfShots: number,
addRequest: string
) {
this.ice = ice;
this.whippingCream = whippingCream;
this.milk = milk;
this.numOfShots = numOfShots;
this.addRequest = addRequest;
}
}
// 각 인자로 넘긴 값이 무엇을 의미하는지 알기 힘들다.
// 사용하지 않는 값도 인자로 무조건 넘겨줘야 한다.
const iceAmericano = new Coffee(true, false, false, 2, "얼음 적게 주세요");
const hotCafeLatte = new Coffee(false, true, true, 4, "");
// Builder 패턴을 이용해 만드는 방법 (TO-BE)
class Coffee {
ice: boolean;
whippingCream: boolean;
milk: boolean;
numOfShots: number;
addRequest: string;
constructor() {
this.ice = false;
this.whippingCream = false;
this.milk = false;
this.numOfShots = 0;
this.addRequest = "";
}
}
class CoffeeBuilder {
coffee: Coffee;
constructor() {
this.coffee = new Coffee(); // 빌더 객체를 생성한다.
}
addIce(addIce: boolean) {
this.coffee.ice = addIce;
return this;
}
addWhippingCream(addWhippingCream: boolean) {
this.coffee.whippingCream = addWhippingCream;
return this;
}
addMilk(addMilk: boolean) {
this.coffee.milk = addMilk;
return this;
}
howManyShots(numOfShots: number) {
this.coffee.numOfShots = numOfShots;
return this;
}
addRequest(message: string) {
this.coffee.addRequest = message;
return this;
}
// builder 객체를 리턴한다.
build() {
return this.coffee;
}
}
// 어떤 객체를 만들어낼지 보다 직관적으로 알 수 있고,
// 필요한 인자만 넘겨 객체를 만들어 낼 수 있다.
// (메서드 체이닝 방식으로 프로퍼티들을 set 해주고 build()를 호출하여 객체를 리턴 받는다.)
const iceAmericano = new CoffeeBuilder().addIce(true).howManyShots(2).build();
// 결과
// { ice: true, whippingCream: false, milk: false, numOfShots: 2, addRequest: '' }
const hotMilk = new CoffeeBuilder().addMilk(true).addRequest("머그컵에 주세요");
// 결과
// { ice: false, whippingCream: false, milk: true, numOfShots: 0, addRequest: '머그컵에 주세요' }