Builder模式:Director的目的是什么?

时间:2017-01-06 23:26:03

标签: c# design-patterns builder

首先,我想承认这个问题与this other one非常相似,但我想提出更具体的问题,并希望获得更高质量的答案。

最近,我学习了一个使用Director实现Builder模式的教程。我为了演示目的简化了课程:

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}");
        }
    }
}

当我跟随本教程时,我无法帮助但想知道为什么我们不将Director唯一有意义的方法(BuildProduct方法)放入抽象基类中建设者。这仍然可以确保所有具体构建器获得相同的构建模板,并消除看似无用的层。主任带来了哪些优势?

这里我编写了几乎相同的东西,只是没有导演(产品类省略,因为它没有改变):

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");
}

这两个例子的用法如下:

    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();
    }

这两种方法输出相同的东西。我看到了Director版本的一个优势,因为你创建了一个导向器并将其重用于多个构建器,这些构建器具有一个顶级对象的感觉,它知道发生了什么(请原谅那里的模糊逻辑) ,但你仍然需要了解并创建两个不同的构建器,那么为什么不直接使用它们呢?

3 个答案:

答案 0 :(得分:1)

Director的工作放入Builder违反了单一责任原则,因为Builder将承担两项责任:

  1. 构建者的责任:它知道如何实现 BuildPart1BuildPart2方法。
  2. 董事的责任:它知道应该使用哪些部分 哪个订单。
  3. 的确,例如,当您将基本类BuildPart1中的BuildPart2Builder的调用顺序更改为所有具体Thing*Builder时(s) )不必要地受到影响(必须重新编译和重新部署)。

答案 1 :(得分:0)

您可以使用Director封装构造代码以及构造对象所需的步骤。在下面的示例中,您必须使用RedCarBuilder和GreenCarBuilder来对您的基类执行此操作。我能找到的最佳例子:)

BuilderPattern尝试解决具有不同目的的对象存在多个构造函数的问题。例如,用于创建红色汽车的构造函数和用于创建绿色汽车的构造函数。但是在代码中很难看出不同构造函数的作用。

public class Car
{
    public int Wheels { get; set; }

    public string Colour { get; set; }
}

public interface ICarBuilder
{
    void SetColour(string colour);
    void SetWheels(int count);

    Car GetResult();
}

public class CarBuilder : ICarBuilder
{
    private Car car;

    public CarBuilder()
    {
        this.car = new Car();
    }

    public void SetColour(string colour)
    {
        this.car.Colour = colour;
    }

    public void SetWheels(int count)
    {
        this.car.Wheels = count;
    }

    public Car GetResult() => car;
}

public class CarBuildDirector
{
    public Car ConstructRedCar()
    {
        CarBuilder builder = new CarBuilder();

        builder.SetColour("Red");
        builder.SetWheels(4);

        return builder.GetResult();
    }

    public Car ConstructGreenCar()
    {
        CarBuilder builder = new CarBuilder();

        builder.SetColour("Green");
        builder.SetWheels(4);

        return builder.GetResult();
    }
}

答案 2 :(得分:0)

创建和使用构建器模式时无需使用director。

在您建议的示例中,当您不使用director时,构建器类看起来更像是模板方法模式的示例。

导演的工作我认为是通过调用构建器类的各种方法来封装创建最终产品的逻辑。

您可以在此处找到此示例 https://sourcemaking.com/design_patterns/builder/java/1

但是还有其他版本的buillder模式 http://www.javaworld.com/article/2074938/core-java/too-many-parameters-in-java-methods-part-3-builder-pattern.html

谢谢和问候, Chetan Ranpariya