根据外部调用构造域对象的最佳实践是什么?

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 应该只知道它需要运行的对象,例如 ColorDataEngineSpecificationsonly正确。

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();
   }