为了不破坏 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)。干净的架构
注意:我仍在学习这些概念,欢迎提出想法。
如果您为每个与业务相关的模块(例如 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)。干净的架构
注意:我仍在学习这些概念,欢迎提出想法。