[디자인 패턴][생성 패턴] 빌더 패턴(Builder Pattern)
Updated:
1. 개요
복잡한 객체를 생성하는 방법과 표현하는 방법을 정의하는 클래스를 별도로 분리하여, 서로 다른 표현이라도 이를 생성할 수 있는 동일한 절차를 제공하는 패턴
빌더 패턴(Builder Pattern)은 생성 패턴(Creational Pattern)의 한 종류로, 빌더 객체의 인터페이스를 통해 필요한 객체를 차례대로 전달하고, 전달 받은 객체들을 조합하여 하나의 완성된 객체를 반환해주는 패턴이다.
2. 생성 패턴(Creational Pattern)
2-1. 생성 패턴이란?
생성 패턴이란 인스턴스를 만드는 절차를 추상화하는 패턴으로, 객체를 생성, 합성하는 방법이나 객체의 표현 방법과 시스템을 분리해 준다. 생성 패턴은 아래 두 가지 특징으로 인해 무엇이, 어떻게, 언제 생성되는지 결정하는데 유연성을 확보할 수 있다.
-
시스템이 어떤 구체 클래스를 사용하는지에 대한 정보를 캡슐화 한다.
-
인스턴스들이 어떻게 만들고, 결합하는지에 대한 부분을 완전히 가려준다.
2-2. 생성 패턴 종류
3. 구성
[출처 : GoF의 디자인 패턴]
-
Builder : 객체의 요소들을 생성하기 위한 추상 클래스
-
ConcreteBuilder : Builder가 정의한 메서드 구현
-
Director : Builder 인터페이스를 사용하는 객체를 합성
-
Product : 생성할 복합 객체를 표현
4. 예제 코드
커피를 만드는 과정을 구현한다고 가정해보자. 커피를 만들기 위해 필요한 재료들을 정해놓고(Builder), 바리스타가 해당 재료들을 조합하여 커피를 만들어낼 수 있다(Director).
4-1. Product
[Coffee.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Coffee {
private String liquid = "";
private String beans ="";
private String syrup = "";
public String getLiquid() {
return liquid;
}
public void setLiquid(String liquid) {
this.liquid = liquid;
}
public String getBeans() {
return beans;
}
public void setBeans(String beans) {
this.beans = beans;
}
public String getSyrup() {
return syrup;
}
public void setSyrup(String syrup) {
this.syrup = syrup;
}
}
4-2. Builder
[CoffeeBuilder.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
abstract class CoffeeBuilder {
protected Coffee coffee;
public Coffee getCoffee() {
return coffee;
}
public void makeCoffee() {
coffee = new Coffee();
}
public abstract void buildLiquid();
public abstract void buildBeans();
public abstract void buildSyrup();
}
4-3. ConcreteBuilder
[VanillaLatteBuilder.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class VanillaLatteBuilder extends CoffeeBuilder {
@Override
public void buildLiquid() {
coffee.setLiquid("Milk");
}
@Override
public void buildBeans() {
coffee.setBeans("Kenya Beans");
}
@Override
public void buildSyrup() {
coffee.setSyrup("Vanilla Syrup");
}
}
4-4. Director
[Barista.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Barista {
private CoffeeBuilder coffeeBuilder;
public void setCoffeeBuilder(CoffeeBuilder coffeeBuilder) {
this.coffeeBuilder = coffeeBuilder;
}
public Coffee getCoffee() {
return coffeeBuilder.getCoffee();
}
public void constructCoffee() {
coffeeBuilder.makeCoffee();
coffeeBuilder.buildLiquid();
coffeeBuilder.buildBeans();
coffeeBuilder.buildSyrup();
}
}
5. 테스트
[Client.java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Client {
public static void main(String[] args) {
Barista barista = new Barista();
CoffeeBuilder vanillaLatteBuilder = new VanillaLatteBuilder();
barista.setCoffeeBuilder(vanillaLatteBuilder);
barista.constructCoffee();
Coffee vanillaLatte = barista.getCoffee();
System.out.println("액체 : " + vanillaLatte.getLiquid());
System.out.println("원두 : " + vanillaLatte.getBeans());
System.out.println("시럽 : " + vanillaLatte.getSyrup());
}
}
[실행 결과]
6. 특징
-
내부 표현을 다양하게 변화 가능 : 빌더 추상 클래스를 상속받는 새로운 빌더를 정의하여 원하는 형태의 객체를 생성 가능
-
생성과 표현의 코드 분리 : 내부 구조를 몰라도 빌더와의 상호작용을 통해 객체 생성 가능
-
객체 생성 절차의 세밀화 : 전달받은 객체들을 조합하여 하나의 객체를 반환하기 전까지, 내부 구성요소를 하나씩 추가하며 과정 확인 가능
Leave a comment