首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >建造者模式:导演的目的是什么?

建造者模式:导演的目的是什么?
EN

Stack Overflow用户
提问于 2017-01-06 23:26:02
回答 4查看 2.5K关注 0票数 4

首先,我想承认这个问题与this other one非常相似,但我想问更多细节,希望得到更高质量的答案。

最近,我遵循了一个教程,其中的Builder模式是用一个Director实现的。为了演示目的,我简化了这些课程:

代码语言:javascript
复制
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方法)放到构建器的抽象基类中。这仍然可以确保所有具体的构建者都获得相同的构建模板,并消除看似无用的层。主任带来了什么好处?

在这里,我编写了几乎相同的代码,但没有使用director (Product省略了,因为它没有更改):

代码语言:javascript
复制
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");
}

这两个示例的用法如下所示:

代码语言:javascript
复制
    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();
    }

这两个方法输出相同的内容。我看到了这样一个提示,即您创建一个导演并与多个建设者一起重用它,它有一种顶层对象的感觉,它知道发生了什么(请原谅这里的模糊逻辑),但是您仍然需要了解和创建两个不同的构建器,那么为什么不直接使用它们呢?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-01-08 10:07:51

Director的工作交给Builder是违反了单一责任原则的,因为Builder有两个责任:

  1. 生成器的责任:它知道如何实现BuildPart1BuildPart2方法。
  2. 主任的责任:委员会知道应按何种顺序使用哪些部分。

实际上,例如,当您更改基类BuildPart1BuildPart2调用的顺序时,所有具体的Thing*Builder(s)都会受到不必要的影响(必须重新编译和重新部署它们)。

票数 4
EN

Stack Overflow用户

发布于 2022-08-12 22:19:55

这是一个老问题,但这也是一个我发现自己说服其他开发人员足够频繁的主题,我认为我想提交一个迟来的答案无论如何。公认的答案是正确引用单一责任原则。我想补充的是一些更具体的想法,为什么这在第一时间如此重要。

Director/Builder是一种更通用的称为Bridge的模式的专门化,您可以通过共享接口将来自两个不同层次结构的实现对组合在一起。B类型的A和N实现的M实现产生了M*N独特的行为组合,用于M+N实现的开发和维护成本。

董事可以代表不同的原因或来源想要构建一个对象。建筑商可以生产不同的终端产品。有能力重用一个层次结构的每个实现与另一个层次的任何新实现都是生产力的巨大好处!

假设我开发了一个数据转换引擎,它需要一个对象图来描述它在运行时给出的每个任务。我为我的转换引擎提供了一种特定于域的语言,允许开发人员从他们的IDE中为它创建工作,我还有一个websocket协议,它允许网络服务提交工作单元。我还设计了一个关系数据库模式,用于支持一个中央存储库,用于托管转换引擎的云部署,并触发调度程序的执行。

我可以执行:

  • 解析我的DSL并使用解析树驱动生成器的DSLDirector
  • 作为驱动生成器的方向处理传入websocket消息的WebSocketDirector
  • 接受某些键标识符、查询数据库并使用返回的行驱动生成器的RepositoryDirector
  • 一个ExportDirector,它接受我的语言的一个实例,并向一个生成器描述自己

在Builder方面,我可能有:

  • 一个DSLBuilder,它将我的数据转换规范通过Builder转换成其特定于域的语言的预格式化实例。
  • 将数据转换规范转换成发送到Websocket协议远程实例的有效消息会话的WebsocketBuilder。
  • 一个RepositoryBuilder,它可以构造SQL查询以插入/更新我的数据转换语言的持久化形式。
  • 一个ImportBuilder,它可以生成一个内存中的对象树,适合我的转换引擎执行。

我可以使用这些组合来完成多个相关用例,比为每个用例编写独立程序的速度要快得多:

  • DSLDirector + WebSocketBuilder =分析我的IDE工作并将其发送到存储库服务
  • WebSocketDirector + RepositoryBuilder =从IDE接收消息并将部署内容写入数据库表。
  • RepositoryDirector + WebSocketBuilder =从数据库加载我以前的部署并将其连接到计算引擎主机
  • WebSocketDirector + ImportBuilder =创建以前保存的可执行模型实例,但在执行服务的地址空间中。快跑!

后来,在我的产品的一生中,我可能会做一些重大改变的选择模型。我设法用第一个引擎的语义来表达所有可能的东西,但是用来指定相同行为的数据模型现在的形状非常不同。如何处理我们现有的用户群?

如果旧模型的语义仍然存在于新模型中,那么处理迁移的一种方法是提供一个新的构建器,它能够使用先前的接口定义其消息传递契约,但使用我的新对象模型实现它的等价意义。

目录/生成器对于MxN集成用例以及迁移/升级路径都是一个巨大的福音。

不管怎样,那是我的两分钱。:)

票数 1
EN

Stack Overflow用户

发布于 2017-01-07 00:04:52

您可以使用Director封装构造代码和构造对象所需的步骤。在下面的示例中,您必须有一个RedCarBuilder和一个GreenCarBuilder来使用您的基类。我能找到的最好的例子:)

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

代码语言:javascript
复制
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();
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41516004

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档