Search

빌더 패턴 (디자인 패턴)

빌더 패턴

빌더 패턴은 복잡한 객체의 생성 과정과 표현 방법을 분리하여 다양한 구성의 인스턴스를 만드는 생성 패턴입니다.
주요 특징과 장점은 다음과 같습니다
1.
복잡한 객체 생성 과정 단순화
복잡한 객체를 step-by-step으로 생성할 수 있습니다.
각 단계를 메서드 체이닝으로 연결하여 가독성 높은 코드를 작성할 수 있습니다.
2.
유연성:
같은 생성 과정으로 서로 다른 표현 결과를 만들 수 있습니다.
생성 과정을 세밀하게 나눠 필요한 데이터만 선택적으로 설정할 수 있습니다.
3.
불변성:
객체 생성이 완료된 후에는 내부 상태를 변경할 수 없어 불변성을 보장합니다.
4.
가독성:
생성자의 매개변수가 많을 때 발생하는 가독성 문제를 해결합니다.
어떤 데이터에 어떤 값이 설정되는지 명확히 알 수 있습니다.
5.
확장성:
새로운 속성이 추가되어도 기존 코드를 변경하지 않고 빌더에 새로운 메서드를 추가하면 됩니다.
빌더 패턴의 구조는 다음과 같습니다
참고
빌더 인터페이스 (Builder Interface)
모든 구상 빌더들이 따라야 하는 공통 인터페이스를 정의합니다.
제품 생성의 각 단계를 추상 메서드로 선언합니다.
이를 통해 서로 다른 유형의 빌더들이 동일한 생성 과정을 따르도록 보장합니다.
구상 빌더 (Concrete Builders)
빌더 인터페이스를 실제로 구현하는 클래스들입니다.
각 구상 빌더는 제품 생성 단계들을 자신만의 방식으로 구현합니다.
중요한 점은, 구상 빌더들이 반드시 공통 인터페이스를 따르는 제품만을 생산할 필요는 없다는 것입니다. 이는 빌더 패턴의 유연성을 보여줍니다.
제품 (Products)
빌더들에 의해 최종적으로 생성되는 객체들입니다.
서로 다른 빌더들에 의해 생성된 제품들은 반드시 같은 클래스 계층 구조나 인터페이스를 공유할 필요가 없습니다.
이는 빌더 패턴이 매우 다양한 유형의 객체들을 생성할 수 있음을 의미합니다.
디렉터 (Director) → 선택적
빌더를 사용하여 객체를 생성하는 순서를 정의합니다.
디렉터를 사용하면 특정 설정의 제품을 쉽게 재생성할 수 있습니다.
복잡한 생성 과정을 캡슐화하여 클라이언트 코드를 단순화합니다.
빌더 패턴은 다음과 같은 상황에서 유용합니다
객체 생성 과정이 복잡하고 여러 단계를 거쳐야 할 때
같은 생성 과정으로 서로 다른 표현의 객체를 만들어야 할 때
객체 생성 코드를 제품의 코드와 분리해야 할 때
하지만 빌더 패턴은 객체 생성을 위한 별도의 Builder 클래스가 필요하므로, 클래스 수가 늘어나는 단점이 있습니다. 따라서 생성하려는 객체가 충분히 복잡할 때 사용하는 것이 좋습니다.
예를 들어, 복잡한 설정이 필요한 자동차 객체를 생성할 때 빌더 패턴을 사용하면, 엔진, 바퀴, 색상 등을 단계별로 설정하고 최종적으로 완성된 자동차 객체를 얻을 수 있습니다.
이 패턴을 통해 객체 생성의 복잡성을 관리하고, 코드의 가독성과 유지보수성을 향상시킬 수 있습니다.

예제

