[Design Pattern] 행동 패턴 4. 빌더 (Builder)
Table of Contents
빌더 (Builder) #
- 객체를 생성하는 클래스와 표현(조립) 하는 클래스를 분리해서, 동일한 절차를 거치더라도 서로 다른 표현(조립된 완성품) 을 생성하는 방법을 제공한다.
- 문제점 : 너무 많은 인자를 넘겨야 하는 생성자
public class Moster
{
string name;
int age;
int power;
int speed;
// ... 많은 수의 필드들
// 엄청나게 늘어날 가능성이 있는 생성자 인자의 수...
public Moster(string n, int a, int p, int s) {}
}
class Program
{
static void Main(string[] args)
{
Monster m = new Monster("ScaryFireMonster", 11, 99, 500);
}
}
- 해결
public interface IMonsterBuilder
{
// 각각의 요소를 독립적으로 조립할 수 있게 한다.
// 이렇게 저렇게 조립한 다양한 결과물들을 만들 수 있다.
void BuildName(string n);
void BuildAge(int a);
void BuildFire(Fire f);
void BuildIce(Ice i);
}
public class ScaryMosterBuilder : IMonsterBuilder
{
Monster monster;
public void BuildName(string n)
{
monster.Name = n;
}
public void BuildAge(int a)
{
monster.Age = a;
}
public void BuildFire(Fire f)
{
monster.fire = f;
}
public void BuildIce(Ice i)
{
monster.ice = i;
}
public Monster GetMonster()
{
return monster;
}
}
public class Director
{
IBuilder builder;
public void SetBuilder(IBuilder b)
{
builder = b;
}
public void BuildScaryFireMonster()
{
// 객체를 생성하는 부분이 이곳에 마련되어 있다.
// 수많은 인자를 넘겨야 하는 생성자가 없다.
// 필요한 것들만 Build 해준다.
builder.BuildName("ScaryFireMonster");
builder.BuildAge(13);
builder.BuildFire(new Fire());
}
public void BuildScaryIceMonster()
{
builder.BuildName("ScaryIceMonster");
builder.BuildAge(15);
builder.BuildIce(new Ice());
}
}
class Program
{
static void Main(string[] args)
{
var builder = new ScaryMosterBuilder();
var director = new Director();
director.SetBuilder(builder);
director.BuildScaryFireMonster();
Monster m = builder.GetMonster();
}
}
개념적인 예시 #
// 빌더
public interface IBuilder
{
// 객체를 표현(조립)한다.
// 나중에 여러가지를 덧붙일 수 있겠다.
void BuildPartA();
void BuildPartB();
void BuildPartC();
}
public class ConcreteBuilder : IBuilder
{
private Product _product = new Product();
public ConcreteBuilder()
{
this.Reset();
}
public void Reset()
{
this._product = new Product();
}
public void BuildPartA()
{
this._product.Add("PartA1");
}
public void BuildPartB()
{
this._product.Add("PartB1");
}
public void BuildPartC()
{
this._product.Add("PartC1");
}
public Product GetProduct()
{
Product result = this._product;
this.Reset();
return result;
}
}
// 제품
public class Product
{
private List<object> _parts = new List<object>();
public void Add(string part)
{
_parts.Add(part);
}
public string ListParts()
{
string str = string.Empty;
for (int i = 0; i < this._parts.Count; i++)
str += _parts[i] + ", ";
str = str.Remove(str.Length - 2);
return "Product parts: " + str + "\n";
}
}
// 디렉터
public class Director
{
private IBuilder _builder;
public IBuilder Builder
{
set { _builder = value; }
}
// 객체를 생성한다.
public void BuildMinimalViableProduct()
{
this._builder.BuildPartA();
}
public void BuildFullFeaturedProduct()
{
this._builder.BuildPartA();
this._builder.BuildPartB();
this._builder.BuildPartC();
}
}
class Program
{
static void Main(string[] args)
{
var director = new Director();
var builder = new ConcreteBuilder();
director.Builder = builder;
director.BuildMinimalViableProduct();
Console.WriteLine(builder.GetProduct().ListParts());
director.BuildFullFeaturedProduct();
Console.WriteLine(builder.GetProduct().ListParts());
// without a Director
builder.BuildPartA();
builder.BuildPartC();
Console.Write(builder.GetProduct().ListParts());
}
}