SOLID 软件设计原则及其在微服务架构设计中的应用

发布日期:2026-07-13 10:15:03   来源 : 杭州电子商务研究院    浏览量 :14
杭州电子商务研究院 发布日期:2026-07-13 10:15:03  
14

介绍

设计原则是好的;它们可以指导我们做出重要决策。在设计软件时,依靠经过验证的成熟“建议”是有帮助的 - 特别是在考虑以下事实时:

  • 计算机科学领域对于我们的世界来说相当“新”。

    因此,新技术、开发语言、运行时和范例相当常见。

    因此,计算机科学这本“书”尚未(也可能永远不会)完成。随着现实世界需求的出现和软件行业的发展以满足这些需求,书中不断增加章节。

    在观察新发现的领土时依靠“最佳实践”将被证明是有益的(至少在统计上)。

  • 许多市场竞争非常激烈。将产品上架可能既有预算紧张的问题,又有时间限制。

    在这种情况下,最好是尽量少留“未解决”的问题。
    有些问题已经被问过很多次了,我们可以依靠经过验证的答案。

  • 编写出色的软件很难。你可以做很多简单的事情,但这些事情根本就不正确。承认这一事实实际上是开发更好的做事方式的驱动力。

    与前一点不同的是,这里我们不是讨论已知问题的答案,而是讨论我们如何回答剩余的未决问题。

本文介绍了“SOLID”软件设计原则以及它们如何适应微服务子领域。

希望您喜欢这篇文章。让我们开始吧!

SOLID 软件设计原则 - 简史

面向对象软件设计在 20 世纪 90 年代开始流行之后不久,人们也清楚地认识到,面向对象的设计并不能免受任何人类书面内容的“优点”的影响——它可能写得很差。

庞大的类和方法、代码和/或配置重复、在单个代码块中执行太多操作等等 - 仍然是可能的。而且很容易恢复旧习惯。

我在这里想要说的是,范式转变为面向对象的软件设计并没有解决我们所处的“混乱”局面。

这就像今天对敏捷软件开发的“炒作”。一些被迫在SCRUM模式下工作的团队对日常会议没有热情(他们认为这是浪费时间),只想回到椅子上工作(因为他们认为这是最有效率的)。他们规划会议的方法也是一样的。

请不要误解我的意思。我并不反对 SCRUM。我只是说,一个人工作方式的任何范式/重大变化都应该被他完全接受 - 明智地接受,理解并致力于范式。

好的,我们知道在面向对象软件设计出现之前有可能编写出“糟糕的”软件,我们也知道在面向对象软件设计出现之后也有可能编写出“糟糕的”软件。

那么,何必呢?

嗯,显然,面向对象软件设计领域更容易“带来秩序”和指导,因为它呈现了抽象。对象及其方法和继承树为编程语言提供了额外的抽象(例如作为一等公民的接口)——处理这些抽象时需要谨慎和有序。

您很快就会看到,本文涵盖的大多数原则都与针对特定代码片段的建议有关(例如,它的职责、它应该执行多少逻辑上的事情、它应该向外界公开什么、它可以复制多少次),这些都与观察到的想法有关。

这些建议(以及其他建议)由罗伯特·C·马丁提出,被称为 SOLID 原则。“SOLID”一词中的每个字母代表一个原则:

  • 单一职责
  • /闭
  • 利斯科夫换人
  • 接口隔离
  • 依赖倒置

尽管完全遵循这些原则也不能保证您的软件是万无一失的,但这些原则在面向对象软件设计领域的成功项目中已经得到了一次又一次的证明。

它甚至对我有用。

让我们在 SOLID 原则的创建背景下对其进行概述。首先:面向对象软件设计的背景。一旦我们完成了这项工作,我们就能够在最近出现的微服务范式中观察到这些原则。

单一责任原则

单一责任原则规定一个类应该只有一个改变的原因。

很多人对这个原则添加了自己的理解,即“一个类应该只执行单一任务”。

虽然这种添加非常有益,但它实际上是“真实”含义的副作用:

  • 类的内部应该是高度耦合的
  • 对类的某个特定区域的改变应该影响所有依赖类

现在,虽然直觉上这听起来像是一件坏事,但它实际上是根据类在系统中的功能责任将类“切割”成小块的驱动力。这样做使我们能够根据要更改的类的依赖关系隔离软件中的特定“更改区域”。如果我们正确地“剖析”代码,我们通常会发现每个小类的依赖关系都比之前的“大”类少。

开放/封闭原则

“开放/封闭”原则规定软件实体应该对扩展开放,但对修改关闭。

是的,我知道。一开始有点困惑。

首先让我们澄清一下实体是什么。在面向对象软件设计领域,实体是类、模块或函数。一些面向对象编程语言在抽象方面有所不同(例如,有些不包含模块抽象),但总的来说,它们都有一些共同点:

它们都允许我们定义具有唯一状态(唯一的,即使仅通过存储在内存中的地址)和所有其他对象实例共享的共同行为的对象实例。

我们所指的实体是我们用来实现对象的代码抽象(无论是对象模板分类还是我们编写了给定对象的特定行为的函数)。

我们来看一个违反该原则的例子:

Car 类有三种加速方法 - 每个车型一种。