refactoring.guru
자동차들의 단계별 생성과 해당 자동차 모델들에 맞는 사용자 설명서들
Product 클래스들
Car: 최종적으로 생성될 자동차 객체.
Manual: 자동차 매뉴얼 객체.
Builder 인터페이스
Builder (추상 기본 클래스): 모든 빌더가 구현해야 할 메서드를 정의.
Concrete Builders
CarBuilder: 실제 Car 객체를 생성하는 빌더.
CarManualBuilder: Car의 매뉴얼을 생성하는 빌더.
Director
Director: 빌더를 사용하여 객체를 생성하는 순서를 정의.
from abc import ABC, abstractmethod # 자동차 클래스 정의 class Car: def __init__(self): self.seats = None self.engine = None self.trip_computer = None self.gps = None def __str__(self): return f"자동차 스펙: {self.seats}개의 좌석, {self.engine} 엔진, " \ f"{'트립 컴퓨터 탑재' if self.trip_computer else '트립 컴퓨터 미탑재'}, " \ f"{'GPS 탑재' if self.gps else 'GPS 미탑재'}" # 매뉴얼 클래스 정의 class Manual: def __init__(self): self.content = [] def add_content(self, content): self.content.append(content) def __str__(self): return "\n".join(self.content) # 빌더 추상 클래스 정의 class Builder(ABC): @abstractmethod def reset(self): pass @abstractmethod def set_seats(self, number): pass @abstractmethod def set_engine(self, engine): pass @abstractmethod def set_trip_computer(self, has_trip_computer): pass @abstractmethod def set_gps(self, has_gps): pass # 자동차 빌더 클래스 정의 class CarBuilder(Builder): def __init__(self): self.car = None self.reset() def reset(self): self.car = Car() def set_seats(self, number): self.car.seats = number def set_engine(self, engine): self.car.engine = engine def set_trip_computer(self, has_trip_computer): self.car.trip_computer = has_trip_computer def set_gps(self, has_gps): self.car.gps = has_gps def get_product(self): product = self.car self.reset() return product # 자동차 매뉴얼 빌더 클래스 정의 class CarManualBuilder(Builder): def __init__(self): self.manual = None self.reset() def reset(self): self.manual = Manual() def set_seats(self, number): self.manual.add_content(f"이 자동차는 {number}개의 좌석이 있습니다.") def set_engine(self, engine): self.manual.add_content(f"이 자동차는 {engine} 엔진을 탑재하고 있습니다.") def set_trip_computer(self, has_trip_computer): if has_trip_computer: self.manual.add_content("이 자동차는 트립 컴퓨터가 장착되어 있습니다.") else: self.manual.add_content("이 자동차는 트립 컴퓨터가 장착되어 있지 않습니다.") def set_gps(self, has_gps): if has_gps: self.manual.add_content("이 자동차는 GPS가 장착되어 있습니다.") else: self.manual.add_content("이 자동차는 GPS가 장착되어 있지 않습니다.") def get_product(self): product = self.manual self.reset() return product # 디렉터 클래스 정의 class Director: # 빌더를 사용하여 객체를 생성하는 순서를 정의 def construct_sports_car(self, builder): builder.reset() builder.set_seats(2) builder.set_engine("스포츠 엔진") builder.set_trip_computer(True) builder.set_gps(True) def construct_suv(self, builder): builder.reset() builder.set_seats(5) builder.set_engine("SUV 엔진") builder.set_trip_computer(True) builder.set_gps(True) # 메인 실행 코드 if __name__ == "__main__": director = Director() # 스포츠카 생성 car_builder = CarBuilder() director.construct_sports_car(car_builder) car = car_builder.get_product() print("생성된 자동차 (Car built):") print(car) # 스포츠카 매뉴얼 생성 manual_builder = CarManualBuilder() director.construct_sports_car(manual_builder) manual = manual_builder.get_product() print("\n생성된 자동차 매뉴얼 (Car manual built):") print(manual) # SUV 생성 print("\nSUV 생성 중 (Building an SUV):") director.construct_suv(car_builder) suv = car_builder.get_product() print(suv)
Python
복사

참고