根据外部调用构造域对象的最佳实践是什么?
What is the best practice to construct a Domain Object depending on external calls?
我正在尝试构建一个从外部 API 获取数据的对象。我将尝试用一个例子来解释它:
首先,我在 API 中得到一个 POST 主体来创建一个对象:
class CarRequestBody {
private String colorId;
private String engineId;
//Constructors, etc.
}
然后根据这些信息,我需要构建汽车的详细实例。从外部服务提供数据:
ColorDetails color = colorApiClient.getColor(colorId);
EngineSpecifications engine = engineApiClient.getEngine(engineId);
最后,我用所有这些信息构建了我的域对象。
所以我想知道构建实例的最佳实践是什么。我以 3
种不同的方式思考:
1 - CarService 中的一个方法是这样的:
public Car createCar(CartRequestBody body) {
ColorDetails color = colorApiClient.getColor(body.getColorId);
EngineSpecifications engine = engineApiClient.getEngine(body.getEngineId);
Car car = new Car(color, engine);
}
2 - 在构造函数中提供数据:
public Car(CarRequestBody body) {
this.color = colorApiClient.getColor(body.getColorId);
this.engine = engineApiClient.getEngine(body.getEngineId);
}
3 - 在域 class:
的吸气剂中
class Car {
private ColorData color;
private EngineSpecifications engine;
//Constructor
public ColorData getColor() {
if (color == null){
return colorApiClient.getColor(colorId);
}
return this.color;
}
....
}
这个场景有一些设计模式吗?
一个简单的构造函数会有什么问题?
我不知道 Java,但在 C# 中会是这样的:
class Car {
...
public Car(Color color, Engine engine) {
... // set properties with the parameters
}
}
哦,如果你想做一些解耦,请不要在你的域中使用与 API 中相同的对象。所以你需要某种 Mapper 对象。
// 编辑
由于您正在使用请求,因此您可以创建一个请求处理程序 class。如果您使用控制反转或调解器,您可以通过这种方式将请求连接到处理程序。所以你可以研究那些设计模式。您还可以查看 Clean Architecture 以将您的域代码与外部系统分开(在本例中为 API)
public CarRequestHandler : IRequestHandler<CarRequest> {
public CarRequestHandler(IColorRepository colorRepository, IEngineRepository engineRepository) {
this.colorRepo = colorRepository; //etc.}
public Handle(CarRequest request) {
// call repositories with the ids and create the domain object and stuff
}
}
如果您的目标是保持设计简洁,您的域 class Car
应该只知道它需要运行的对象,例如 ColorData
和 EngineSpecificationsonly
正确。
将apiClient
注入Car
不是一个好主意class因为它与其功能无关并且会增加coupling。
此外,如果 API 调用失败怎么办,您真的要将处理这种情况的管道代码添加到构造函数中吗?
同样,我没有看到定义期望 CarRequestBody
.
的构造函数有什么好处
最简洁的方法是使域的构造函数 class 简单,并且不包含它们运行时不需要的对象。如果您想概括这些域 classes 的实例化过程,您可以引入将处理它的实用方法。
我建议使用 Builder 设计模式。
这里可以看到代码-
Car.java
public class Car{
private ColorDetails colorDetails;
private EngineSpecifications specifications;
private Car(CarBuilder builder){
this.colorDetails = builder.colorDetails;
this.specifications = builder.specifications;
}
public static class CarBuilder {
private ColorDetails colorDetails;
private EngineSpecifications specifications;
public CarBuilder withColor(ColorDetails colorDetails) {
this.colorDetails = colorDetails;
return this;
}
public CarBuilder withSpecifications(EngineSpecifications
specifications) {
this.specifications = specifications;
return this;
}
public Car build() {
Car car = new Car(this);
return car;
}
}
}
// 客户端代码
public class Client{
ColorDetails color = colorApiClient.getColor(colorId);
EngineSpecifications engine = engineApiClient.getEngine(engineId);
Car car = new Car.CarBuilder()
.withColor(color)
.withSpecifications(engine)
.build();
}
我正在尝试构建一个从外部 API 获取数据的对象。我将尝试用一个例子来解释它:
首先,我在 API 中得到一个 POST 主体来创建一个对象:
class CarRequestBody {
private String colorId;
private String engineId;
//Constructors, etc.
}
然后根据这些信息,我需要构建汽车的详细实例。从外部服务提供数据:
ColorDetails color = colorApiClient.getColor(colorId);
EngineSpecifications engine = engineApiClient.getEngine(engineId);
最后,我用所有这些信息构建了我的域对象。
所以我想知道构建实例的最佳实践是什么。我以 3
种不同的方式思考:
1 - CarService 中的一个方法是这样的:
public Car createCar(CartRequestBody body) {
ColorDetails color = colorApiClient.getColor(body.getColorId);
EngineSpecifications engine = engineApiClient.getEngine(body.getEngineId);
Car car = new Car(color, engine);
}
2 - 在构造函数中提供数据:
public Car(CarRequestBody body) {
this.color = colorApiClient.getColor(body.getColorId);
this.engine = engineApiClient.getEngine(body.getEngineId);
}
3 - 在域 class:
的吸气剂中class Car {
private ColorData color;
private EngineSpecifications engine;
//Constructor
public ColorData getColor() {
if (color == null){
return colorApiClient.getColor(colorId);
}
return this.color;
}
....
}
这个场景有一些设计模式吗?
一个简单的构造函数会有什么问题? 我不知道 Java,但在 C# 中会是这样的:
class Car {
...
public Car(Color color, Engine engine) {
... // set properties with the parameters
}
}
哦,如果你想做一些解耦,请不要在你的域中使用与 API 中相同的对象。所以你需要某种 Mapper 对象。
// 编辑
由于您正在使用请求,因此您可以创建一个请求处理程序 class。如果您使用控制反转或调解器,您可以通过这种方式将请求连接到处理程序。所以你可以研究那些设计模式。您还可以查看 Clean Architecture 以将您的域代码与外部系统分开(在本例中为 API)
public CarRequestHandler : IRequestHandler<CarRequest> {
public CarRequestHandler(IColorRepository colorRepository, IEngineRepository engineRepository) {
this.colorRepo = colorRepository; //etc.}
public Handle(CarRequest request) {
// call repositories with the ids and create the domain object and stuff
}
}
如果您的目标是保持设计简洁,您的域 class Car
应该只知道它需要运行的对象,例如 ColorData
和 EngineSpecificationsonly
正确。
将apiClient
注入Car
不是一个好主意class因为它与其功能无关并且会增加coupling。
此外,如果 API 调用失败怎么办,您真的要将处理这种情况的管道代码添加到构造函数中吗?
同样,我没有看到定义期望 CarRequestBody
.
最简洁的方法是使域的构造函数 class 简单,并且不包含它们运行时不需要的对象。如果您想概括这些域 classes 的实例化过程,您可以引入将处理它的实用方法。
我建议使用 Builder 设计模式。
这里可以看到代码-
Car.java
public class Car{
private ColorDetails colorDetails;
private EngineSpecifications specifications;
private Car(CarBuilder builder){
this.colorDetails = builder.colorDetails;
this.specifications = builder.specifications;
}
public static class CarBuilder {
private ColorDetails colorDetails;
private EngineSpecifications specifications;
public CarBuilder withColor(ColorDetails colorDetails) {
this.colorDetails = colorDetails;
return this;
}
public CarBuilder withSpecifications(EngineSpecifications
specifications) {
this.specifications = specifications;
return this;
}
public Car build() {
Car car = new Car(this);
return car;
}
}
}
// 客户端代码
public class Client{
ColorDetails color = colorApiClient.getColor(colorId);
EngineSpecifications engine = engineApiClient.getEngine(engineId);
Car car = new Car.CarBuilder()
.withColor(color)
.withSpecifications(engine)
.build();
}