Design Pattern, Builder

2021. 12. 29. 00:59ETC/Design Patterns

Builder Pattern

 

Separate the construction of a complex object from its representation so that the same construction process can create different representations.

- GoF Design Patterns

 

빌더 패턴은 복잡한 객체를 생성하는 클래스와 표현하는 클래스를 분리하여, 동일한 절차에서도 서로 다른 표현을 생성하는 방법을 제공합니다. 추상 팩토리를 확장하여 크고 복잡한 객체를 생성할 수 있습니다.

 

Builder의 사전적 의미는 ‘건축물을 짓는 사람 또는 회사’. 즉, 커다란 구조의 큰 물체를 설계하고 만드는 것을 의미합니다.

 

 

왜 필요할까?

생성 패턴의 주요 목적은 객체의 생성 과정을 한 곳에 집중화하는 것입니다. 패턴을 사용하여 객체의 생성 관리하는 이유는 인스턴스화 과정에서 발생하는 강력한 의존 관계를 해소하기 위함입니다.

또, 복잡한 구조를 가진 복합 객체의 생성과정을 분리하여 처리할 수 있습니다.

 

 

복합 객체 

객체 지향에서 객체는 단일 객체, 복합 객체으로 나눌 수 있습니다.

단일 객체란 하나의 클래스로 생성된 객체이며, 복합 객체란 하나의 객체가 다른 객체를 포함하는 관계 구조입니다.

 

객체는 데이터와 행동을 가지며, 객체를 확장하기 위해 상속 구조를 적용합니다. 하지만 상속에서는 강력한 상하 결합 관계와 불필요한 모든 행위까지 포함된다는 단점도 있습니다. 그래서 객체 지향에서는 상속의 단점을 개선하기 위해 의존성 주입을 사용하곤 하는데요. 의존성을 통해 복합 객체를 생성하여 사용하는 것을 권장합니다. 복합 객체는 이에 맞게 구조적 의존 관계를 통해 객체를 확장할 수 있습니다.

 

즉, 복합 객체는 객체가 생성된 후에도 다른 객체와 관계를 설정해 동적 확장할 수 있다는 장점을 가집니다.

하지만, 복합 객체는 내부적으로 다른 클래스의 객체를 포함하고 관계 설정을 추가로 해줘야 하므로 객체를 생성하는 과정이 단일 객체보다 복잡합니다. 복합 객체를 생성할 때는 객체의 구조 순서에 맞게 단계별로 실행되어야 하죠.

 

 

생성 패턴 : 복합 객체

많은 디자인 패턴의 원리와 목적은 상속 결합을 배제하고 의존 관계의 복합 객체로 변경하여 처리하는 것입니다.

복합 객체 사용을 중요시하는 것이 최신 객체 지향 트렌드이지만 팩토리, 팩토리 메서드, 추상 메서드 패턴으로는 복합 객체를 생성할 수 없습니다. 기존 생성 패턴의 한계로 인해 복합 객체 생성을 처리할 수 있는 또 다른 패턴이 필요해졌고, 빌더 패턴은 복잡한 구조의 복합 객체를 생성하는 로직을 별도로 분리하여 객체 생성을 처리합니다.

 

빌더 패턴은 복잡한 구조를 가진 복합 객체의 생성 과정을 분리하여 처리할 수 있습니다. 복합 객체의 생성 과정을 단계별로 분리함으로써 복합 객체의 생성을 일반화할 수 있습니다.

 

 

Builder 구조

 

https://ko.wikipedia.org/wiki/%EB%B9%8C%EB%8D%94_%ED%8C%A8%ED%84%B4

 

Product라는 객체를 생성하고자 할 때,

Product를 프로퍼티로 갖는 추상 객체 Builder를 정의하고 실제 세부 구현 객체인 ConcreteBuilder를 정의합니다.

이 Builder와 ConcreteBuilder에는 Product를 생성할 때 필요한, Product 프로퍼티를 각각 설정하는 setter등을 정의할 수 있습니다.

Director에는 프로퍼티로 Builder를 가지고, construct 세부 생성 로직을 구현합니다.

 

그리고 이 Product를 생성하고자 할 때에는  Director의 구현한 세부 생성 로직인 construct를 불러옵니다.

 

 

 

빌더 패턴은 추상 메서드를 통해 복합 객체 생성 방법을 달리 적용할 수 있습니다.

아래의 코드를 보면 Pizza(Product)를 제작할 때 HawaiianPizza Builder와 SpicyPizza Builder를 따로 적용한 것을 확인할 수 있습니다.

 

또한 복합 객체의 생성 로직을 직접 클라이언트 코드로 구현하거나 메서드를 호출하지 않으며, 독립적인 단계별 구축 공정을 분리하여 처리합니다. 

 

