再次将服务注入域对象 [英] Injecting service into domain object once again

查看:65
本文介绍了再次将服务注入域对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用地理数据的特定域。我正在TypeScript和NodeJS中实现此项目,并具有以下类:

I've got specific domain that operates on a geographical data. I'm implementing this project in TypeScript and NodeJS and have following classes:


  • Point -包含纬度的值对象和经度

  • 面积-包含点集作为形状定义的值对象

  • 扇区 >-实体(它不是持久的,但可变的)-包含区域和位于其中的点集

  • Point - value object containing latitude and longitude
  • Area - value object containing set of points as a shape definition
  • Sector - entity (it's not persisted, but it's mutable) - containing area and set of points that lie inside it

现在我需要实现一种名为 isPointInside(point:Point)的方法,该方法计算提供的点是否适合区域内。我不想自己实现,因为有图书馆可以帮我实现。现在,我决定使用其中一个: https://github.com/manuelbieh/Geolib

Now I need implement a method named isPointInside(point: Point) that calculates whether provided point fits inside of area or not. I don't want to implement it by myself, because out there are libraries that will do it for me. Right now I've decided to use that one: https://github.com/manuelbieh/Geolib .

我还在TypeScript的IoC框架中使用inversifyjs,没什么花哨的-通过注释提供DI。

Also I'm using IoC framework for TypeScript called inversifyjs, nothing fancy - provides DI through annotations.

因此,我创建了一个名为 GeoService的接口,该接口提供了负责地理计算的方法,并且我打算在该域模型中大量使用它。使用inverseify,我提供了实现我的界面的GeoLib适配器,我真的很想在Area类中以某种方式使用它。

So I created an interface called "GeoService" that provides methods responible for geographical calculations, and I intend to use it rather heavily in that domain model. Using inversify I provided GeoLib adapter that implements my interface and I'd really like to use it somehow from inside my Area class.

所以这是第一个问题,但这不是

So that's first problem, but it's not the end of my struggles :-).

我有另一个名为 SectorGrid 的类,其中包含扇区网格(每个扇区都是(在本用例中为正方形)在二维数据结构中。 SectorGrid具有方法 addPoint(point:Point)。该方法的责任是找到一个适合点的扇区,如果找不到,则创建一个扇区。现在,它不仅需要GeoService来计算扇区的起始点应该在哪里(距网格中心的距离),而且还需要创建扇区-并且在编写测试时遇到了这个问题,逻辑太多了,我们决定为SectorGrid提供某种部门工厂,不仅可以简化测试,而且可以封装部门创建逻辑(这非常复杂)。因此,现在要注入另一种服务,并且不知道如何以不会导致我出现问题的方式进行操作。

I've got another class, called SectorGrid, that contains grid of sectors (every sector is the square in this usecase) in two-dimensional data structure. SectorGrid has a method addPoint(point: Point). Responsibility of that method is to find a sector that provided point fits in, and if it doesn't find one, to create it. Now it not only needs GeoService to calculate where initial point of the sector should be (distance from grid center), but also it needs to create Sector - and there I faced the issue while I was writing tests, there was too much logic and I've decided to provide some kind of a sector factory to SectorGrid not only to simplify tests, but also to encapsulate sector creation logic (that's quite complex). So another service to inject now, and no idea how to do it in a way that won't lead me to problems.

现在,我只是将这两项服务注入这些类的静态属性,但这不是我引以为傲的东西,我正在寻找其他选择。

For now I just injected those two services as static properties of these classes, but that's not something I'm proud of and I'm looking for other options.

我知道我的设计可能过于复杂了,我我正在寻找一种简化它的方法,但我不想在Anemic Domain Models领域中落下帷幕。对于我来说,拥有诸如Area对象之类的东西并且无法在其中进行地理计算听起来很像贫血模型。

I know that my design may be be overcomplicated and I'm looking for a way to simplify it, but I don't want to end in the Anemic Domain Models land. Having something like Area object and not being able to put geographical calculations inside of it sounds exactly like anemic model for me.

我还阅读了很多有关注入的讨论服务到实体中,但是他们都不满意我,因为他们要么提供诸如不要这样做或只要这样做就不要打扰之类的结论,要么提供诸如域事件之类的解决方案,而这些解决方案完全不适合我

Also I've read quite a few discussions about injecting services into entities, but none of them satisfied me as they either provided to conclusion like "don't do this" or "just do this and don't bother", or provided solutions like domain event that totally doesn't fit in my case.

推荐答案

处理领域对象需要与服务协作的情况的一种常用方法是在方法级别注入这些服务并应用ISP原理以确保依赖性不会超出所需范围。

A common way of handling cases where domain objects needs to collaborate with services is to inject these services at the method level and apply the ISP principle to ensure the dependencies are not wider than needed.

例如 addPoint(point:Point,geoService:GeoService)

处理该问题的另一种常用方法是解决依赖于应用程序服务的依赖关系,并将结果传递给聚合方法,但是当该方法在应用程序层内部泄漏太多逻辑时,您可能应该在方法级别使用服务注入。

Another common way of dealing with the problem is to resolve the dependency from the application service and pass the result into the aggregate method, but when that approach is leaking too much logic inside the application layer you should probably use service injection at the method level instead.


但是您能详细说明一下后一种解决方案吗?

but could you elaborate a little more about the latter solution

好吧,假设项目聚合必须以最终一致的方式根据其链接的任务聚合来调整其完成状态和百分比。为此,项目必须找出到目前为止已完成的任务。

Well imagine that a Project aggregate must adjust it's completion status and percentage based on it's linked Tasks aggregates in an eventually consistent manner. To do so the Project must find out how many tasks are completed so far.

而不是传递 TaskRepository / TaskCompletionSummaryProvider 放入您可以解析的 Project.adjustCompletionState 方法中

Rather than passing in a TaskRepository/TaskCompletionSummaryProvider into the Project.adjustCompletionState method you could resolve the dependency at the application layer level.

var project = projectRepository.projectOfId(someProjectId);
var taskCompletionSummary = taskRepository.taskCompletionSummaryOfProject(project.id());
project.adjustCompletionState(taskCompletionSummary);


class Project {
    public void adjustCompletionState(TaskCompletionSummary summary) {
        //The following line could be seen as defensive programming. You could also trust that the application layer is doing it's job correctly. It wouldn't be required at all if a `TaskCompletionSummaryProvider` service would be injected directly instead.
        if (this.id != summary.projectId()) throw new InvalidOperationException('Wrong summary for project');

        if (summary.allCompleted()) this.completionState = ProjectCompletionState.COMPLETED;
        else this.completionState = ProjectCompletionState.inProgress(summary.completionPercentage());
    }
}

这篇关于再次将服务注入域对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