再次将服务注入域对象

2024-04-22

我有一个对地理数据进行操作的特定域。我正在 TypeScript 和 NodeJS 中实现这个项目,并有以下类:

  • Point- 包含纬度和经度的值对象
  • Area- 包含点集作为形状定义的值对象
  • Sector- 实体(它不是持久的,但它是可变的) - 包含区域和位于其中的点集

现在我需要实现一个名为isPointInside(point: Point)计算提供的点是否适合区域内。我不想自己实现它,因为有一些库可以为我实现它。现在我决定使用那个:https://github.com/manuelbieh/Geolib https://github.com/manuelbieh/Geolib .

另外,我正在使用名为 inversifyjs 的 TypeScript IoC 框架,没什么花哨的 - 通过注释提供 DI。

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

所以这是第一个问题,但这并不是我斗争的结束:-)。

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

目前,我只是将这两个服务作为这些类的静态属性注入,但这并不是我引以为豪的事情,我正在寻找其他选项。

我知道我的设计可能过于复杂,我正在寻找一种简化它的方法,但我不想以贫血领域模型结束。拥有像 Area 对象这样的东西并且无法将地理计算放入其中,对我来说听起来就像贫血模型一样。

此外,我还阅读了很多有关向实体注入服务的讨论,但没有一个让我满意,因为他们要么提供“不要这样做”或“只做这个而不用打扰”之类的结论,要么提供解决方案就像完全不适合我的情况的领域事件。


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

E.g. addPoint(point: Point, geoService: GeoService)

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

但你能详细说明一下后一个解决方案吗

想象一下,一个Project聚合必须根据其链接调整其完成状态和百分比Tasks 以最终一致的方式聚合。为此,Project必须查明到目前为止已完成多少任务。

而不是传递一个TaskRepository/TaskCompletionSummaryProvider进入Project.adjustCompletionState方法您可以解决应用程序层级别的依赖关系。

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());
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

再次将服务注入域对象 的相关文章

随机推荐

  • 使用 ffmpeg 进行视频标准化

    无论如何 有没有使用 ffmpeg 脚本将视频亮度标准化为其完整的动态范围 我一直在尝试用 lutyuv 这样做 ffmpeg i input mp4 vf lutyuv y val minval 255 maxval minval 输出
  • 使用 mysqldump 转储和加载 MySQL InnoDB 数据库的最快方法是什么?

    我想使用 mysqldump 和 MySQL 5 1 创建一个包含大约 40 个 InnoDB 表和大约 1 5GB 数据的数据库副本 能够实现最快转储和加载数据的最佳参数是什么 即 single transaction 此外 将数据加载到
  • 最大执行时间超过 30 秒 Laravel 4 错误

    我在 laravel 4 的 UserController 中发送密码请求的某个函数遇到问题 它检查数据库中是否存在电子邮件 如果用户存在 则发送电子邮件 然后 该函数在表中创建一个令牌 并将其发送到电子邮件内链接的末尾 该函数的工作原理与
  • JPA 中更好的异常处理

    我在持久化我的实体时使用了 EJB3 JPA 我很高兴它能够管理我的数据库相关内容 任务 我唯一关心的是异常处理 我保存实体时的示例代码总是采用这种风格 我在网上读到的大多数教程都是这种风格 也没有考虑异常处理 Stateless publ
  • 并行运行合金分析仪

    我正在生成相当多的合金规格 als 文件 对于我试图解决的中等规模问题 我生成了 1536 个 als 文件 为了节省运行所有这些文件的时间 我使用了 Java 并发 API 特别是ExecutorCompletionService wit
  • C++ 虚拟析构函数和 vtable

    我对虚拟析构函数和虚函数表有一些具体问题 假设我有以下代码 class Base public virtual Base class Child public Base public Child 问题 vtable存储在哪里 它是否始终位于
  • Android系统颜色常量

    Android 编程快把我逼疯了 用于 GUI 开发的 XML 或可编程方法正在为代码制作一份正确的老狗早餐 这里有一些东西 那里有一些东西 我目前的挫败感是试图保留所有 XML 我想设置背景颜色TextView与 a 的背景颜色相同的颜色
  • ArrayIndexOutOfBoundsException - 改造调用

    我正在尝试打电话PUT方法在我的Retrofit实例 Response
  • 大端和小端表示

    如果我写以下内容 section data align 4 X db 1 Y dw 5 Z db 0x11 section text add dword X 0xAA000101 我试图理解大端和小端表示之间的差异 但我不明白每个表示的每个
  • 使用react-google-maps-api将自定义标记作为React组件

    我们正在转换自google map react https github com google map react google map react readme to react google maps api这意味着更多原生 Googl
  • 使用 COMPS 构建 C/C++ 应用程序时出错:硬编码路径

    我正在尝试构建一个使用 C C 绑定开发的 COMPASs 应用程序 当我构建应用程序时 出现以下错误 您知道我该如何解决这个问题吗 xxxx xxx c increment gt buildapp increment BSC Barcel
  • Crash Firebase vs Crashlytics vs HockyApp

    我一直在应用程序中使用 Crashlytics 我们的客户端使用 HockeyApp 并且我是通过 Google Firebase 最近的更新了解到的 有谁有机会使用上述工具 您的概述和建议是什么 您是否喜欢其中一个 为什么 祝你有美好的一
  • Laravel 将数据传递给路由

    我是 Laravel 5 的新手 我需要一些帮助 因为我无法解决我的简单问题 我有一个数据列表http sample com partners http sample com partners如果我单击数据链接 我希望将其重定向到 http
  • 如何从服务器中的客户端池中识别客户端 - 设计

    好的 我正在使用一个客户端 服务器库 服务器可以接受来自客户端的多个连接 每次调用 Accept 时 如果成功 客户端套接字的句柄就会被推送到映射 并以假定的唯一 ID 作为键 这样当服务器稍后想要向特定客户端发送消息时 它就会使用该 ID
  • mysql 其中字符串以数字结尾

    我的表列包含如下值 id item 1 aaaa11a112 2 aa1112aa2a 3 aa11aa1a11 4 aaa2a222aa 我只想选择项目值以数字结尾的行 有这样的事吗 select from table where ite
  • Maven 对特定存储库使用 SOCKS 代理

    我试图将 Maven 配置为在访问特定存储库时使用袜子代理 但不将其用于 Maven 中央存储库 我用过export MAVEN OPTS DsocksProxyHost
  • 单击单个单元格并使用 Javascript 添加颜色到 HTML 表格

    我创建了一个 HTML 表 带有用户输入的列和行 并且还具有选择颜色的动态方式 现在我希望能够单击表格中的各个单元格并用所选颜色为它们着色 到目前为止我有这个代码 我的最终目标是当我再次点击 提交 时能够重置颜色 流程将是 选择桌子尺寸 选
  • 当其父对象设置为不显示时,如何获取对象的最小高度?

    为什么我无法获取min height当一个物体的parent被设定为display none 但如果最小高度是 我仍然可以得到物体的高度not in use 例如 css li display none object display blo
  • 确定 Linux 或 Windows 是 C++ 语言

    我正在用 C 编写一个跨平台兼容函数 该函数根据输入文件名创建目录 我需要知道机器是 Linux 还是 Windows 并使用适当的正斜杠或反斜杠 对于下面的代码 如果机器是Linux那么isLinux true 如何确定操作系统 bool
  • 再次将服务注入域对象

    我有一个对地理数据进行操作的特定域 我正在 TypeScript 和 NodeJS 中实现这个项目 并有以下类 Point 包含纬度和经度的值对象 Area 包含点集作为形状定义的值对象 Sector 实体 它不是持久的 但它是可变的 包含