门面模式是否违反SRP原则?

8

SRP原则表明:

一个类或模块应该只有一个改变的原因

我有一些Facade类作为我的服务层类,例如SaleService,它提供了一些方法,例如SaveOrder(),CancelOrder(),CreateOrder(),GetAllOrders(),GetAllPlannedOrders()等。

我之所以将它们放在一起,是因为它们具有概念上的关系。
使用这些可能有多个改变原因的方法来编写这样的类是否违反了SRP?如果是,如何解决这个问题?

4个回答

9
外观模式本身并不违反单一职责原则。通常外观模式会隐藏底层对象之间的复杂交互。在这种情况下,外观的“单一职责”是管理这些交互。只要这些交互不发生变化,就没有理由改变你的外观。如果交互变得非常复杂,将外观的实现拆分成多个对象可能是值得的。
从您的示例中看来,我并没有感到您真正试图隐藏复杂性,因此重新考虑在此处使用外观模式可能是有趣的。

谢谢,你说“因此在这里重新考虑使用门面模式可能会很有趣”。你有什么建议? - Masoud
很遗憾,如果不了解您的系统更多信息,很难给出明确答案;对您来说一个好的起点是考虑为什么您认为需要使用外观模式。有几个合理的原因可以使用它。如果您的原因不在其中,那么您可能只会给系统增加复杂性。 - Matthijs P

4
我认为SRP的目的是识别类正在做太多事情的情况,更好的设计应该是有多个类。一个经典的例子是ReportProducer类,它需要做一些工作来收集数据和格式化输出,可能应该有两个类:一个用于收集,一个用于格式化。这种方法的好处之一是灵活性:我们可以使用单个收集类和多个不同的格式化类。
现在你的例子看起来非常合理,你有一个连贯的类,所有的方法都相关,该类的用户知道这是处理订单的类。对我来说,这看起来像是单一职责。
改变的原因是什么?在报告示例中,我们有两种完全不同类型的更改:也许数据来源发生了变化,或者期望的格式发生了变化。在您的示例中,人们可以认为也有多种可能的原因:订单的“形状”可能会改变,期望的接口可能会改变(例如添加一个queryCancelledOrders()方法),您作为Facade的后端可能会发生变化。然而,我不认为这些是违反SRP的迹象:它们都与呈现操纵订单界面的任务相关。
如果我们完全按照“单一更改原因”的字面意思来看,那么我不认为我们可以编写任何类。我们总是有接口和实现,通常还有一些依赖类。其中任何一个都可能会改变,因此我们始终至少有两个,可能有三个更改原因。
相反,考虑“这个类的责任是什么?”你能用一句话表达它而不使用“AND”等词吗?糟糕的:收集数据并格式化报告。

谢谢,那么你认为对于我的SaleService类来说,什么是一个好的句子? - Masoud

2

SRP(单一职责原则)是指一个职责的实现细节发生变化时,即使该职责只是类的一小部分,也可能导致修改类。而 Facade(外观模式)不会以这种精细、更严重的方式违反 SRP,因为它只是一个表面上的反映——它不会在每次操作的内部发生变化时改变。它可能会在某个操作的名称发生变化时发生变化,这会导致一些脆弱性,但并不可怕,或者在我们想要通过 Facade 反映的操作被删除或添加时发生变化——但这更多地与 Facade 选择公开的内容有关,这实际上是其真正的职责。

我最常使用 Facade 是当我希望通过我的代码的单个入口点来消耗第三方组件时。其中一个例子是Anti-Corruption Layer 模式。然而,我通常会三思而后行地创建 Facade 到自己的代码中,因为你很容易被其便利性所吸引,这可能会阻止你真正思考对象之间的依赖关系。

我不确定在你的例子中 SaleService 是否真的是一个 Facade,因为服务通常不仅仅是重定向到某个业务行为(它们可以进行日志记录、授权、事务管理、协调多个对业务的调用等)。


1

是的,但外观模式的主要目的是切换责任分类维度。

外观将子系统中的所有对象封装成一个单一对象,并提供多个公共方法作为接口。

子系统中的对象根据业务实体进行分类。但外观的方法根据用例进行分类。

如果涉及仅一个用例的组件导入了外观,则该组件也可以看到外观的其他用例的方法。也就是说,在组件的视图中,外观具有多个职责。

因此,外观模式通常与接口隔离一起使用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接