gpt4 book ai didi

domain-driven-design - 域服务应该如何调用基础设施服务?

转载 作者:行者123 更新时间:2023-12-04 11:26:51 28 4
gpt4 key购买 nike

1) 当 Domain 层使用一个 Infrastructure Service IS 时,它的接口(interface)定义在 Domain 层,而它的实现定义在 Infrastructure 层。

我们不应该将(例如存储库或电子邮件服务)直接注入(inject)域实体:

class Foo
{
IRepository repo;
...
public int DoSomething()
{
var info = repo.Get...;
...
}
}

相反,如果域实体的某个方法需要特定的 ,那么应用层可以将 作为参数传递给该方法:
 class Foo
{
...
public int DoSomething(IRepository repo)
{
var info = repo.Get...;
...
}
}

a) 我假设 也不应该直接注入(inject)到域服务中:
class TransferService
{
IRepository repo;
...
public bool Transfer()
{
var info = repo.Get...;
...
}
}

,但 应该作为参数传递给那些打算使用它的域服务方法:
class TransferService
{
public bool Transfer(IRepository repo)
{
var info = repo.Get...;
...
}
}

b) 我假设如果域实体的方法需要使用域服务,它不需要通过参数接收它(尽管将域服务作为参数传递具有显式传达方法依赖项的好处),而是可以调用它直接,原因是领域实体和领域服务都是领域概念:
class Foo
{
...

public int DoSomething()
{
var info = TransferService.Transfer(...);
...
}
}

更新:

1)

An IS can be injected into a domain service if it needs it for functionality - ie not passed to method. This is different than entities and it is because a domain service is stateless and so it can be configured with required dependencies once and used where needed, such as by other entities.



a) 所以 不应该被注入(inject)域实体的主要原因是由于它们的状态性质?

b) 但我认为不向域实体注入(inject) 的主要原因是因为它会违反持久性无知规则?

c) 如果我们向实体注入(inject) ,它的状态性质会导致什么问题?

d) 将 注入(inject)域服务是否违反了PI?如果没有,为什么不呢?

2)

A domain service should be passed to entity as argument much like you would pass a repository interface as argument. The same principles apply.



但是与存储库不同,域服务是一个域概念,那么“相同原则适用”是什么意思?也就是说,将域服务注入(inject)域实体不会违反 PI,而注入(inject)存储库会!

第二次更新:

1)

一种)

That is one reason. Another is that is creates needless coupling. If a repository is needed for only a single behavior on the entity, why inject it into entity all the time? Also, now you have to consider how you will resolve those dependencies? Make entities part of dependency injection graph? This quickly overloads the responsibilities of the entity.



所以,如果我理解正确的话——将 注入(inject)域服务 DS并不违反SRP,因为 DS正在使用它来执行其指定的任务指定责任),而将 IS注入(inject)域实体是违反SRP的,因为域实体的主要责任是关注其生命周期和身份,而 大多数时候不是' t 管理这两项任务的一个组成部分(即关注生命周期和身份)?

b)

You can still pass an IS to a domain entity method and the problem here wouldn't be violation of PI since you're passing an interface, not an implementation. The problem would be violation of SRP if the domain method only used one method on the IS interface.



我 - 但是在您之前的几篇文章中,您注意到可以将 作为作为域实体方法的参数传递,但是在这里您说如果仅使用此域方法,它将违反 SRP 上的一种方法是实例?

II - 如果 实现了一个包含单个方法的基于角色的接口(interface),而我们将这个基于角色的接口(interface)作为参数传递给域方法,您是否仍然认为这违反了SRP?如果没有,为什么不呢?

d)

PI is maintained with the use of interfaces.



我已经多次阅读,即使域方法通过接口(interface)引用存储库,它仍然被认为违反了 PI。你为什么不同意呢?

2)

It is better however to be very explicit. So instead of passing a repository and implicitly understanding that it happens to provide a service to the entity, declare the provided functionality as its own interface and have the entity depend on that.



a) 那么不将域服务注入(inject)域实体的唯一原因是由于违反了 SRP?

b)

declare the provided functionality as its own interface



我假设您建议使用基于角色的接口(interface)?但是,即使将基于角色的接口(interface)(由域服务实现)注入(inject)域实体也不会导致违反 SRP,因为正如您在 1a中指出的那样,注入(inject)的功能很可能只需要域实体的单一行为?!

