简体   繁体   English

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

[英]What is the best practice to construct a Domain Object depending on external calls?

I am trying to build an object that gets its data from external APIs.我正在尝试构建一个从外部 API 获取其数据的对象。 I will try to explain it with an example:我将尝试用一个例子来解释它:

First of all, I get a POST body in my API to create an object:首先,我在我的 API 中获得一个 POST 正文来创建一个对象:

class CarRequestBody {
    private String colorId;
    private String engineId;
    //Constructors, etc.
}

Then with this info I need to build a detailed instance of the Car.然后有了这些信息,我需要构建 Car 的详细实例。 Feeding the data from external services:从外部服务提供数据:

ColorDetails color = colorApiClient.getColor(colorId);
EngineSpecifications engine = engineApiClient.getEngine(engineId);

And finally I build my Domain Object with all this info.最后,我用所有这些信息构建了我的域对象。

So I would like to know what is the best practice in order to build the instance.所以我想知道构建实例的最佳实践是什么。 I have thought in 3 different ways:我以3种不同的方式思考过:

1 - A method in CarService like this: 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 - Feed the data in the constructor: 2 - 在构造函数中输入数据:

public Car(CarRequestBody body) {
    this.color = colorApiClient.getColor(body.getColorId);
    this.engine = engineApiClient.getEngine(body.getEngineId);
}

3 - In the getters of the domain class: 3 - 在域类的吸气剂中:

class Car {
    private ColorData color;
    private EngineSpecifications engine;
    //Constructor

    public ColorData getColor() {
        if (color == null){
            return colorApiClient.getColor(colorId);
        }
        return this.color;
    }
    ....
}

Is there some design pattern for this scenario?这种情况有一些设计模式吗?

I would suggest using the Builder design pattern.我建议使用Builder设计模式。

Here you can see the code-在这里你可以看到代码 -

Car.java汽车.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;
       }
   }
 }

// Client code // 客户端代码

 public class Client{

  ColorDetails color = colorApiClient.getColor(colorId);
  EngineSpecifications engine = engineApiClient.getEngine(engineId);
 Car car = new Car.CarBuilder()
          .withColor(color)
          .withSpecifications(engine)
          .build();
   }

If you aim to keep your design clean, your domain class Car should be aware only of the objects like ColorData and EngineSpecificationsonly that it requires to function properly.如果你的目标是保持你的设计干净,你的域类Car应该只知道它需要正常运行的对象,如ColorDataEngineSpecificationsonly

It's not a good idea to inject apiClient into the Car class because it's unrelated to its functionality and will increase coupling .apiClient注入Car类不是一个好主意,因为它与它的功能无关,并且会增加耦合

Also, what if an API call will fail, do you really want to add the plumbing code that will handle this scenario into a constructor?此外,如果 API 调用失败怎么办,您真的想将处理这种情况的管道代码添加到构造函数中吗?

Similarly, I don't see an advantage in defining a constructor that expects CarRequestBody .同样,我看不出定义一个期望CarRequestBody的构造函数有什么好处。

The cleanest approach will be to keep the constructors of your domain classes simple and free from objects that are not needed for them to act.最简洁的方法是让域类的构造函数保持简单,并且不受不需要它们执行的对象的影响。 And if you want to generalize the process of instantiation of these domain classes, you can introduce utility methods that will take care of it.如果你想概括这些领域类的实例化过程,你可以引入实用方法来处理它。

What would be wrong with a simple constructor?一个简单的构造函数会有什么问题? I don't know Java, but would be this in C#:我不知道 Java,但在 C# 中是这样的:

class Car {
   ...
    public Car(Color color, Engine engine) {
   ... // set properties with the parameters
   }
}

Oh, and if you want to do some Decoupling, please don't use the same objects in your Domain as in API.哦,如果你想做一些解耦,请不要在你的域中使用与 API 中相同的对象。 So you will need some kind of Mapper object.所以你需要某种 Mapper 对象。

// EDIT // 编辑

Since you are using a request, you could make a requesthandler class.由于您使用的是请求,因此您可以创建一个 requesthandler 类。 If you use Inversion of Control or a Mediator you could connect the request to the handler in that way.如果您使用控制反转或调解器,您可以通过这种方式将请求连接到处理程序。 So you could look into those design patterns.所以你可以研究那些设计模式。 You could also look into Clean Architecture to separate your domain code from external systems (API's in this case)您还可以查看 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
       
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM