[C# 디자인 패턴] 빌더 디자인 패턴 및 Fluent Builder

참고


Builder 디자인 패턴이란?

  • 빌더 디자인 패턴은 한 번에 한 단계씩 개체를 생성할 수 있는 생성 디자인 패턴입니다.
  • 복잡한 객체를 생성할 때 이 패턴을 사용하는 것은 매우 일반적입니다.
  • 이 패턴을 사용하여 단계별로 개체의 다른 부분을 만든 다음 모든 부분을 연결할 수 있습니다.
  • 이 패턴이 없으면 객체를 구성하는 데 필요한 모든 매개변수를 제공하는 큰 생성자로 끝낼 수 있습니다.

Builder 디자인 패턴 구현하기

  • Builder 디자인 패턴을 어떻게 구현하는지 예제 코드를 작성해 봅니다.

Product 클래스

public class Product
{
    public string Name { get; set; }
    public double Price { get; set; }
}
  • 단일 제품에 대한 몇 가지 기본 데이터를 저장하기 위해 해당 클래스를 사용할 것입니다.
  • ProductStockReport 클래스는 HeaderPart, BodyPart, FooterPart 부분으로 구성됩니다.
public class ProductStockReport
{
    public string HeaderPart { get; set; }
    public string BodyPart { get; set; }
    public string FooterPart { get; set; }
    public override string ToString() =>
        new StringBuilder()
        .AppendLine(HeaderPart)
        .AppendLine(BodyPart)
        .AppendLine(FooterPart)
        .ToString();
}
  • 위 객체는 Builder 디자인 패턴으로 빌드할 객체입니다.
  • 다음은 Builder 인터페이스 입니다.
public interface IProductStockReportBuilder
{
    void BuildHeader();
    void BuildBody();
    void BuildFooter();
    ProductStockReport GetReport();
}
  • 이 인터페이스를 구현할 구체적인 빌더 클래스가 ProductStockReport 객체에 대한 모든 부분을 만들고 해당 객체도 반환해야 함을 알 수 있습니다.
  • 이제 IProductStockReportBuilder 인터페이스를 상속받는 구현체를 구현해 봅니다.
public class ProductStockReportBuilder : IProductStockReportBuilder
{
    private ProductStockReport _productStockReport;
    private IEnumerable<Product> _products;
    public ProductStockReportBuilder(IEnumerable<Product> products)
    {
        _products = products;
        _productStockReport = new ProductStockReport();
    }
    public void BuildHeader()
    {
        _productStockReport.HeaderPart = $"STOCK REPORT FOR ALL THE PRODUCTS ON DATE: {DateTime.Now}\n";
    }
    public void BuildBody()
    {
        _productStockReport.BodyPart = string.Join(Environment.NewLine, _products.Select(p => $"Product name: {p.Name}, product price: {p.Price}"));
    }
    public void BuildFooter()
    {
        _productStockReport.FooterPart = "\nReport provided by the IT_PRODUCTS company.";
    }
    public ProductStockReport GetReport()
    {
        var productStockReport = _productStockReport;
        Clear();
        return productStockReport;
    }
    private void Clear() => _productStockReport = new ProductStockReport();
}
  • 이 로직은 매우 간단합니다.
  • 보고서에 필요한 모든 제품을 수신하고 _productStockReport개체를 인스턴스화합니다.
  • 그런 다음 객체의 모든 부분을 만들고 마지막으로 반환합니다.
  • GetReprot 메서드에서 객체를 재설정하고 다른 보고서를 만들 준비가 되도록 새 인스턴스를 준비합니다.
  • 빌드 로직이 끝나면 클라이언트 클래스에서 객체 빌드를 시작하거나 Director 클래스 내부의 클라이언트 클래스에서 빌드 프로세스를 캡슐화할 수도 있습니다.
public class ProductStockReportDirector
{
    private readonly IProductStockReportBuilder _productStockReportBuilder;
    public ProductStockReportDirector(IProductStockReportBuilder productStockReportBuilder)
    {
        _productStockReportBuilder = productStockReportBuilder;
    }
    public void BuildStockReport()
    {
        _productStockReportBuilder.BuildHeader();
        _productStockReportBuilder.BuildBody();
        _productStockReportBuilder.BuildFooter();
    }
}

StockReport 객체 생성

class Program
{
    static void Main(string[] args)
    {
        var products = new List<Product>
        {
            new Product { Name = "Monitor", Price = 200.50 },
            new Product { Name = "Mouse", Price = 20.41 },
            new Product { Name = "Keyboard", Price = 30.15}
        };
        var builder = new ProductStockReportBuilder(products);
        var director = new ProductStockReportDirector(builder);
        director.BuildStockReport();
        var report = builder.GetReport();
        Console.WriteLine(report);
    }
}

Fluent Builder 생성

  • Flunet Builder 는 빌더 디자인 패턴의 작은 변형으로 빌더 호출을 다른 작업으로 연결할 수 있습니다.
  • Fluent 빌더를 구현하기 위해 먼저 빌더 인터페이스를 변경합니다.
public interface IProductStockReportBuilder
{
    IProductStockReportBuilder BuildHeader();
    IProductStockReportBuilder BuildBody();
    IProductStockReportBuilder BuildFooter();
    ProductStockReport GetReport();
}
  • ProductStockReportBuilder 클래스의 구현도 수정합니다.
public IProductStockReportBuilder BuildHeader()
{
    _productStockReport.HeaderPart = $"STOCK REPORT FOR ALL THE PRODUCTS ON DATE: {DateTime.Now}\n";
    return this;
}
public IProductStockReportBuilder BuildBody()
{
    _productStockReport.BodyPart = string.Join(Environment.NewLine, _products.Select(p => $"Product name: {p.Name}, product price: {p.Price}"));
    return this;
}
public IProductStockReportBuilder BuildFooter()
{
    _productStockReport.FooterPart = "\nReport provided by the IT_PRODUCTS company.";
    return this;
}
public void BuildStockReport()
{
    _productStockReportBuilder
        .BuildHeader()
        .BuildBody()
        .BuildFooter();
}

728x90

이 글을 공유하기

댓글

Designed by JB FACTORY