들어가며
개발을 하면서 빌더 패턴에 대해서 정확히 알지 못한 상태로 사용 중이었다. 모르고 쓰는 것에 답답함을 느껴 찾아보게 되었다. 두고두고 볼 용도로 공부한 내용을 정리하고자 한다.
Builder Pattern 이란?
- 클래스의 구축을 단순화하고, 사용자가 전문 지식 없이 클래스를 구축할 때 사용하는 패턴이다.
- 생성 패턴(인스턴스를 만드는 절차를 추상화하는 패턴)의 일종이다.
언제 쓰는가?
“The builder pattern itself is used to separate the construction of complex object from its presentation.” - Wikipedia
예를 들어 함수가 여러 개의 인자를 받고 있고, 중간 중간에 null 값을 넘겨줘야 하는 인자가 있을 경우
complicatedMethod('HELLO', true, 3.141592, null, null, 'BYE');
다음과 같이 쓰는 경우가 있을 수 있다.
해당 코드를 살펴보면,
- 함수 사용자가 인자의 자리를 고려하여 직접 입력할 인자가 너무 많다.
- 각각의 인자가 어떤 값을 가리키는지 한 눈에 파악하기 어렵다.
- 거기다가 null과 같은 값까지 중간중간 직접 넘기면 코드를 처음 보는 사람은 당황할 수 있다.
builder 패턴을 사용하면 각각의 인자가 어떤 값을 가리키는지 한 눈에 파악할 수 있으며, 필요하지 않은 값은 더 이상 추가해주지 않아도 된다.
예시
builder 패턴 적용 전
다음과 같이 name, age 프로퍼티를 가진 User 인터페이스가 있다.
export interface User {
name: string;
age: number;
}
우리는 User 인터페이스의 인스턴스를 만들고자 한다.
const user: User = {
name: "John",
age: 16
};
user 객체의 name 프로퍼티 값의 첫번째 글자가 대문자인지 확인하고자 한다.
그렇다면 위와 같이 무작위의 age 값을 집어넣고 user 객체를 생성해주면 된다.
지금 User 인터페이스의 프로퍼티가 단 두 개이기 때문에 user 객체 생성이 그렇게 복잡하지 않다.
하지만, 다음과 같이 만약 User 인터페이스가 name 이외에 5가지의 프로퍼티를 가지고 있다면 어떨까?
export interface User {
name: string;
age: number;
gender: string;
height: number;
weight: number;
job: string;
}
user 객체 생성 시 매번 각 프로퍼티에 대한 값을 제공해줘야 할 것이다.
const user: User = {
name: "John",
age: 16,
gender: "Male",
height: 171,
weight: 65,
job: "student"
};
모든 테스트는 수많은 프로퍼티들을 가진 복잡한 객체를 가지게 될 것이다.
이와 같이 복잡한 객체 생성 문제를 builder pattern을 적용하여 해결할 수 있다.
import { User } from "./user";
export class UserBuilder {
private readonly _user: User;
constructor() {
// each property's default value
this._user = {
name: "",
age: 0
};
}
name(name: string): UserBuilder {
this._user.name = name;
return this;
}
age(age: number): UserBuilder {
this._user.age = age;
return this;
}
build(): User {
return this._user;
}
}
UserBuilder 사용하기
UserBuilder를 사용하는 경우 우린 이제 더 이상 신경 쓸 필요가 없는 다른 프로퍼티들을 생략하고 user 객체를 생성할 수 있다.
const userWithName: User = new UserBuilder().name("Ron").build();
age 값은 설정하지 않아도 되고, 다른 프로퍼티들 또한 설정해주지 않아도 된다.
우리가 필요한 프로퍼티들만 설정해주면 된다.
이외에도,
gender를 기준으로 특정 사용자들에 대해 다른 광고를 보여주는 코드를 작성하고자 한다. 이때 생성되는 user 객체는 다음과 같다.
const userWithGender: User = new UserBuilder().gender("Female").build();
매우 간단하지 않은가? gender 를 제외한 name, age 등 다른 프로퍼티들에 대해서는 전혀 신경쓰지 않아도 된다.
결론
객체 표현 코드는 builder를 사용하여 믿기 어려울 정도로 간단해진 반면 객체는 내가 원하는 대로 복잡해질 수 있다.
참조
'프로그래밍 언어 > TypeScript' 카테고리의 다른 글
[TypeScript] Conditional Types, extends, infer (0) | 2022.12.25 |
---|---|
[TypeScript] 기본 타입 (0) | 2022.12.20 |
TypeScript 언어 소개 및 장점 및 단점, 컴파일러 동작 방식 (0) | 2022.11.14 |