반응형
빌더 패턴이란?
빌더 패턴(Builder Pattern)은 복잡한 객체를 단계적으로 생성할 수 있도록 도와주는 디자인 패턴이다. 즉, 객체를 생성할 때 필요한 값을 하나씩 설정하며 유연하게 만들 수 있도록 도와준다.
빌더 패턴을 왜 사용할까?
- 복잡한 생성자를 피할 수 있다
- 만약 객체를 만들 때 옵션이 많다면, 생성자가 너무 길어질 수 있음.
- 빌더 패턴을 사용하면 필요한 값만 설정하고 객체를 만들 수 있음.
- 코드를 더 읽기 쉽게 만들 수 있다
- 메서드 체이닝(연속적인 메서드 호출)으로 객체를 설정할 수 있음.
- 가독성이 좋아지고 유지보수가 쉬워짐.
- 불변성(Immutable) 객체를 쉽게 만들 수 있다
- 객체를 한 번 설정한 후 변경할 필요가 없는 경우 유용함.
빌더 패턴을 쉽게 이해하는 예제
예제 1: 햄버거 만들기
햄버거를 만드는 과정을 생각해보자.
햄버거는 빵, 패티, 치즈, 야채 등 여러 가지 재료가 들어갈 수 있다.
우리는 손님이 원하는 재료만 추가하면서 햄버거를 만들 수 있도록 빌더 패턴을 적용할 수 있다.
class Burger {
constructor(builder) {
this.bun = builder.bun;
this.patty = builder.patty;
this.cheese = builder.cheese;
this.lettuce = builder.lettuce;
this.tomato = builder.tomato;
}
describe() {
return `버거 구성: ${this.bun} 번, ${this.patty} 패티, ${this.cheese ? '치즈 있음' : '치즈 없음'},
${this.lettuce ? '상추 있음' : '상추 없음'}, ${this.tomato ? '토마토 있음' : '토마토 없음'}`;
}
static get Builder() {
return class {
setBun(bun) { this.bun = bun; return this; }
setPatty(patty) { this.patty = patty; return this; }
addCheese() { this.cheese = true; return this; }
addLettuce() { this.lettuce = true; return this; }
addTomato() { this.tomato = true; return this; }
build() { return new Burger(this); }
};
}
}
// 햄버거 만들기
const myBurger = new Burger.Builder()
.setBun("참깨")
.setPatty("소고기")
.addCheese()
.addLettuce()
.build();
console.log(myBurger.describe());
🛠 결과:
버거 구성: 참깨 번, 소고기 패티, 치즈 있음, 상추 있음, 토마토 없음
- setBun(), setPatty() 등을 이용해 원하는 재료만 추가할 수 있음.
- build() 메서드를 호출하면 최종적으로 Burger 객체가 생성됨.
예제 2: 자동차 만들기
class Car {
constructor(builder) {
this.make = builder.make;
this.model = builder.model;
this.year = builder.year;
}
describe() {
return `${this.year}년식 ${this.make} ${this.model}`;
}
static get Builder() {
return class {
setMake(make) { this.make = make; return this; }
setModel(model) { this.model = model; return this; }
setYear(year) { this.year = year; return this; }
build() { return new Car(this); }
};
}
}
// 자동차 객체 생성
const myCar = new Car.Builder()
.setMake("Tesla")
.setModel("Model Y")
.setYear(2024)
.build();
console.log(myCar.describe()); // "2024년식 Tesla Model Y"
- 원하는 속성만 선택적으로 설정할 수 있음.
- 객체를 쉽게 조립하듯 만들 수 있음.
정리
✔ 빌더 패턴은 객체를 만들 때 필요한 속성을 하나씩 설정하며 유연하게 생성할 수 있도록 도와줌.
✔ 복잡한 생성자보다 가독성이 뛰어나고 유지보수하기 쉬움.
✔ 메서드 체이닝을 사용해 직관적인 코드 작성이 가능.
✔ 옵션이 많은 객체 생성에 적합 (예: 자동차, 음식 주문, API 요청 등).
1. 클래스를 이용한 기본적인 빌더 패턴
class Car {
constructor(builder) {
this.make = builder.make;
this.model = builder.model;
this.year = builder.year;
}
toString() {
return `${this.year} ${this.make} ${this.model}`;
}
static get Builder() {
class Builder {
setMake(make) { this.make = make; return this; }
setModel(model) { this.model = model; return this; }
setYear(year) { this.year = year; return this; }
build() { return new Car(this); }
}
return Builder;
}
}
const car = new Car.Builder()
.setMake("Tesla")
.setModel("Model 3")
.setYear(2023)
.build();
console.log(car.toString()); // "2023 Tesla Model 3"
2. 객체 리터럴을 이용한 빌더 패턴
const carBuilder = {
make: "",
model: "",
year: 0,
setMake(make) { this.make = make; return this; },
setModel(model) { this.model = model; return this; },
setYear(year) { this.year = year; return this; },
build() { return { make: this.make, model: this.model, year: this.year }; }
};
const car2 = carBuilder
.setMake("Toyota")
.setModel("Corolla")
.setYear(2022)
.build();
console.log(car2); // { make: "Toyota", model: "Corolla", year: 2022 }
3. 함수형 빌더 패턴
const createCarBuilder = () => {
let car = {};
return {
setMake: (make) => { car.make = make; return carBuilder; },
setModel: (model) => { car.model = model; return carBuilder; },
setYear: (year) => { car.year = year; return carBuilder; },
build: () => car
};
};
const car3 = createCarBuilder()
.setMake("BMW")
.setModel("X5")
.setYear(2024)
.build();
console.log(car3); // { make: "BMW", model: "X5", year: 2024 }
4. 클로저를 활용한 빌더 패턴
function carBuilder() {
let car = {};
return {
setMake(make) { car.make = make; return this; },
setModel(model) { car.model = model; return this; },
setYear(year) { car.year = year; return this; },
build() { return car; }
};
}
const car4 = carBuilder()
.setMake("Hyundai")
.setModel("Sonata")
.setYear(2021)
.build();
console.log(car4); // { make: "Hyundai", model: "Sonata", year: 2021 }
5. 프로토타입을 이용한 빌더 패턴
function CarBuilder() {}
CarBuilder.prototype.setMake = function(make) { this.make = make; return this; };
CarBuilder.prototype.setModel = function(model) { this.model = model; return this; };
CarBuilder.prototype.setYear = function(year) { this.year = year; return this; };
CarBuilder.prototype.build = function() { return { make: this.make, model: this.model, year: this.year }; };
const car5 = new CarBuilder()
.setMake("Honda")
.setModel("Civic")
.setYear(2020)
.build();
console.log(car5); // { make: "Honda", model: "Civic", year: 2020 }
6. 커스텀 데이터 타입을 위한 빌더 패턴
class User {
constructor(builder) {
this.name = builder.name;
this.age = builder.age;
this.email = builder.email;
}
static get Builder() {
return class {
setName(name) { this.name = name; return this; }
setAge(age) { this.age = age; return this; }
setEmail(email) { this.email = email; return this; }
build() { return new User(this); }
};
}
}
const user = new User.Builder()
.setName("John Doe")
.setAge(30)
.setEmail("john@example.com")
.build();
console.log(user); // User { name: "John Doe", age: 30, email: "john@example.com" }
7. 스프레드 연산자를 활용한 빌더 패턴
const personBuilder = (defaults = {}) => ({
...defaults,
setName(name) { return personBuilder({ ...this, name }); },
setAge(age) { return personBuilder({ ...this, age }); },
setEmail(email) { return personBuilder({ ...this, email }); },
build() { return this; }
});
const person = personBuilder()
.setName("Alice")
.setAge(25)
.setEmail("alice@example.com")
.build();
console.log(person); // { name: "Alice", age: 25, email: "alice@example.com" }
8. 데이터베이스 연결을 위한 빌더 패턴
class DatabaseConnection {
constructor(builder) {
this.host = builder.host;
this.port = builder.port;
this.username = builder.username;
this.password = builder.password;
}
static get Builder() {
return class {
setHost(host) { this.host = host; return this; }
setPort(port) { this.port = port; return this; }
setUsername(username) { this.username = username; return this; }
setPassword(password) { this.password = password; return this; }
build() { return new DatabaseConnection(this); }
};
}
}
const db = new DatabaseConnection.Builder()
.setHost("localhost")
.setPort(5432)
.setUsername("admin")
.setPassword("secret")
.build();
console.log(db);
9. REST API 요청 빌더 패턴
class ApiRequest {
constructor(builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers;
this.body = builder.body;
}
static get Builder() {
return class {
setUrl(url) { this.url = url; return this; }
setMethod(method) { this.method = method; return this; }
setHeaders(headers) { this.headers = headers; return this; }
setBody(body) { this.body = body; return this; }
build() { return new ApiRequest(this); }
};
}
}
const request = new ApiRequest.Builder()
.setUrl("https://api.example.com/data")
.setMethod("POST")
.setHeaders({ "Content-Type": "application/json" })
.setBody(JSON.stringify({ key: "value" }))
.build();
console.log(request);
10. WebSocket 빌더 패턴
class WebSocketBuilder {
constructor() {
this.url = "";
this.protocols = [];
}
setUrl(url) { this.url = url; return this; }
setProtocols(protocols) { this.protocols = protocols; return this; }
build() { return new WebSocket(this.url, this.protocols); }
}
const ws = new WebSocketBuilder()
.setUrl("wss://example.com/socket")
.setProtocols(["json"])
.build();
console.log(ws);
728x90
반응형
'웹개발 > javascript' 카테고리의 다른 글
[자바스크립트] 프록시(Proxy) 패턴 (0) | 2025.03.17 |
---|---|
[자바스크립트] 옵저버 패턴 (0) | 2025.03.17 |
[자바스크립트] 팩토리 패턴 (0) | 2025.03.17 |
[자바스크립트] 싱글톤(Singleton) 패턴 (0) | 2025.03.17 |
[자바스크립트] 디자인 패턴 소개 (0) | 2025.03.17 |