如果我们要向我们的系统引入额外的汽车模型,我们就必须修改 Car 类本身!

这意味着我们在扩展系统时进行了不希望的修改。

让我们看一个不违反开放/封闭原则的设计:

在这个设计中,我们可以看到,通过使用接口,并将行为实现的责任传递给继承类,我们已经“封闭”了我们的系统以进行修改,同时保持它对扩展“开放”(即添加新的车型)。

里氏替代原则

里氏替换原则 (Liskov Substitution Principle) 指出,如果在程序中将类型 T 的对象替换为类型 S 的对象,当 S 是 T 的子类型时,程序的特性不应改变(例如正确性)。

虽然这对你来说听起来非常直观,但今天你需要了解一些编程语言实际上允许子类型修改其超类型行为!

因此,这个“扩展”原则基本上是对避免这种陷阱的警告。

接口隔离原则

这个原则听起来很简单,但却非常强大:

对象应该只依赖于它所需要的接口,而不应该被强制实现它不需要的任何方法(或属性)。

您是否遇到过两个继承了相同接口的类,但其中一个(甚至两个)都没有使用该接口中的一个或多个方法?

当然了。我们都这么做过。

请看以下示例:

      interface IMatrixOperations
{
    Matrix GetInverseMatrix();
    Matrix Transpose ();
}
    

我们在这里看到的是定义矩阵操作的接口 IMatrix。

我们看到接口包含方法GetInverseMatrix()

但是,计算矩阵的逆矩阵只与常规矩阵有关。为什么这种行为应该在通用接口中描述,而不是在单独的接口(例如IRegularMatrix)中描述?真的没有理由。让我们开始吧:

      internal interface IRegularMatrixOperations
{
    Matrix GetInverseMatrix();
}

interface IMatrixOperations : IRegularMatrixOperations
{
    Matrix Transpose ();
}
    

“分解”接口描述行为可以让我们提高代码的可读性、可测试性和可维护性。

依赖倒置原则

对于依赖反转,我将首先引用以下原则:

A. 高级模块不应该依赖于低级模块。两者都应该依赖于抽象。

B. 抽象不应该依赖于细节。细节应该依赖于抽象。

很有趣,对吧?

再者,现在这看起来相当直观,因为我们已经习惯了使用接口“连接”我们的组件。

然而,许多初级开发人员一再犯这个错误,因为(显然)我们的人类思维倾向于分层思考。

以下“糟糕”的例子并不罕见:

      internal class Gear
{
}

internal class Engine
{
    Gear gear;
}

class Car
{
    Engine engine;
}
    

看到那里的“问题”了吗?

我们的高级类Car与Engine类紧密耦合反过来,Engine类又与Gear类紧密耦合。

我们创建了一个紧密耦合的系统。每个低层组件都直接被上层组件使用。

我们如何解决这种情况?答案很简单,使用组件之间的接口。

      internal interface IGear
{
}

internal class Gear : IGear
{
}

internal interface IEngine
{
}

internal class Engine : IEngine
{
    IGear gear;
}

class Car
{
    IEngine engine;
}
    

通过提取每个依赖实体之间的“契约”,我们将每个实体与其之前的依赖项分离。现在,每个实体与其依赖项之间共享一个契约。

微服务设计原则 - 当今的炒作

如今,似乎每个人都在谈论微服务。许多人声称他们的软件平台是一个微服务平台,其余的(大多数)人则声称他们正在朝着这个方向发展。

他们都在谈论什么?最重要的是,我们学到的东西是否可以应用到这个新领域?我认为有。

我们首先来解释一下微服务软件架构的核心原则。

与任何抽象一样,无论是新的还是非新的,备受关注的范式、技术或概念,您都可能会请不同的人向您解释并得到不同的答案。

但是,大多数答案都会与以下的想法和特征有关,我将在这里进行描述。

独立部署

首先,微服务应该是可独立部署的。您的软件系统可以作为整体部署,但这不是强制性的。服务(微服务)可以在系统运行时添加(和删除)。微服务应与其依赖项(如数据库、第三方组件)一起部署(如果有)。

模块化

每个微服务都是一段独特的代码,运行在单独的进程中,可能托管在与其他微服务不同的机器上。作为服务于业务目标的更大“拼图”的一部分,它负责为系统提供单个“片段”或“功能”。

沟通

必要时,微服务应使用定义明确、标准且轻量级的通信机制与“外部世界”(例如其他微服务)进行通信。我见过(和写过)系统,其中服务仅通过 HTTP/REST(使用 Json)公开其端点,以及微服务仅通过队列进行通信。还有这些的混合。无论您选择哪种方式,保持通信标准的“秩序”对于您的成功至关重要。

尺寸

我把它放在最后,尽管你可能希望我首先谈论“大小”,正如“服务”这个名字所暗示的那样。

<font style="vertical-alig

以上内容来自杭州电子商务研究院推送
关注
关于我们
热门推荐
合作伙伴
免责声明:本站部分资讯来源于网络,如有侵权请及时联系客服,我们将尽快处理
Copyright © 2025-2027 ToB产业网址导航 公安备案 浙公网安备33010602013138号 浙ICP备16025413号-9
支持 反馈 关注 数据