0

假设我们必须创建具有一些预定义(默认)值的复杂 DTO 对象。该对象用于序列化,序列化器需要无参数构造函数。为此,我想使用静态工厂方法,但我对这种方法的正确使用有些怀疑。

请考虑以下两个示例:

public class Foo
{
    public void DoSomething()
    {
        // the first way of creating the object
        var addressDtoFirstWay = AddressDtoFirstWay
            .CreateWithPredefinedValues();
        addressDtoFirstWay.StreetName = "Street";
        addressDtoFirstWay.HouseNumber = 100;
        addressDtoFirstWay.PostalCode = "1000";

        // the second way of creating the object
        var addressDtoSecondWay = AddressDtoSecondWay
            .CreateWithPredefinedValues("Street", 100, null, "1000");
    }
}

public class AddressDtoFirstWay
{
    public string RecipientName { get; set; }
    public string StreetName { get; set; }
    public int HouseNumber { get; set; }
    public int? FlatNumber { get; set; }
    public string PostalCode { get; set; }
    public string City { get; set; }
    public string CountryName { get; set; }

    public static AddressDtoFirstWay CreateWithPredefinedValues()
    {
        return new AddressDtoFirstWay
        {
            RecipientName = "John Doe",
            City = "City",
            CountryName = "Country"
        };
    }
}

public class AddressDtoSecondWay
{
    public string RecipientName { get; set; }
    public string StreetName { get; set; }
    public int HouseNumber { get; set; }
    public int? FlatNumber { get; set; }
    public string PostalCode { get; set; }
    public string City { get; set; }
    public string CountryName { get; set; }

    public static AddressDtoSecondWay CreateWithPredefinedValues(
        string streetName,
        int houseNumber,
        int? flatNumber,
        string postalCode)
    {
        return new AddressDtoSecondWay
        {
            RecipientName = "John Doe",
            StreetName = streetName,
            HouseNumber = houseNumber,
            FlatNumber = flatNumber,
            PostalCode = postalCode,
            City = "City",
            CountryName = "Country"
        };
    }
}

在第一个示例中,工厂方法仅初始化预定义字段 - 用户必须在对象创建后初始化其余字段。第二个示例初始化预定义的字段,也是必需的字段,但作为缺点,用户必须填写可为空的(在这种情况下不需要,但在其他情况下是必需的)字段flatNumber

我看到了这两种解决方案的优点和缺点,但我正在考虑哪一种更受欢迎以及为什么。也许其他一些方法会更好。我愿意接受任何建议,但我想指出,构建器模式适用的问题并不复杂。

4

1 回答 1

2

假设你

  • 想要创建具有某些默认值的 DTO 的方法
  • 想要一个默认构造函数并且不想强制使用工厂方法

也许答案是将两者分开。让你的 DTO 做自己的事:

public class AddressDto
{
    public string RecipientName { get; set; }
    public string StreetName { get; set; }
    public int HouseNumber { get; set; }
    public int? FlatNumber { get; set; }
    public string PostalCode { get; set; }
    public string City { get; set; }
    public string CountryName { get; set; }
}

...并且不要将其与各种默认选项混淆。随着时间的推移,您会发​​现您需要针对各种场景使用不同的默认值。我可以看到这变得有点混乱。

然后,采用完全相同的静态方法并将它们放入自己的类中:

public static class AddressDtoFactory
{
    public static AddressDto CreateWithPredefinedValues()
    {
        return new AddressDto
        {
            RecipientName = "John Doe",
            City = "City",
            CountryName = "Country"
        };
    }
}

我倾向于工厂方法仅填充默认值的“第一种方式”。原因是必须将每个属性都作为参数传递有点麻烦,尤其是在它们没有得到验证的情况下。另外,每次添加属性时,您都希望更新该构造函数。

另一种选择是这样的扩展类:

public static class AddressDtoExtensions
{
    public static AddressDto PopulatePredefinedValues(
        this AddressDto dto)
    {
        dto.RecipientName = dto.RecipientName ?? "John Doe";
        dto.City = dto.City ?? "City";
        dto.CountryName = dto.CountryName ?? "Country";
        return dto;
    }
}

这使您可以执行以下操作:

var dto = new AddressDto
{
    HouseNumber = 5,
    PostalCode = "12345"
}.PopulatePredefinedValues();

它为您提供了两者 - 您可以同时使用属性初始化并添加默认值。如果您决定使用 Automapper 或类似的东西,它也可能会更友好一些。

于 2019-04-04T18:54:32.857 回答