빌더(Builder) 패턴

2024. 10. 10. 01:02Design Pattern

디자인 패턴: 빌더(Builder) 패턴

빌더 패턴(Builder Pattern)은 복잡한 객체의 생성 과정을 단계별로 분리하여, 같은 생성 절차에서 서로 다른 표현을 만들 수 있게 하는 생성 패턴(Creational Patterns) 중 하나입니다. 이 패턴은 객체를 단계별로 구성하거나 점진적으로 구성해야 할 때 유용하게 사용됩니다. 특히, 복잡한 객체 생성 로직을 클라이언트 코드와 분리하여 가독성유지보수성을 높이는 데 기여합니다.


빌더 패턴의 개념

빌더 패턴은 객체를 생성하는 데 필요한 과정을 여러 단계로 나누고, 그 단계를 순차적으로 실행하는 구조를 따릅니다. 객체를 단계별로 구성한 후 마지막 단계에서 완성된 객체를 반환합니다. 이렇게 하면 객체 생성 과정이 복잡해지더라도 각 단계를 세분화하여 관리할 수 있습니다.

주요 구성 요소

  1. Product (제품)
    • 빌더가 생성하는 복합 객체입니다. 여러 단계에 걸쳐 빌더에 의해 생성됩니다.
  2. Builder (빌더)
    • 제품의 구성 단계를 정의하는 인터페이스입니다. 각 단계에서 필요한 구성 요소를 정의하고, 이를 통해 객체를 점진적으로 생성합니다.
  3. ConcreteBuilder (구체적인 빌더)
    • 빌더 인터페이스를 구현한 구체적인 빌더입니다. 특정 제품을 생성하는 데 필요한 단계별 구현을 제공합니다.
  4. Director (감독자)
    • 빌더를 통해 객체를 생성하는 절차를 제어합니다. 감독자는 빌더에게 객체를 생성하는 순서를 지시하며, 최종 결과물인 객체를 반환받습니다.

빌더 패턴 구현 예시

1. Product 클래스

// Product: 빌더 패턴으로 생성될 객체
public class House
{
    public string Walls { get; set; }
    public string Roof { get; set; }
    public string Foundation { get; set; }

    public override string ToString()
    {
        return $"House with {Foundation}, {Walls}, and {Roof}.";
    }
}

2. Builder 인터페이스

// Builder: House의 구성 단계 정의
public interface IHouseBuilder
{
    void BuildFoundation();
    void BuildWalls();
    void BuildRoof();
    House GetHouse();
}

3. ConcreteBuilder 클래스

// ConcreteBuilder: 구체적인 House 빌더
public class ConcreteHouseBuilder : IHouseBuilder
{
    private House _house = new House();

    public void BuildFoundation()
    {
        _house.Foundation = "Concrete Foundation";
    }

    public void BuildWalls()
    {
        _house.Walls = "Brick Walls";
    }

    public void BuildRoof()
    {
        _house.Roof = "Tile Roof";
    }

    public House GetHouse()
    {
        return _house;
    }
}

4. Director 클래스

// Director: 빌더를 통해 House 생성 과정 제어
public class HouseDirector
{
    private IHouseBuilder _builder;

    public HouseDirector(IHouseBuilder builder)
    {
        _builder = builder;
    }

    public void ConstructHouse()
    {
        _builder.BuildFoundation();
        _builder.BuildWalls();
        _builder.BuildRoof();
    }
}

5. 빌더 패턴 사용 예시

class Program
{
    static void Main(string[] args)
    {
        // ConcreteBuilder 사용
        IHouseBuilder builder = new ConcreteHouseBuilder();
        HouseDirector director = new HouseDirector(builder);

        // House 생성
        director.ConstructHouse();
        House house = builder.GetHouse();

        // 생성된 House 출력
        Console.WriteLine(house);
    }
}

출력 결과:

House with Concrete Foundation, Brick Walls, and Tile Roof.

 


빌더 패턴의 장점

  1. 복잡한 객체 생성 과정 분리
    • 객체를 생성하는 코드를 세분화하여 단계별로 관리할 수 있습니다. 각 구성 요소를 독립적으로 생성하고 조합할 수 있어, 복잡한 객체도 쉽게 만들 수 있습니다.
  2. 유연성
    • 빌더를 통해 동일한 생성 절차에서 다양한 표현의 객체를 생성할 수 있습니다. 객체 생성에 대한 제어권이 명확해지고, 필요에 따라 객체 구성을 쉽게 변경할 수 있습니다.
  3. 가독성 향상
    • 생성 과정을 단계별로 나누어 코드가 직관적이고 읽기 쉽게 됩니다. 특히, 매개변수가 많은 객체 생성 시 빌더 패턴을 사용하면 코드의 복잡도를 줄일 수 있습니다.

빌더 패턴의 단점

  1. 복잡한 구조
    • 빌더 패턴 자체가 다수의 클래스(Builder, ConcreteBuilder, Director 등)를 요구하므로, 비교적 간단한 객체를 생성하는 경우에는 오히려 불필요하게 복잡해질 수 있습니다.
  2. 객체 생성 비용 증가
    • 객체 생성 절차가 세분화되면서 빌더 객체를 추가로 생성하고 관리해야 하기 때문에, 간단한 객체 생성에는 성능상 이점이 크지 않을 수 있습니다.

빌더 패턴의 사용 사례

  1. 복잡한 객체 생성
    • 매개변수가 많은 객체를 생성할 때, 생성자의 매개변수를 잘못 전달할 위험을 줄이고 가독성을 높일 수 있습니다. 예를 들어, 복잡한 GUI 구성 요소나 다수의 옵션을 가진 객체 생성 시 유용합니다.
  2. 객체의 다양한 표현 필요
    • 동일한 생성 절차에서 서로 다른 표현을 가진 객체를 생성해야 할 때, 빌더 패턴은 유용하게 사용됩니다. 예를 들어, 게임 개발에서 다양한 캐릭터나 아이템을 생성할 때, 빌더 패턴을 활용할 수 있습니다.

빌더 패턴은 복잡한 객체를 단계적으로 생성할 수 있도록 도와주는 유용한 디자인 패턴입니다.
각 단계별로 객체를 구성하고, 필요에 따라 다양한 표현의 객체를 생성할 수 있어 유연성확장성을 제공합니다. 다만 간단한 객체를 생성하는 데는 오히려 불필요한 복잡성을 추가할 수 있으므로, 적절한 상황에서 활용하는 것이 중요합니다.