正确使用静态工厂方法创建具有预定义值的 DTO 对象
The proper usage of a static factory method for creating a DTO object with predefined values
假设我们必须创建具有一些预定义(默认)值的复杂 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
.
我看到了这两种解决方案的优点和缺点,但我正在考虑更喜欢哪一种以及为什么。也许其他一些方法会更好。我乐于接受任何建议,但我想指出,构建器模式适用的问题并不复杂。
假设你
- 想要创建具有特定默认值的 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; }
}
...并且不要将其与各种默认选项混为一谈。随着时间的推移,您会发现您需要针对各种场景使用不同的默认值。我可以看到变得有点凌乱。
然后,将那些完全相同的静态方法放入它们自己的 class:
public static class AddressDtoFactory
{
public static AddressDto CreateWithPredefinedValues()
{
return new AddressDto
{
RecipientName = "John Doe",
City = "City",
CountryName = "Country"
};
}
}
我倾向于 "first way",其中工厂方法仅填充默认值。原因是必须将每个 属性 作为参数传递,这有点麻烦,尤其是在它们没有得到验证的情况下。另外,每次添加 属性 时,您都希望更新该构造函数。
另一种选择是扩展 class,如下所示:
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 或类似的东西,它也可能会更友好一些。
假设我们必须创建具有一些预定义(默认)值的复杂 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
.
我看到了这两种解决方案的优点和缺点,但我正在考虑更喜欢哪一种以及为什么。也许其他一些方法会更好。我乐于接受任何建议,但我想指出,构建器模式适用的问题并不复杂。
假设你
- 想要创建具有特定默认值的 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; }
}
...并且不要将其与各种默认选项混为一谈。随着时间的推移,您会发现您需要针对各种场景使用不同的默认值。我可以看到变得有点凌乱。
然后,将那些完全相同的静态方法放入它们自己的 class:
public static class AddressDtoFactory
{
public static AddressDto CreateWithPredefinedValues()
{
return new AddressDto
{
RecipientName = "John Doe",
City = "City",
CountryName = "Country"
};
}
}
我倾向于 "first way",其中工厂方法仅填充默认值。原因是必须将每个 属性 作为参数传递,这有点麻烦,尤其是在它们没有得到验证的情况下。另外,每次添加 属性 时,您都希望更新该构造函数。
另一种选择是扩展 class,如下所示:
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 或类似的东西,它也可能会更友好一些。