在将 传递给域实体的方法方面,您和 Aaron Hawkins 似乎是对立的?!

第三次更新:

1)

一种)

So if I understood you correctly - Injecting IS into Domain Service DS doesn't violate SRP, because DS is using it to execute its designated tasks ( ie its designated responsibility), while injecting IS into Domain Entity is a violation of SRP because primary responsibility of Domain Entity is focusing on its life cycle and identity, and ISmost of the times isn't an integral part in managing these two tasks ( ie focusing on life cycle and identity )?



是的,这是正确的,也是主要原因之一。

I - 从远处看,将 IS 注入(inject)域实体 DE 似乎完全合理,这个 DE 将违反 SRP,因为 “IS79104” IS79104不会有助于管理指定为 DE的两个任务。

但是当试图更详细地想象这个场景时会有点困难。也就是说,如果 DE的方法专注于管理两个指定的任务(即它的生命周期和身份),那么如果这些方法之一需要 ,这不是合理的吗?假设它需要 来完成两个指定的任务而不是与 DE的生命周期和身份无关的其他任务?如果是,那么我们怎么能声称 DE违反了 SRP?

II - 我也很难想象管理 DE 的生命周期和身份究竟意味着什么。首先,一旦 DE被分配了一个身份,这个身份就不会改变。那么我们需要管理它的身份呢?

III - 管理 DE 的生命周期是什么意思?也许在 DE上定义不变量,以保持其数据一致或......?

IV - 那么现实世界实体执行的所有其他任务(即那些与 DE 的生命周期和身份无关的任务)都应该从 DE中提取出来并放入相关对象中?

d)

If IS implemented a role-based interface containing a single method, and instead we pass this role-based interface as an argument to domain method, would you still consider this as a violation of SRP? If not, why not?



这样做并不可怕,但它有可能违反 SRP 或作为
由 guillaume31 - ISP 更清楚地指定。

我不确定我们如何声称将 IS注入(inject) DE可能违反 ISP,因为据我所知只能违反“1094567”ISP79通过实现此接口(interface)的对象而不是注入(inject)此接口(interface)的实现的对象?

第四次更新:

我开始意识到 SRP 比我最初想象的要困惑得多

一种)

Behavior associated with the entity, which usually entails state changes, should also be placed into the entity. If such behavior requires use of a service, pass that service in, but generally try to place as much behavior into the entity as possible.



IV – 1 以下行为方法不包括状态更改,但我认为它们也应该属于 Dog实体:
class Dog
{
...
void DoBark();
void DoFetch();
void DoGuard();

Breed GetBreed();
Pedigree GetPedigree();
Snack FavSnack();
}

IV – b) GetBreedGetPedigreeFavSnack是行为方法吗?如果是,那么属性 BreedPedigreeSnack也应该被视为行为,因为它们本质上提供相同的功能(假设 GetBreedGetPedigreeFavSnack不重计算,但只是返回对象):
class Dog
{
...
void DoBark();
void DoFetch();
void DoGuard();

Breed Breed { get{...} }
Pedigree Pedigree { get{...} }
Snack Snack { get{...} }
}

IV – c) 如果上述属性也有 setter,我们会说它们包含状态改变行为吗?

IV – d)

Behavior associated with the entity, which usually entails state changes, should also be placed into the entity.



但是如果域实体的主要职责是管理它的生命周期,那么包括与管理生命周期无关的行为是否违反了 SRP(在上面的例子中,诸如 Dog.DoBark之类的方法很可能没有太多需要与 Dog的生命周期有关)?!

d)

一世。

Passing IS to a DE behavioral method is better, however can violate SRP/ISP if IS interface has lots of things unrelated to the behavior at hand. This is the basic premise of ISP - dependencies should be made on specific interfaces as opposed to bloated interfaces that happen to contain the required functionality.



所以如果 作为参数传递给DE的行为方法之一确实有一些与手头行为无关的操作,但DE的方法 M不使用任何 的方法与行为 无关 M应该处理,我们仍然认为DE违反了SRP/ISP?

二、 – 我明白你在说什么,但我的困惑源于以下事实:根据 ISP 的以下定义,该术语只能用于指定对象 ServObj实现特定接口(interface)违反 ISP ,而注入(inject) ServObj的对象违反了SRP(由于接收到 ServObj):

The Interface Segregation Principle is similar to the Single Responsibility Principle in that both deal with the cohesion of responsibilities. In fact, the ISP can be understood as the application of the SRP to an object’s public interface.

