【问题标题】:How to implement a builder for a complex type?如何为复杂类型实现构建器?
【发布时间】:2020-05-07 08:53:48
【问题描述】:

我有一个非常复杂的类型。该类型有多个只读属性,每个属性都是一个复杂类型:

public class FinalResult
{
    public ComplexType1 ComplexType1 {get;set;}

    public ComplexType2 ComplexType2 {get;set;}

    public ComplexType3 ComplexType3 {get;set;}

    public ComplexType4 ComplexType4 {get;set;}
}

因为ComplextTypeX 很复杂,我为每个人创建了一个构建器:

public class ComplexType1Builder
{
    public ComplexType1 Build(Dependency dep, OtherDependency otherDep)
    {
        // build / create the complex object

        return complexType1;
    }
}

public class ComplexType2Builder
{
    public ComplexType2 Build(Dependency dep, OtherDependency otherDep)
    {
        // build / create the complex object

        return complexType2;
    }
}

// same for ComplexType3 and ComplexType4

最后我有 FinalResultDirector 将所有东西联系在一起:

public class FinalResultDirector
{

    private readonly ComplexType1Builder _builder1;
    private readonly ComplexType2Builder _builder2;
    private readonly ComplexType3Builder _builder3;
    private readonly ComplexType4Builder _builder4;

    public FinalResultDirector(
        ComplexType1Builder builder1, 
        ComplexType2Builder builder2, 
        ComplexType3Builder builder3, 
        ComplexType4Builder builder4 )
    {
        _builder1 = builder1;
        _builder2 - builder2;
        _builder3 = builder3;
        _builder4 = builder4;
    }

    public FinalResult Build(Dependency dep, OtherDependency otherDep)
    {
        return new FinalResult
        {
            ComplexType1 => _builder1.Build(dep, otherDep),

            ComplexType2 => _builder2.Build(dep, otherDep),

            ComplexType3 => _builder3.Build(dep, otherDep),

            ComplexType4 => _builder4.Build(dep, otherDep),
        };
    }
}

这行得通,但我的 OO 心在哭泣。我知道这可以解决得更好、更干净、更可靠,但我还没有看到解决方案。

我尝试过使用接口,但由于每个构建器返回不同的类型,它没有任何附加值。

我一直在考虑的另一种方法是新建一个FinalResult 对象,并让每个Build 方法接受它作为第三个参数:public ComplexTypeX Build(Dependency dep, OtherDependency otherDep, FinalResult finalResult)。然后返回无效。现在所有构建器都具有相同的方法签名。这种方法的缺点是您很想使用 FinalResult 上尚未设置的属性。

我很想听听如何以一种不错的 OO 方式解决这个问题。

【问题讨论】:

  • 你为什么需要这么复杂的FinalResult类,里面有复杂的类型?有没有想过解耦?它是否始终具有所有复杂类型,还是取决于某些逻辑?否则你可以看看fluent builder
  • FinalResult 不会编译,因为属性必须有名称,而不仅仅是类型
  • 修复了代码。是的,据我目前所见,我需要所有这些复杂类型。
  • 好吧,你已经将 4 个不同类型的构建器传递给了 director 类,但是将它们分配给了 4 个相同类型的变量 ComplexType1Builder。那你为什么需要4个建造者呢?此行将无法编译 _builder2 - builder2; 您是否尝试过至少构建您的示例?它不可能是真正的代码,因为它永远不会运行
  • 如果您的代码可以工作但可能会更好(可能不是此代码)Code Review 是更好的匹配。不过,在发布之前请确保您有实际的工作代码。

标签: c# design-patterns solid-principles builder-pattern


【解决方案1】:

您可以使用构建所有类型的单个 Builder 类。一般规则(对我而言)是,如果您有很多类,每个类只有一个方法,那么这是过度设计的,您至少应该考虑使用所有这些方法创建更少的类,甚至是一个类。

现在我们有了一个 Builder 类,尝试消除 FinalResultDirector 类也变得更加容易。

这个+我添加了internal set;,因为除了从构造函数或类中的初始化程序之外,您不能分配只读属性。

工作代码+dotnetfiddle:

using System;

public class Program
{
    public static void Main()
    {
        var director = new FinalResultDirector(new ComplexTypeBuilder());
        var result = director.Build(new Dependency(), new OtherDependency());

        Console.WriteLine(result);
    }
}

public class ComplexType1 {}
public class ComplexType2 {}
public class ComplexType3 {}
public class ComplexType4 {}

public class Dependency {}
public class OtherDependency{}

public class FinalResult
{
    public ComplexType1 ComplexType1 {get; internal set;}
    public ComplexType2 ComplexType2 {get; internal set;}
    public ComplexType3 ComplexType3 {get; internal set;}
    public ComplexType4 ComplexType4 {get; internal set;}
}

public class ComplexTypeBuilder
{
    public ComplexType1 Build1(Dependency dep, OtherDependency otherDep)
    {
        return new ComplexType1();
    }
    public ComplexType2 Build2(Dependency dep, OtherDependency otherDep)
    {
        return new ComplexType2();
    }
    public ComplexType3 Build3(Dependency dep, OtherDependency otherDep)
    {
        return new ComplexType3();
    }
    public ComplexType4 Build4(Dependency dep, OtherDependency otherDep)
    {
        return new ComplexType4();
    }
}

public class FinalResultDirector
{
    private readonly ComplexTypeBuilder _builder;

    public FinalResultDirector(ComplexTypeBuilder builder)
    {
        _builder = builder;
    }

    public FinalResult Build(Dependency dep, OtherDependency otherDep)
    {
        return new FinalResult
        {
            ComplexType1 = _builder.Build1(dep, otherDep),
            ComplexType2 = _builder.Build2(dep, otherDep),
            ComplexType3 = _builder.Build3(dep, otherDep),
            ComplexType4 = _builder.Build4(dep, otherDep)
        };
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-08
    • 1970-01-01
    • 2013-12-27
    • 2018-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-18
    相关资源
    最近更新 更多