Builder Pattern은 다른 creational (제작) 패턴과 달리 Builder 는 제품에 공통 인터페이스가 필요하지 않습니다. 따라서 동일한 제작 프로세스를 사용하여 다양한 제품을 제작할 수 있습니다.
다시 말해서, Builder 패턴은 복잡한 객체를 생성하는 과정을 단계별로 나누어 구성할 수 있는 디자인 패턴입니다. 일반적으로 이 패턴은 대상 객체를 만드는 데 필요한 다양한 설정 옵션이 있거나 생성 과정이 복잡한 경우 사용됩니다. 객체에 대한 구성 정보에 따라 생성 결과를 조작하려는 경우에도 사용할 수 있습니다.
Builder 패턴의 주요 구성 요소들은 다음과 같습니다.
Director: Builder를 가리키며, 최종 결과를 생성하는 과정을 제어합니다.
Builder: 생성될 객체의 각 부분에 대한 단계별로 인터페이스를 정의합니다.
ConcreteBuilder: Builder 인터페이스를 구현한 클래스로, 실제 객체를 생성하는 과정의 로직을 포함합니다.
Product: 최종적으로 생성되는 복잡한 객체입니다.
using System;
// 각 유닛의 공통 기능을 정의할 IUnit 인터페이스
public interface IUnit
{
string Name { get; }
int HP { get; }
int AttackPower { get; }
void Attack(IUnit enemy);
void ReceiveDamage(int damage);
}
// Builder 인터페이스를 작성
public interface IUnitBuilder
{
void SetName(string name);
void SetHP(int hp);
void SetAttackPower(int attackPower);
IUnit Build();
}
public class Terran : IUnit
{
public string Name { get; set; }
public int HP { get; set; }
public int AttackPower { get; set; }
public void Attack(IUnit enemy)
{
enemy.ReceiveDamage(AttackPower);
}
public void ReceiveDamage(int damage)
{
HP -= damage;
}
}
public class Protoss : IUnit
{
public string Name { get; set; }
public int HP { get; set; }
public int AttackPower { get; set; }
public void Attack(IUnit enemy)
{
enemy.ReceiveDamage(AttackPower);
}
public void ReceiveDamage(int damage)
{
HP -= damage;
}
}
public class TerranBuilder : IUnitBuilder
{
private Terran _unit;
public TerranBuilder()
{
Reset();
}
public void Reset()
{
_unit = new Terran();
}
public void SetName(string name)
{
_unit.Name = name;
}
public void SetHP(int hp)
{
_unit.HP = hp;
}
public void SetAttackPower(int attackPower)
{
_unit.AttackPower = attackPower;
}
public IUnit Build()
{
IUnit builtUnit = _unit;
Reset();
return builtUnit;
}
}
public class ProtossBuilder : IUnitBuilder
{
private Protoss _unit;
public ProtossBuilder()
{
Reset();
}
public void Reset()
{
_unit = new Protoss();
}
public void SetName(string name)
{
_unit.Name = name;
}
public void SetHP(int hp)
{
_unit.HP = hp;
}
public void SetAttackPower(int attackPower)
{
_unit.AttackPower = attackPower;
}
public IUnit Build()
{
IUnit builtUnit = _unit;
Reset();
return builtUnit;
}
}
public class Game
{
public static void Main(string[] args)
{
IUnitBuilder terranBuilder = new TerranBuilder();
IUnitBuilder protossBuilder = new ProtossBuilder();
terranBuilder.SetName("Marine");
terranBuilder.SetHP(40);
terranBuilder.SetAttackPower(5);
IUnit terranUnit = terranBuilder.Build();
protossBuilder.SetName("Zealot");
protossBuilder.SetHP(60);
protossBuilder.SetAttackPower(8);
IUnit protossUnit = protossBuilder.Build();
// 유닛들이 서로 싸우기 시작합니다.
while (true)
{
terranUnit.Attack(protossUnit);
if (protossUnit.HP <= 0)
{
Console.WriteLine($"{protossUnit.Name} is defeated!");
break;
}
protossUnit.Attack(terranUnit);
if (terranUnit.HP <= 0)
{
Console.WriteLine($"{terranUnit.Name} is defeated!");
break;
}
}
}
}
Builder 패턴과 Abstract Factory 패턴의 차이점
목적:
Builder 패턴은 복잡한 객체의 생성 과정을 간소화하는 데 사용되며, 이를 통해 생성 결과를 정교하게 조작할 수 있는 유연성을 제공합니다. 반면, Abstract Factory 패턴은 관련 있는 객체 집합을 생성하도록 돕는 역할을 합니다.
객체 생성 과정
Builder 패턴에서 객체 생성 과정은 단계별로 진행되며, 필요에 따라 구성 정보를 변경할 수 있습니다. 반면, Abstract Factory 패턴에서 객체 생성 로직은 다양한 구체 팩토리에서 정의되며, 관련 객체를 일괄적으로 생성합니다.
사용 케이스:
Builder 패턴은 객체 생성 과정이 복잡하거나 다양한 설정 옵션이 있는 경우에 사용됩니다. 반면, Abstract Factory 패턴은 연관된 객체 집합을 동일한 주제나 목적으로 생산하고 생성된 객체를 대체하기 쉽게 만드는 경우에 사용됩니다.
이 두 패턴 모두 서로 다른 상황에서 유용하게 사용됩니다. 따라서 구현하려는 시스템의 요구 사항에 따라 적절한 패턴을 선택하면 코드의 가독성과 유지 관리성을 높일 수 있습니다.