To a certain extent, ISP can be considered a sub-set, or more specific form of the Single Responsibility Principle. The perspective shift of ISP, though, examines the public API for a given class or module.



谢谢

最佳答案

1a) 如果一个 IS 需要它的功能,它可以被注入(inject)到一个域服务中 - 即不传递给方法。这与实体不同,这是因为域服务是无状态的,因此可以使用所需的依赖项配置一次并在需要的地方使用,例如由其他实体使用。

1b) 域服务应该作为参数传递给实体,就像您将存储库接口(interface)作为参数传递一样。同样的原则也适用。此外,传递整个存储库接口(interface)会产生不必要的耦合,因此最好声明并传递特定于角色的接口(interface)。

更新

1a) 这是一个原因。另一个是造成不必要的耦合。如果实体上的单个行为只需要存储库,为什么一直将其注入(inject)实体?另外,现在您必须考虑如何解决这些依赖关系?让实体成为依赖注入(inject)图的一部分?这很快使实体的责任重载。

1b) 违反 PI 是违反单一责任原则的更一般概念的一个实例。您仍然可以将 IS 传递给域实体方法,这里的问题不会违反 PI,因为您传递的是接口(interface),而不是实现。如果域方法仅在 IS 接口(interface)上使用一种方法,则问题将违反 SRP。

1c) 见 1a)

1d) 否,因为 PI 是通过使用接口(interface)来维护的。

2)是的,这就是为什么我建议避免直接传递存储库接口(interface)。原理是相似的,因为您可以将存储库接口(interface)和域服务视为抽象服务,为域实体提供一些有趣的行为。然而,最好是非常明确的。因此,与其传递存储库并隐式地理解它恰好为实体提供服务,不如将提供的功能声明为其自己的接口(interface)并使实体依赖于它。

更新 2

1a) 是的,这是正确的,也是主要原因之一。

1b) 这样做并不可怕,但它有可能违反 SRP 或更明确地由 guillaume31 - ISP 指定。所以这比说注入(inject)实体实例要好,但可以通过声明一个特定的接口(interface)来改进。

不,如果您创建一个基于角色的界面,那么这在这种情况下就足够了。

1d) 如果实体使用存储库接口(interface)来持久化自己,那么这违反了 PI。然而,如果它使用存储库接口(interface)来执行一些查询以运行其业务逻辑,那么我们并不是真正在谈论持久性。要真正解耦存储库,请改用特定于角色的接口(interface)。

2a) 是的,出于同样的原因,将存储库注入(inject)实体是不合适的。

2b) 是的,但我只是建议在您将域服务传递给实体上的行为方法的情况下,而不是将其注入(inject)实体实例本身。

更新 3

1a) 这可能是一个我同意的争论点。但是,从实用的角度来看,最好将 DE 设计为消除它们对外部服务的依赖,或者使其变得非常明确和隔离。如果您的 DE 对 IS 具有实例依赖性,则意味着无论何时创建 DE 的实例,例如在重构期间或创建新实体时,都必须在那时提供 IS。这使依赖关系图变得复杂。此外,如果 DE 负责维护其自身状态的完整性,那么为什么会依赖于外部服务?可能需要服务来调用某些行为,但通常可以在没有外部服务的情况下完成保持完整性。事实上,以这种方式依赖外部服务通常是一种责任混淆的味道。

II, III) 这包括诸如保护不变量之类的事情。例如,实体可以通过引发异常来确保其值不会进入不一致的状态。这是 OOP 的一个基本前提——封装状态并公开行为。

IV) 与实体相关的行为,通常需要状态改变,也应该放入实体中。如果此类行为需要使用服务,请传入该服务,但通常会尝试将尽可能多的行为放入实体中。这并不总是完美的,但你可以为理想而努力。

d) 可以肯定的是,当我说注入(inject) IS 时,我的意思是从 DE 获得对 IS 的必需实例引用。由于上述原因,不鼓励这样做。将 IS 传递给 DE 行为方法会更好,但是如果 IS 接口(interface)有很多与手头行为无关的东西,则可能会违反 SRP/ISP。这是 ISP 的基本前提 - 应该依赖特定的接口(interface),而不是碰巧包含所需功能的臃肿接口(interface)。

关于domain-driven-design - 域服务应该如何调用基础设施服务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14612673/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com