추상 메서드 build() 안에는 복합 객체 생성을 위한 처리 로직들이 들어 있으며 빌더 생성 로직을 별도의 알고리즘으로 분리하여 외부로부터 주입받을 수도 있는데요. 이 예시는 깃허브 코드를 참고해주세요.

 

 

Sample Code : Java

Product

class Pizza {
	private String dough = "";
	private String sauce = "";
	private String topping = "";

	public void setDough(String dough) {
		this.dough = dough;
	}

	public void setSauce(String sauce) {
		this.sauce = sauce;
	}

	public void setTopping(String topping) {
		this.topping = topping;
	}
}

 

Builder

abstract class PizzaBuilder {
	protected Pizza pizza;

	public Pizza getPizza() {
		return pizza;
	}

	public void createNewPizzaProduct() {
		pizza = new Pizza();
	}

	public abstract void buildDough();

	public abstract void buildSauce();

	public abstract void buildTopping();
}

 

ConcreteBuilder

class HawaiianPizzaBuilder extends PizzaBuilder {
	public void buildDough() {
		pizza.setDough("cross");
	}

	public void buildSauce() {
		pizza.setSauce("mild");
	}

	public void buildTopping() {
		pizza.setTopping("ham+pineapple");
	}
}

class SpicyPizzaBuilder extends PizzaBuilder {
	public void buildDough() {
		pizza.setDough("pan baked");
	}

	public void buildSauce() {
		pizza.setSauce("hot");
	}

	public void buildTopping() {
		pizza.setTopping("pepperoni+salami");
	}
}

 

Director

class Cook {
	private PizzaBuilder pizzaBuilder;

	public void setPizzaBuilder(PizzaBuilder pizzaBuilder) {
		this.pizzaBuilder = pizzaBuilder;
	}

	public Pizza getPizza() {
		return pizzaBuilder.getPizza();
	}

	public void constructPizza() {
		pizzaBuilder.createNewPizzaProduct();
		pizzaBuilder.buildDough();
		pizzaBuilder.buildSauce();
		pizzaBuilder.buildTopping();
	}
}

 

Main

public class Main {
	public static void main(String[] args) {
		Cook cook = new Cook();
		PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder();
		PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();

		cook.setPizzaBuilder(hawaiianPizzaBuilder);
		cook.constructPizza();

		Pizza pizza = cook.getPizza();
	}
}

 

 

 

관련 패턴

C- Creational Patterns  |  S - Structural Patterns  |  B - Behavioral Patterns

 

C: Abstract Factory

빌더 패턴은 추상화 작업으로 다양한 복합 객체의 생성 그룹을 만들 수 있습니다. 추상화를 통해 그룹을 관리하는 것은 추상 패토리와 유사하며, 빌더 패턴은 추상 팩토리를 확장하여 복합 객체를 생성합니다.

✔️ Factory - 팩토리 패턴은 단일 클래스의 객체만 생성, 반환하므로 요청된 객체가 복합객체일 경우 팩토리 패턴을 적용할 수 없음

 

S: Composite

빌더는 복잡한 복합 객체를 생성합니다. 복합 객체는 다른 객체를 포함하며 복합체 패턴과 유사한 구조를 가집니다.

 

S: Facade

복합 객체의 생성 로직은 Builder 객체에서 조합하며 외부에서는 빌더 패턴이 복합 객체를 생성하는 내부 구조를 알지 못합니다. 클라이언트는 빌더 패턴의 복잡한 구조를 알 수가 없으며, 외부에 공개된 생성 메서드만 호출하면 복합 객체를 생성할 수 있습니다.

 

B: Template Method

빌더 패턴의 Builder는 객체를 건축하는 행위이며 실제로 객체 생성 로직을 분리합니다. 상위 클래스에는 추상 메서드를 선언하기만 하고, 하위 클래스에는 실제 구현 메서드를 오버라이드합니다.

 

 

 

그럼 지금까지 Builder Pattern에 대해 알아보았습니다.

오타나 잘못된 내용이 있다면 댓글로 남겨주세요!

감사합니다 ☺️ 

 

 

 

모든 Design Patterns 모아보기

 

Design Patterns

안녕하세요. GoF 디자인 패턴을 정리하고자 합니다. 디자인 패턴은 일주일 전부터 공부를 시작했는데, 스스로 설명하듯 적는게 익히는데 도움이 클 것같아 정말 오랜만에 시리즈로 포스팅하려

gngsn.tistory.com

 

 

 

참고 

Builder Pattern - Wikipedia

'ETC > Design Patterns' 카테고리의 다른 글

Design Pattern, Factory Method  (0) 2022.01.03
Design Pattern, Template Method  (0) 2022.01.01
Design Pattern, Strategy  (0) 2021.12.29
Design Pattern, Facade  (0) 2021.12.26
Design Patterns, 제대로 이해하기  (1) 2021.12.26