SOLID 设计原理揭秘

SOLID 设计原理揭秘

本文最初发表于 https://www.learncsdesign.com

坚硬的 是五项设计原则的首字母缩写词,旨在使软件设计更易于理解、灵活和可维护。它们是由 Robert C. Martin 在他的论文“设计原则和设计模式”中介绍的。

根据维基百科,SOLID 的想法是:

  • 单一职责原则 (SRP) — 一个类永远不应该因为一个以上的原因而改变。
  • 开闭原则 (OCP) — 实体应该对扩展开放,对修改关闭。
  • 里氏替换原则 (LSP) — 任何使用基类指针或引用的方法都必须能够在不知情的情况下使用派生类或对象。
  • 接口隔离原则(ISP) — 拥有许多特定于客户端的接口比拥有一个通用接口要好。
  • 依赖倒置原则(DIP) — 依赖于抽象,然后是具体的实现。

让我们更详细地探讨这些 SOLID 原则。

单一职责原则

改变班级应该只有一个原因。

最好让每个类负责软件提供的单个部分功能,并将该职责封装在类中。

该原则旨在降低复杂性。如果其中一件事情发生了变化,你就必须改变一个班级,如果它做了太多的事情。这样做,您可能会破坏课程中您甚至不打算更改的其他部分。

如果您无法一次只关注程序的特定方面,请记住单一职责原则并考虑划分一些类。

开闭原则

类应该对扩展开放,但对修改关闭。

它的主要目的是防止现有代码在实现新功能时被破坏。

你可以扩展一个类,创建一个子类并做任何你想做的事情,添加方法或字段,覆盖行为等。同时,一个类可以对扩展开放,也可以对修改关闭。

修改已经开发、测试、审查并包含在框架或其他代码中的类是有风险的。您可以创建一个子类并覆盖您想要更改的原始类的部分,而不是直接更改代码。您将实现您的目标,但也不会破坏原有课程的任何现有客户。

您不需要创建子类来修复类中的错误。直接修复类中的bug即可。子类不应对父类的问题负责。

里氏替换原则

如果您正在扩展一个类,您应该能够传递子类的对象而不是父类的对象,而不会破坏客户端代码。

子类应与其超类保持兼容。通过扩展其行为而不是完全替换它来覆盖方法。

使用替换原则,您可以预测子类是否与可与超类中的对象一起使用的代码兼容。

与其他可以解释的设计原则相反,替代原则包括一组对子类的形式要求,特别是对它们的方法的要求。

规则 1:子类中方法的参数类型应匹配或比超类中方法的参数类型更抽象。

假设有一个类有一个喂狗的方法

 饲料(狗狗);

此方法将始终从客户端代码传递一个 Dog 对象。

我们创建的子类覆盖了该方法,以便它可以喂养任何动物(狗的超类)。

 饲料(动物);

现在,如果我们将这个子类的对象而不是超类的对象传递给客户端代码,一切仍将按预期工作。该方法能够喂养所有动物,因此它仍然可以喂养客户经过的任何狗。

然后您创建了另一个子类并将喂养方法限制为仅接受哈士奇狗(Dog 的子类)。

 饲料(哈士奇狗);

因为该方法只喂特定品种的狗,所以它不会为客户端传递的通用狗提供服务,从而破坏了所有功能。

规则 2:在子类方法中,返回类型必须匹配或者是超类方法中返回类型的子类型。

考虑一个有方法的类

 狗买狗();

执行此方法后,客户端代码期望接收任何狗。

我们现在创建了一个覆盖该方法的子类,如下所示

 哈士奇狗买狗();

客户得到了一只哈士奇狗,它仍然是一只狗,所以一切都很好。

现在您已经创建了另一个覆盖该方法的子类,如下所示

 动物购买狗();

现在,客户端代码中断,因为它接收到一个不适合用于狗的结构的未知通用动物。

规则 3:子类中的方法不应该抛出基方法不应该抛出的异常。

在客户端代码中,try-catch 块针对基方法可能抛出的特定类型的异常。因此,意外的异常可能会穿过客户端代码的防御线并导致整个应用程序崩溃。

规则 4:子类不应强化前置条件。

考虑基方法具有 int 类型参数的情况。子类可以覆盖该方法并要求传递给该方法的参数的值为正,这加强了先决条件。

过去在将负数传递给方法时可以正常工作的客户端代码现在在开始使用此子类时会失败。

规则 5:子类不应该削弱后置条件。

让我们想象一个具有与数据库交互的方法的类。返回值后,该类的方法应该关闭所有打开的数据库连接。

我们创建了一个保持数据库连接打开的子类,以便我们可以重用它们。但是,客户端在调用该方法并泄漏数据库连接资源后可能没有意识到您的意图并关闭程序。

规则 6:超类必须保留其不变量。

不变量是对象有意义的条件。扩展类时,最安全的方法是引入新的字段和方法,而不会影响超类的任何现有成员。

规则 7:子类不应修改超类的私有字段。

与流行的看法相反,可以访问和修改私有字段。一些编程语言,例如 Java,允许您通过反射访问私有字段。子类永远不应该触及超类的私有字段。

接口隔离原则

不应强迫客户依赖他们不使用的方法。

使您的接口足够窄,以便客户端不必实现他们不需要的行为。胖接口应该被分解成更细粒度和更具体的接口。只应实施客户真正需要的方法。

类只能从一个超类继承,但它们可以同时实现任意数量的接口。

依赖倒置原则

高层的类不应该依赖于低层的类。两者都应该依赖于抽象。抽象不应依赖于细节(具体实现)。相反,抽象应该决定细节。

设计软件时通常有两个级别的类:

  • 低级类 — 使用这些类,您可以使用存储、通过网络移动数据、连接到数据库等。
  • 高级班 — 复杂的业务逻辑包含在这些类中,指导低级类做某些事情。

人们通常先设计低级类,然后再处理高级类,因为在低级设计明确之前,他们不确定在高层次上什么是可能的。

根据依赖倒置原则,这种依赖应该倒置。

应该有高级类所依赖的低级操作的接口,最好是在业务方面。高级类现在可以依赖于这些接口,而不是具体的低级类。当低级类实现这些接口时,它们就依赖于业务逻辑层,将原来依赖的方向颠倒过来。

旋拧​​平头型螺钉和旋出平头螺丝时,起子手柄(高级级)使用固定平头工具(低级)。由于螺丝类型与螺丝刀柄类紧密耦合,如果螺丝类型发生变化,将会影响螺丝刀柄类。

创建一个高级接口,描述任何螺丝类工具如何拧/拧任何螺丝,并使螺丝刀手柄类使用该接口而不是低级接口。然后,您可以修改或扩展螺丝类型工具以适应新螺丝类型,而不会影响螺丝刀手柄类的更改。

如果你喜欢这篇文章,别忘了鼓掌。如果你想连接,你可以找到我 领英 .

参考

https://en.wikipedia.org/wiki/SOLID
Alexander Shvets 深入研究设计模式

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/39358/38512611

posted @ 2022-09-26 11:39  哈哈哈来了啊啊啊  阅读(49)  评论(0编辑  收藏  举报