CS/디자인패턴

[디자인패턴] Builder 패턴 (빌더)

mabb 2023. 6. 2. 13:51
반응형

▶디자인 패턴 ( Design Pattern)

:프로그램 개발 시 문제 해결을 위하여 빈번히 사용되는 개발자들의 경험, 내적인 축적에 대하여,
GoF(Gang of Four) 라 불리는 4인의 개발자들이 각각을 패턴으로 정의하고 이름을 붙였다.
이를 디자인 패턴 (Design Pattern) 이라고 한다.
 23개의 디자인 패턴을
『Elements of Reusable Object-Oriented Software』
라는 책으로 발간하였다.

Gang of Four 분들은 모두 안경을 썼다.

 

▷디자인 패턴의 용어를 빌리면 서로의 아이디어를 보다 용이하게 비교, 논의할 수 있게 된다.
▷재사용과 기능확장이 쉬운 소프트웨어를 만들기 위한 유익한 기법이 바로 디자인 패턴이다.

 

---------------------------------------------------------
1. Iterator
2. Adapter
3. Template Method
4. Factory Method
5. Singleton
6. Prototype
7. Builder
8. Abstract Factory
9. Bridge
10. Strategy
11. Composite
12. Decorator
13. Visitor
14. Chain of Responsibility
15. Facade
16. Mediator
17. Observer
18. Memento
19. State
20. Flyweight
21. Proxy
22. Command
23. Interpreter
---------------------------------------------------------

▶Builder 패턴

"복잡한 객체(인스턴스)를 단계별로 생성하기"


-왜 사용하는가
-클래스다이어그램
-각 클래스(인터페이스)의 역할
-Java소스

▶Builder 패턴에 대한 이해

-객체를 생성하는 디자인 패턴

-복잡한 객체를 단계별로 생성해나가는 패턴

-객체 생성을 단계별로 빌드업 해나간다.

-객체 생성방법에는 점층적 생성자패턴, 자바빈즈패턴, 필더 패턴이 존재한다.

-구조를 가진 인스턴스를 쌓아올리는 패턴이다.

-Builder는 객체 생성 각 단계에 대한 방법을 정의한다.
ex) 인스턴스 생성을 위한 방법 step1, step2, step3

-Builder가 정의한 추상메소드는 각각의 하위 클래스에서 구체화한다.

-Director는 Builder의 메소드를 이용하여 인스턴스(객체) 를 조립(구축)한다 

-빌더는 객체 제작 단계별 방법을 구현한다.

-디렉터는 빌더의 방법을 가지고 단계별로 객체를 조립한다.

-빌더패턴에 항상 디렉터가 있지는 않다. 하지만 빌더의 방법을 가지고 다양한 객체 생성 루틴을 가지고 있는 디렉터가 있다면 편리하다.

-다양한 구상 빌더들은 다양한 방식으로 빌더가 정해놓은 작업을 실행한다.

-수많은 필드와 중첩된 객체를 힘들게 단계별로 초기화해야 하는 복잡한 객체가 있을 때
초기화 코드는 수많은 매개변수를 가진 거대한 생성자 내부에 묻혀 있을 수 있다. 
하지만 이 경우 항상 생성자의 모든 매개변수가 다 필요하지 않다.

-필드 초기화 코드가 클라이언트 코드전체에 흩어져있을 수 있다.

-점층적 생성자패턴은 메소드 오버로딩을 지원하는 Java나 C#같은 언어에서만 가능하다.

-매개변수가 다양한 여러개의 생성자를 사용하는 점층적 생성자 패턴을 빌더패턴으로 바꿀 수 있다.

-빌더는 공통 생성 단계별 방법을 명확하게 정의해야 한다.

-SRP. 복잡한 객체 생성 코드를 분리한다.

-팩토리메소드로 시작해 빌더패턴, 추상팩토리패턴, 프로토타입패턴으로 발전한다.

-빌더패턴은 복잡한 객체의 단계별 생성에 주안점

-추상팩토리 패턴은 관련객체 패밀리 생성에 주안점

-StringBuilder에서  빌더 패턴을 사용한다고 한다.

 

▶왜 사용하는가

복잡한 객체를 단계별로 생성할 때 사용한다. 복잡한 객체, 수많은 필드를 가진 객체를 초기화 할 때 거대한 생성자를 쓰거나,  여러개의 생성자를 점층적으로 사용하거나, 또는 객체를 초기화 하는 코드가 여기저기 분산되어 있다면 아주 불편할 것이다. SRP(단일 책임원칙) 으로 객체 생성에 대한 절차를 분리하는 것이다.

 

▶클래스다이어그램

 

▶각 클래스(인터페이스)의 역할

 

클라이언트 역할 - Client.java

:디렉터를 통해 객체를 손쉽게 생성한다.

디렉터 역할 - PizzaDirector.java

:빌더를 가지고 빌더의 방법을 이용하여 인스턴스를 구축(조립)하는 다양한 루틴을 가지고 있다.

빌더 역할 - PizzaBuilder.java

;복잡한 인스턴스 구축, 조립을 위한 방법을 정의한다.

구상 빌더 역할 - BulgogiBuilder.java, HawaiianBuilder.java, PepperoniBuilder.java

:빌더의 방법을 구체화 한다.

 

 

▶Java 소스

