First, I want to acknowledge that this question is very similar to this other one, but I wanted to ask with more specifics and hopefully garner higher quality answers.
Recently I followed a tutorial where the Builder pattern was implemented with a Director. I've streamlined the classes for demonstration purposes:
public class Director
{
private readonly Builder _builder;
public Director(Builder builder)
{
_builder = builder;
}
public void BuildProduct()
{
_builder.CreateProduct();
_builder.BuildPart1();
_builder.BuildPart2();
}
public Product GetProduct() => _builder.GetProduct();
}
public abstract class Builder
{
protected Product Product;
internal void CreateProduct()
{
Product = new Product();
}
internal Product GetProduct() => Product;
internal abstract void BuildPart1();
internal abstract void BuildPart2();
}
public class Thing1Builder : Builder
{
internal override void BuildPart1() => Product.ThingStrings.Add("Thing-1 String-1");
internal override void BuildPart2() => Product.ThingStrings.Add("Thing-1 String-2");
}
public class Thing2Builder : Builder
{
internal override void BuildPart1() => Product.ThingStrings.Add("Thing-2 String-1");
internal override void BuildPart2() => Product.ThingStrings.Add("Thing-2 String-2");
}
public class Product
{
internal readonly ICollection<string> ThingStrings = new List<string>();
public void Display()
{
foreach (string thingString in ThingStrings)
{
Console.WriteLine($"Thing string = {thingString}");
}
}
}
As I was following along with the tutorial, I couldn't help but wonder why we don't just put the Director's only meaningful method (the BuildProduct method) into the abstract base class of the builders. This still ensures all concrete builders get the same build template and does away with what seems like a useless layer. What advantages does the Director bring?
Here I have coded virtually the same thing, just without the director (Product class omitted because it did not change):
public abstract class BuilderWithoutDirector
{
protected Product Product;
public void CreateProduct()
{
Product = new Product();
BuildPart1();
BuildPart2();
}
public Product GetProduct() => Product;
protected abstract void BuildPart1();
protected abstract void BuildPart2();
}
public class Thing1BuilderWithoutDirector : BuilderWithoutDirector
{
protected override void BuildPart1() => Product.ThingStrings.Add("Thing-1 String-1");
protected override void BuildPart2() => Product.ThingStrings.Add("Thing-1 String-2");
}
public class Thing2BuilderWithoutDirector : BuilderWithoutDirector
{
protected override void BuildPart1() => Product.ThingStrings.Add("Thing-2 String-1");
protected override void BuildPart2() => Product.ThingStrings.Add("Thing-2 String-2");
}
Usages of these two examples look like this:
private static void UseWithDirector()
{
var director = new Director(new Thing1Builder());
director.BuildProduct();
var thing1 = director.GetProduct();
director = new Director(new Thing2Builder());
director.BuildProduct();
var thing2 = director.GetProduct();
thing1.Display();
thing2.Display();
}
private static void UseWithoutDirector()
{
var builder1 = new Thing1BuilderWithoutDirector();
builder1.CreateProduct();
var thing1 = builder1.GetProduct();
var builder2 = new Thing2BuilderWithoutDirector();
builder2.CreateProduct();
var thing2 = builder2.GetProduct();
thing1.Display();
thing2.Display();
}
These two methods output the same thing. I see a hint to an advantage with the Director version in that you create one director and reuse it with multiple builders which has a feeling of a top-level object that knows what's going on (please excuse the fuzzy logic there), but you still have to know about and create two different builders, so why not just use them directly?
Aucun commentaire:
Enregistrer un commentaire