为了不破坏 SRP,您是否在单独 类 中定义应用程序的每个业务逻辑功能?

Do you define each business logic function of an application in separate classes in order to not break SRP?

如果您为每个与业务相关的模块(例如 UserService)提供服务 class。您可能有 AddProductToBasket()PlaceOrder().

这些方法将依赖于 IOC 容器中定义的较低级别的模块。 PlaceOrder() 不会直接调用数据库或支付服务,但会将所有逻辑粘合在一起。

虽然这不会破坏单一职责原则。因为即使服务 class 没有直接调用它仍然执行许多不同的业务功能,如果两个业务功能在同一个 class 中发生变化,那么 class 有多种原因因此改变。

每个业务功能都有一个 class 有意义吗?

您在这里遗漏了一个非常重要的观点:域模型和聚合。 在您的示例中,AddProductToBasket 方法应位于 Basket class.

在这种情况下,多个业务功能可能没有意义。确保您在正确的限界上下文中正确地将它们分开。例如,如果您正在使用微服务,您可能希望每个限界上下文都有一个微服务。

我想建议你研究这个博客:

https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html

根据我的理解,我认为这个名字令人困惑。它是应该只承担一个职责的函数。

对我来说,SRP 可以看作:

1). SRP的objective是为了实现内聚,把关系密切的东西放在一起class,关系较小的东西作为依赖和 尽管通常不可能,但代码应尽可能尝试零依赖。

因此,如果您将 UserService 用于 placeOrder() 和 addProductToBucket(),那么您的代码内聚性会降低,从而违反 SRP。

正如@DavidGuida 的回答中提到的,关于限界上下文可以看到凝聚力。

2). class 不应该包含多个 Actor 的业务逻辑(我在上一段中已经解释过了)。 Actor 是指需要统一对待的单个用户或一组用户。就像我们可以将 Admin 和 simple User 作为两个不同的 Actor。

因此,classes 应设计为松散耦合、较少依赖性并处理单一资源。 也就是说,UserService 应该只处理特定于用户的任务,如 registerUser()、updatePassword() 等。

我们可以创建 OrderService 来处理 placeOrder() 和 ProductService 以及 BucketService 来处理 addProductsToBasket()。

BucketService 可以作为 ProductService 的依赖,反之亦然。

ProductService 任务可以是:

  • 检查产品是否可用。
  • 调用 BucketService 将产品添加到存储桶中。
  • 减少产品数量。

BucketService 任务可能是:

  • 检查桶是否已满。
  • 将产品添加到存储桶中。
  • 增加存储桶中产品的数量。

但是,如果管理员和普通用户可以调用 placeOrder(),那么 SRP 就会发挥作用。 然后 OrderService 可以充当 Facade(重命名为 OrderFacade),然后它可以在其中执行类似的操作,对于管理员和用户特定的操作,它可以使用 Strategy Pattern。

就像我们可以创建一个接口 OrderService,其功能由 OrderServiceForAdmin 和 OrderServiceForUser classes 实现。

因此,对于与管理员相关的更改,我们将更新 OrderServiceForAdmin,对于与用户相关的更改,我们将修改 OrderServiceForUser。

参考文献:

上面提到的博客。

罗伯特·马丁的书。 1).清洁代码 2)。干净的架构

注意:我仍在学习这些概念,欢迎提出想法。