*java1.8 이전 버전을 사용하는 교재를 참고 하였습니다.
Java API 문서 등을 참조하여 제네릭을 적용하는 등 소스를 개선할 필요가 있습니다.
(https://docs.oracle.com/en/java/javase/20/docs/api/)

Client.java

package main.java.designpattern.builder;

public class Client {

    public static void main(String[] args){

        PizzaDirector bulgogiPizzaDirector = new PizzaDirector(new BulgogiBuilder());

        PizzaDirector pepperoniPizzaDirector = new PizzaDirector(new PepperoniBuilder());

        PizzaDirector hawaiianPizzaDirector = new PizzaDirector(new HawaiianBuilder());

        //소스 없는 불고기 치즈크러스트 피자 만들기
        bulgogiPizzaDirector.makePizzaNoSauce("치즈크러스트");
        bulgogiPizzaDirector.completePizza();


        //페퍼로니피자 만들기
        pepperoniPizzaDirector.makePizza("기본도우","토마토소스");
        pepperoniPizzaDirector.completePizza();

        //기본토핑 없는 크림소스 고구마도우 하와이안 피자 만들기
        hawaiianPizzaDirector.makePizzaNoBasicTopping("고구마도우","크림소스");
        hawaiianPizzaDirector.completePizza();

    }
}

 

 

PizzaDirector.java

package main.java.designpattern.builder;

public class PizzaDirector {
    private PizzaBuilder pizzaBuilder;

    public PizzaDirector(PizzaBuilder pizzaBuilder){
        this.pizzaBuilder = pizzaBuilder;
    }

    public void makePizza(String dough, String sauce){
       pizzaBuilder.makeDough(dough);
       pizzaBuilder.addSauce(sauce);
       pizzaBuilder.addBasicTopping();
       pizzaBuilder.addSpecialTopping();
    }

    public void makePizzaNoSauce(String dough){
        pizzaBuilder.makeDough(dough);
        pizzaBuilder.addBasicTopping();
        pizzaBuilder.addSpecialTopping();
    }

    public void makePizzaNoBasicTopping(String dough, String souce){
        pizzaBuilder.makeDough(dough);
        pizzaBuilder.addSauce(souce);
        pizzaBuilder.addSpecialTopping();
    }

    public void completePizza(){
        System.out.println("피자가 완성 되었습니다. \n" + pizzaBuilder.toString());
        System.out.println();
    }
}

 

 

PizzaBuilder.java

package main.java.designpattern.builder;

public abstract class PizzaBuilder {
    public abstract void makeDough(String dough);
    public abstract void addSauce(String sauce);
    public abstract void addBasicTopping();
    public abstract void addSpecialTopping();

    @Override
    public abstract String toString ();
}

 

 

BulgogiBuilder.java

package main.java.designpattern.builder;

public class BulgogiBuilder extends PizzaBuilder {

    private String   dough;
    private String   sauce;
    private String basicTopping;
    private String   specialTopping;

    @Override
    public void makeDough(String dough) {
        this.dough = dough;
    }

    @Override
    public void addSauce(String sauce) {
        this.sauce = sauce;
    }

    @Override
    public void addBasicTopping() {
        basicTopping = "양파,옥수수,올리브,양송이";
    }

    @Override
    public void addSpecialTopping() {
        specialTopping = "불고기";
    }

    @Override
    public String toString() {
        String pizzaInfo = "[만들어진 피자의 정보]"+
                            "\n도우 : " + dough +
                            "\n소스 : " + sauce +
                            "\n기본토핑 : " + basicTopping +
                            "\n특별토핑 : " + specialTopping;

        return pizzaInfo;
    }
}

 

 

PepperoniBuilder.java

package main.java.designpattern.builder;

public class PepperoniBuilder extends PizzaBuilder {

    private String   dough;
    private String   sauce;
    private String basicTopping;
    private String   specialTopping;


    @Override
    public void makeDough(String dough) {
        this.dough = dough;
    }

    @Override
    public void addSauce(String sauce) {
        this.sauce = sauce;
    }

    @Override
    public void addBasicTopping() {
        basicTopping = "양파,옥수수,올리브,양송이";
    }

    @Override
    public void addSpecialTopping() {
        specialTopping = "페퍼로니";
    }

    @Override
    public String toString() {
        String pizzaInfo = "[만들어진 피자의 정보]"+
                "\n도우 : " + dough +
                "\n소스 : " + sauce +
                "\n기본토핑 : " + basicTopping +
                "\n특별토핑 : " + specialTopping;

        return pizzaInfo;
    }
}

 

 

HawaiianBuilder.java

package main.java.designpattern.builder;

public class HawaiianBuilder extends PizzaBuilder {

    private String   dough;
    private String   sauce;
    private String basicTopping;
    private String   specialTopping;

    @Override
    public void makeDough(String dough) {
        this.dough = dough;
    }

    @Override
    public void addSauce(String sauce) {
        this.sauce = sauce;
    }

    @Override
    public void addBasicTopping() {
        basicTopping = "양파,옥수수,올리브,양송이";
    }

    @Override
    public void addSpecialTopping() {
        specialTopping = "파인애플";
    }

    @Override
    public String toString() {
        String pizzaInfo = "[만들어진 피자의 정보]"+
                "\n도우 : " + dough +
                "\n소스 : " + sauce +
                "\n기본토핑 : " + basicTopping +
                "\n특별토핑 : " + specialTopping;

        return pizzaInfo;
    }
}

 

 

 

 

 

 

---------------------------------------------------------
※참고자료
-Java언어로 배우는 디자인 패턴 입문
-Headfirst Design Pattern
-나무위키, 위키백과, 네이버백과
-리팩토링구루(https://refactoring.guru/ko)

반응형