SOLID原则与GRASP原则的区别

2025 年 4 月 21 日 | 阅读 7 分钟

SOLIDGRASP 是面向对象设计中的两组不同原则,它们的上下文以及它们的出现/实现/工作的含义都截然不同。

什么是 SOLID?

SOLID面向对象编程 的五个主要原则的定义。它在增强软件的可维护性、可扩展性和模块化方面发挥作用,从而促进类之间的松耦合和高内聚。

SOLID 代表了面向对象设计的五个原则,这些原则可以带来可维护、可扩展且风险较低的系统,减少了系统中的变更和错误。

1. S - 单一职责原则 (Single Responsibility Principle)

定义: 一个类应该只有一个改变的理由,这意味着它应该只有一个且仅有一个工作。

目的: 它缩小了类的职责范围,从而简化了类的实现,以提高可读性和可维护性。

示例: Bill 类应该只负责与账单本身相关的事务,例如计算总额,而不是像通过电子邮件发送发票这样的事务,这些事务由 EmailService 处理。

2. O - 开闭原则 (Open/Closed Principle)

定义: 一个类应该对扩展开放,对修改关闭。

目的: 该原则允许在不修改类源代码的情况下扩展类的功能,从而可能减少引入新错误。

示例: 一个例子是支付系统,我们创建一个名为 PaymentProcessor 的基类,它可以扩展为在单独的类中实现不同的功能,例如 CreditCardPaymentProcessor 或 PayPalPaymentProcessor,并且仍然工作相同。

3. L - 里氏替换原则 (Liskov Substitution Principle)

定义: 超类对象的实例应该可以用子类对象的实例替换,而不会影响程序的正确性。

目的: 它提供了保证,确保派生类在不改变预期行为的情况下扩展其父类的行为。

示例: 如果我们将“Rectangle”作为等效基类,“Square”作为派生类,那么 King 用“Square”替换“Rectangle”应该不会破坏程序的逻辑。

4. I - 接口隔离原则 (Interface Segregation Principle - ISP)

定义: 客户端不应被迫依赖于那些不服务于它们的接口。

目的: 该原则提倡使用更小、更内聚的接口,而不是更大、更通用的接口,以对客户端施加有限程度的依赖。

示例: 不要设计一个像 Worker 这样包含 eat()、work() 和 sleep() 方法的大型接口。相反,应有两个隔离的接口,例如用于 work() 的 IWorker 和用于 eat() 的 IEater,以便类只实现它们需要的内容。

5. D - 依赖倒置原则 (Dependency Inversion Principle - DIP)

定义: 高层模块不应依赖于低层模块。两者都应依赖于抽象。

目的: 该原则鼓励使用接口或抽象类来解耦高层和低层组件,从而增强整体系统的灵活性。

示例: 类应使用像 IDataStore 这样的接口,而不是直接实例化 Database 对象。这提供了灵活性,允许注入任何类型的数据存储(例如,SQLNoSQL)。

什么是 GRASP 原则?

GRASP 是用于表示“通用责任分配软件模式”(General Responsibility Assignment Software Patterns) 的首字母缩写。它们是一组设计模式,有助于开发人员在面向对象设计中决定哪些对象承担哪些责任。GRASP 侧重于系统中类的职责。

1. 信息专家 (Information Expert)

定义: 将责任分配给拥有完成该责任所需信息的类。

目的: 该原则通过将一些职责从一个类转移到拥有完成任务所需信息的类来减轻该类的负担。

示例: 在图书馆应用程序中,Book 类应负责检查其可用性,因为它知道其当前状态。

2. 创建者 (Creator)

定义: 将聚合、包含或紧密使用对象的类的职责分配给该类,负责实例化该类的实例。

目的: 它确定哪个类应承担创建对象的责任,并提供更高的内聚性、更低的耦合性和更易于维护性。

示例: 可能有一个 Library 类负责创建 Book 类的实例,因为它收藏了整本藏书并跟踪它们。

3. 控制器 (Controller)

定义: 将系统事件处理的责任分配给代表特定用例或 UI 控制器的控制器类。

