빌더 패턴

빌더 패턴이란

빌더 패턴은 복잡한 객체 생성 과정을 단계적으로 진행할 수 있도록 돕는 생성 패턴입니다. 이 패턴에서는 객체와 객체의 생성 과정을 분리하게 됩니다.

빌더 패턴의 구성 요소

간단한 빌더 패턴

  • 제품 (Product) : 최종적으로 생성될 객체
  • 빌더 (Builder) : 제품을 생성하는 방법과 단계를 정의한 객체
  • Java 의 lombok 의 @builder 가 이러한 패턴을 가진다.

전통적인 빌더 패턴

  • 제품 (Product) : 최종적으로 생성될 객체
  • 빌더 (Builder) : 제품을 생성하는 방법에 대한추상 인터페이스
  • 구상 빌더 (Concrete Builder) : 앞서 정의된 생성 단계들을 상속받아 다양하게 구현한다.
  • (선택사항) 디렉터 (Director) : 빌더를 이용해 제품의 생성 순서를 정의한다.

예제

Java lombok 의 @builder

1
2
3
4
5
6
7
8
9
10
11
// Product
import lombok.Builder;
import lombok.ToString;

@Builder
@ToString
public class User {
    private String name;
    private int age;
    private String email;
}
1
2
3
4
5
6
7
8
9
10
// 빌더를 이용한 객체 생성
public static void main(String[] args) {
	User user = User.builder()
					.name("Alice")
					.age(30)
					.email("alice@example.com")
					.build();

	System.out.println(user);
}

Python 에서 빌더 패턴 따라해보기

  • lombok 에서 사용하는 builder 패턴을 파이썬에서 따라해보면 아래와 같다.
1
2
3
4
5
6
# Product
class User:
	def __init__(self):
		self.name: str  = ""
		self.age: int   = 0
		self.email: str = ""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Builder
class UserBuilder:

	def __init__(self):
		self.user = User()

	def set_name(self, name:str):
		self.user.name = name
		return self

	def set_age(self, age:int):
		self.user.age = age
		return self

	def set_email(self, email:str):
		self.user.email = email
		return self

	def build(self):
		return self.user
1
2
3
4
5
6
7
8
# builder 사용
user = UserBuilder().set_name(name="홍길동")\
					.set_age(age=20)\
					.set_email(email="hong@abc.com")\
					.build()

print(user.__dict__)
>> {'name' : "홍길동", 'age' : 20, 'email' : "hong@abc.com"}

Pydantic

  • 하지만 파이썬에서는 Pydantic 을 사용하면 이와 같은 빌더 패턴을 사용할 필요가 없다.
1
2
3
4
5
6
7
# Product
from pydantic import BaseModel

class User(BaseModel):
	name: str
	age: int
	email: str
1
2
3
4
5
6
7
8
9
# 클래스 생성  
user = User(
			name = "홍길동",
			age = 20,
			email = "hong@abc.com"
		)

print(user.__dict__)
>> {'name' : "홍길동", 'age' : 20, 'email' : "hong@abc.com"}
  • 또한 .model_copy(update={...}) 메서드를 사용하면 필드 업데이트도 가능하다.
1
2
3
4
new_user = user.model_copy(update={"age":30})

print(user.__dict__)
>> {'name' : "홍길동", 'age' : 30, 'email' : "hong@abc.com"}

빌더 패턴의 장단점

장점 - 객체들을 단계별로 생성할 수 있어, 복잡한 생성을 단순화할 수 있다.
- 객체 생성의 유연성을 높일 수 있다.
- 단일 책임 원칙에 따르며, 복잡한 생성 코드를 고립시킬 수 있다.
- 객체 생성 시 유효성 검증(필드에 대한 유효성 검증 등)을 수행할 수 있다.
단점 - 코드의 길이가 늘어날 수 있다.
- 객체 생성 부분 자체는 단순해지지만, 전반적인 코드의 복잡성이 올라갈 수 있다.
- 객체 생성 시간이 조금 더 늘어날 수 있다. (미미함)

Reference

https://refactoring.guru/ko/design-patterns/builder
https://python101.tistory.com

Comments