我想了解一个班级,一个责任的原则。我找到了一些关于它的文章,但没有例子。如果你能给我一个违反原则的类的例子,那将对我有所帮助。
我熟悉一个方法应该只做一件事的想法,例如 get 和 set 方法。它不能与One Class, One Responsibility相同,因为 set 和 get 方法都是在一个类中实现的。那么这是否意味着该类违反了规则,因为该类有设置和获取的责任?
什么是一类一责任原则?
我想了解一个班级,一个责任的原则。我找到了一些关于它的文章,但没有例子。如果你能给我一个违反原则的类的例子,那将对我有所帮助。
我熟悉一个方法应该只做一件事的想法,例如 get 和 set 方法。它不能与One Class, One Responsibility相同,因为 set 和 get 方法都是在一个类中实现的。那么这是否意味着该类违反了规则,因为该类有设置和获取的责任?
什么是一类一责任原则?
我不是这个设计模式的 100% 专家,但我是这样认为的——如果我创建一个对象,它只负责一件事。如果它需要做其他事情,但与另一个对象相关,根据情况,我会使用继承或接口。
这是一个看起来相当简单的概念。确保特定对象(或方法,就此而言)处理一个逻辑。如果它处理更多,您需要另一个对象(或方法)。
关于不混合职责的原则方面。
如果您有一个处理发票的 InvoiceProcessor 类,根据业务规则进行计算,生成带有发票的 PDF,处理数据库并向卖方注册额外的奖励积分,那么您就有一个明确的需要分离关注点的案例。在这种情况下,应该明确分离甚至委托给其他类。
但是一个类 - 一个责任更加微妙和可怕。如果您必须为发票处理提供解决方案,并且像那些奖励积分一样有几个目标要实现,那么您可以有一个违反多个目标的功能:计算卖家的奖励积分和客户的折扣。
在较小的范围内:如果您有一个具有其数据结构的类,例如优先级队列或其他任何东西,同时将其与用于缓存部分的数据结构混合使用,例如使用 List 和 Map,那么您在某些情况下针对不同的关注点处理数据,甚至可能在缓存列表中寻址,从而使数据结构交织在一起。如果您随后有一个更改优先级并更改缓存状态的功能,那么将来将很难理解这些过程。
我经常遇到需要实现一些不同方面的违规行为,并且它们是在一个类中完成的。然后,API 具有不同抽象级别或困难语义的调用。
这是您不知道自己需要它的事情之一,直到您尝试不使用它并查看它是如何变成一团糟的:
假设您编写了自己的 Logger 实用程序,并且因为它一开始很简单(带有写入标准输出的方法的单例),您决定将其所有功能放入一个类中。当您使用它时,您会想到要添加的更多功能:
登录到的不同目的地(stderr、文件、队列等)
更改消息格式的能力
为不同类别提供单独的记录器
按日志级别过滤类别消息的能力
您希望能够在程序运行时更改日志记录级别
新的日志记录级别(ERROR、WARN、INFO、DEBUG 等)
等等,然后您将每个功能的实现添加到您开始使用的同一个类中。你所做的每一次改变都意味着回到同一个班级,对它进行分类以查看相关内容,然后进行更改。该类将具有不同的生命周期事件,其中每个功能都被初始化,因此所有功能代码都不在一个地方,而是分布在类中的不同方法中。
因为所有代码都挤在一个类中,并且方法包含实现不同功能的代码,所以跟踪更改的所有相关部分变得具有挑战性,并且总是有可能更改可能会无意中影响其他一些功能,因此之前的一些- 现有功能现在可能在某些情况下停止工作。因此,您必须测试类中的所有特征,更糟糕的是,测试所有特征的所有组合,以便捕获这些错误。这意味着测试将不完整,错误可能会潜入。
现在看看像 log4j 这样的真实项目是如何处理这些东西的。不同的类处理格式化、处理输出的写入方式、为类别提供记录器以及所有这些部分之间的交互是明确定义的,结果是当你修补或替换它的一个部分时,关注点是分离的不影响其他部分。用户可以创建自己的类来添加他们需要的功能(他们不需要了解有关日志框架的所有内容,他们只需要知道他们想要添加的特定类型的合同)并将其插入,用户可以混合搭配不同的插件。如果一个插件坏了,这个坏点不会超出插件的范围,对单个部分的更改不会威胁到整个项目的完整性。就合同控制各个部分的交互而言,您无需测试特定功能的所有不同组合。它之所以如此工作,是因为它由各个部分组成,每个部分都有一个单一的职责。
使用单类方法你永远无法做到这一点,有人添加的每一个新功能都将成为项目的一个分支,并且将每个重新合并将是一项越来越大的任务。单一职责原则和其他 SOLID 规则的要点是提供一种整体策略,使软件能够以受控方式更改而不破坏事物。
原理正是它所说的,仅此而已。一个班级应该只有一个职责。但是,定义责任可能很困难。一个示例可以是处理应用程序中所有数据库请求的“DatabaseHandler”类。
延伸阅读:凝聚力。
类中的每一件事都应该与类应该负责的内容相关。
如果它是一个名为 MailSender 的类,它应该只知道如何发送邮件。创建邮件内容的代码不应包含在其中。