目的: 它有助于处理输入、处理以及系统中各个部分之间的通信。

示例: LibraryController 可以处理用户与图书借阅相关的交互并与系统进行通信。

4. 低耦合 (Low Coupling)

定义: 以使相应依赖级别降低的方式将职责分配给类。

目的: 它有助于减少维护开销,从而一个类的任何后续更改都不会导致许多其他类的更改。

示例: 通过接口和依赖注入可以降低 Library 类与 BookDatabase 中特定实现的耦合。

5. 高内聚 (High Cohesion)

定义: 以一种方式分配职责,使得相互关联的功能保留在一个类中,并且对特定类应该做什么有清晰的定义。

目的: 它使系统更易于理解和维护,因为每个类都做好一件事。

示例: Book 类负责与书本身相关的所有事务(例如,标题、作者和可用性),而不是将此责任委托给其他不相关的类。

6. 多态 (Polymorphism)

定义: 将职责分配给根据类型具有不同实现的行为,使用多态方法,其中子类覆盖基类中的方法。

目的: 这是一个允许系统中灵活扩展的原则,可以添加新类型而对现有代码的更改最小。

示例: 如果有一个 Notification 基类和像 EmailNotification 和 SMSNotification 这样的子类,每个子类都将实现自己的 send() 版本。

SOLID 原则与 GRASP 原则之间的主要区别

Difference between SOLID Principles and GRASP Principles

SOLID 原则和 GRASP 原则之间存在一些主要区别。一些主要区别如下

特点SOLIDGRASP
定义SOLID 代表单一职责、开闭、里氏替换、接口隔离、依赖倒置。Grasp 详细阐述了通用责任分配软件模式。
描述它主要专注于创建可维护、可扩展和可扩展的类。它侧重于如何在系统中的类和对象之间分配职责。
粒度更细粒度的视图,专注于类的设计、构造和相关性。更高层次的视图,侧重于跨系统的职责分配。
主要关注点处理面向对象编程原则,以提高可维护性和可扩展性。为系统的职责分配设定指导原则。
关注关系Grasp 强调通过适当的抽象和接口设计考虑来解耦类。这些对象在哪里以及如何相对于职责进行协作和行动。
抽象更倾向于通过提供 DIP 和 ISP 来实现解耦高层和低层模块交互的原则。它使用多态和间接性等概念来处理对象交互中的变化和依赖。
职责分配它不直接帮助分配职责,大多数讨论都集中在代码的正确结构及其灵活性上。它明确指导这些对象之间的功能如何分配,并结合了一些 GRASP 原则。
用例它用于设计特定类和接口,以确保灵活性并保持系统的可维护性。它在设计系统时用于确定应将职责放在何处以及对象应如何协作。
耦合与内聚它专注于减少类之间的耦合并增加内聚(例如,ISP 和 SRP)。在系统级别处理耦合和内聚,主要考虑类如何共享其职责的交互(低耦合、高内聚)。
多态它通过里氏替换原则 (LSP) 和接口隔离原则 (ISP) 来促进多态。通过将行为职责分配给需要的类型来显式处理多态(多态原则)。

结论

总而言之,SOLIDGRASP 面向对象设计原则在不同层面上倡导先进的软件开发原则。SOLID 原则为所有原则提供了清晰的抽象:单一职责、开闭、里氏替换、接口隔离和依赖倒置。目标是通过类级别设计改进来创建更可维护、更灵活、更可扩展的系统,最大限度地减少方法和类依赖的复杂性,它过度强调了高内聚的某些方面。它还试图在不进行修改的情况下使代码可扩展。

另一方面,GRASP 原则处理面向对象设计中的责任分配。设计人员在实现其设计时,始终以低耦合和高内聚为目标。GRASP 原则的词汇,如信息专家、低耦合和高内聚,为系统中的每个实体定义了不同的角色,并确保更顺畅的协作,从而降低了维护成本。虽然 SOLID 原则优化类,但 GRASP 原则更多地用于构建系统的整体架构。这两种方法是互补的,共同构成了创建功能性面向对象系统的基础。