Builder

2022. 2. 22. 00:00CSharp/Advance

반응형

복잡한 객체를 단계별로 구성할 수 있는 창작 디자인 패턴

동일한 구성 코드를 사용하여 객체의 다양한 유형과 표현을 생성할 수 있다.

 

문제

많은 필드와 중첩 개체를 힘들게 단계별로 초기화해야 하는 복잡한 개체를 상상해 보자. 

이러한 초기화 코드는 일반적으로 많은 매개변수가 있는 무시무시한 생성자 내부에 묻혀 있다. 

또는 더 나쁜: 클라이언트 코드 전체에 흩어져 있다. 

 

참조 : https://refactoring.guru/images/patterns/diagrams/builder/problem1-2x.png

집을 예를 들어 객체 를 생성하는 방법을 생각해 보자.

단순한 집 객체

기본 : 벽, 바닥, 문, 창문, 지붕 ( 모두  n개 이상일 수 있다.)

추가 : 뒤뜰, 난방 시스템, 배관 및 전기 배선...  또는 더 크고 밝은 집

 

가장 간단한 솔루션은 House 클래스를 확장하고 매개변수의 모든 조합을 포함하는 하위 클래스 집합을 만드는 것

이럴 경우 하위 클래스가 기능별로 다수 만들어 질 것이고  스타일 추가는 더 많은 계층 구조를 만들게 된다. 

 

다른 방법은 House 클래스를 제어하는 모든 가능한 매개 변수를 사용 하여 기본 클래스에서 바로 거대한 생성자를 만들 수 있습니다 . 이 접근 방식은 실제로 하위 클래스의 필요성을 제거하지만 또 다른 문제를 생성합니다.

 

House 별로 필요한 매개변수(기능별로)의 수가 달라서 생성자 호출이 보기 흉해 지고 생성자 관리가 힘들어 진다.

참조 : https://refactoring.guru/images/patterns/diagrams/builder/problem2-2x.png

 

해결책

객체 생성 코드를 추출하여 builders 라고 하는 별도의 객체로 이동

참조 : https://refactoring.guru/images/patterns/diagrams/builder/solution1-2x.png

class diagram

https://www.dofactory.com/net/builder-design-pattern

 

 

앞 강좌에서 AbstractFactory 로 구현한 내용을 Builder 로 변경한 예제

 

Director

public class Director
{
    public IUnitBuilder Builder { get;init;}    
    public Director(IUnitBuilder builder) => Builder = builder;
    public void BuildWeaponOnly() => Builder.BuildWeapon();
    public void BuildArmorOnly() => Builder.BuildArmor();
    public void BuildFullFeature()
    {
        Builder.BuildWeapon();
        Builder.BuildArmor();
    }
}

Parts

public interface IPart { void GetDescription(); }
public interface IWeapon : IPart { }
public class BigSword : IWeapon
{
    public void GetDescription() => Console.WriteLine("BigSword");
}
public class PoisonDagger : IWeapon
{
    public void GetDescription() => Console.WriteLine("Dagger");
}
public class DoubleDagger : IWeapon
{
    public void GetDescription() => Console.WriteLine("DoubleDagger");
}

public interface IArmor : IPart { }

public class PlateArmor : IArmor
{
    public void GetDescription() => Console.WriteLine("PlateArmor");
}
public class LeatherArmor : IArmor
{
    public void GetDescription() => Console.WriteLine("LeatherArmor");
}

public class ClothArmor : IArmor
{
    public void GetDescription() => Console.WriteLine("ClothArmor");
}

Builder

public interface IUnitBuilder
{
    public  void BuildWeapon();
    public  void BuildArmor();
    public  UnitProduct GetUnitProduct();
}
public abstract class AbstractUnitBuilder : IUnitBuilder
{
    protected UnitProduct _product { get; set; } = new UnitProduct();
    public abstract void BuildArmor();

    public abstract void BuildWeapon();

    public virtual UnitProduct GetUnitProduct() => _product;

}

public class WarriorBuilder : AbstractUnitBuilder
{
    public override void BuildArmor() => _product.Add(new PlateArmor());
    public override void BuildWeapon() => _product.Add(new BigSword());   
}

public class RogueUnitBuilder : AbstractUnitBuilder
{
    public override void BuildArmor() => _product.Add(new LeatherArmor());
    public override void BuildWeapon() => _product.Add(new PoisonDagger());

}

public class AssassinBuilder : AbstractUnitBuilder
{
    public override void BuildArmor() => _product.Add(new ClothArmor());
    public override void BuildWeapon() => _product.Add(new DoubleDagger());
}

Product

public class UnitProduct
{
    private List<IPart> _parts = new List<IPart>();
    public void Add(IPart part) =>_parts.Add(part);
    public void Show()
    {
        Console.WriteLine("\nUnit Equipments ---------");
        foreach (var part in _parts)
            part.GetDescription();
    }

}

사용

Director director = new Director(new WarriorBuilder());
director.BuildFullFeature();
director.Builder.GetUnitProduct().Show();

director = new Director(new RogueUnitBuilder());
director.BuildFullFeature();
director.Builder.GetUnitProduct().Show();

director = new Director(new  AssassinBuilder());
director.BuildFullFeature();
director.Builder.GetUnitProduct().Show();
// output
Unit Equipments ---------
BigSword
PlateArmor

Unit Equipments ---------
Dagger
LeatherArmor

Unit Equipments ---------
DoubleDagger
ClothArmor

 

관련영상

https://youtu.be/iQLf_VYEzkc

 

 

 

반응형

'CSharp > Advance' 카테고리의 다른 글

Prototype  (0) 2022.02.24
Factory Method  (0) 2022.02.23
Abstract Factory  (0) 2022.02.21
Parallel Programming (PLINQ Optimizing and Parallel Class)  (0) 2022.02.18
Parallel Programming (PLINQ)  (0) 2022.02.17