7 大设计原则总结篇(41张图解、2万多字、非常详细)

来源:mikechen的互联网架构

无论是哪一种设计模式,都需要遵循设计原则

如果说设计模式则是具体运用,那么设计原则就是理论指导。

因此,要想理解设计模式的精髓,就需要先深入 7 大设计原则

本文,我们重点介绍设计模式的 7 大原则


01
  设计模式的概述

1.1  设计模式是什么

设计模式(Design Pattern)是软件开发经验的总结,是一套解决特定问题领域的通用、可重用的解决方案。

简单理解,就是通过复用成功的设计和体系结构,来解决反复出现的通用问题。

设计模式一共有 23 种,每一种模式都有明确的用途和适用场景,解决的问题都是不一样的。

1.2  设计模式的起源


1995 年,Gang of Four  联合出版了图书《设计模式:可复用面向对象软件的基础》。

在这本书中,第一次将设计模式提升到理论高度,并将之规范化,23 种经典的设计模式被首次提出。


1.3  设计模式的作用


设计模式通过复用成功的设计和体系结构,提高了代码的重用性可读性、可靠性、可扩展性

  • 将通用功能封装在可重用的组件中,减少了代码的冗余;

  • 提供了一种结构化的方式来组织代码,减少代码的复杂性;

  • 有新的需求和变化时,可以轻松进行扩展,减少了对现有代码的破坏性更改。


02
  设计模式的七大设计原则

在前面的系列文章中,我们介绍了 7 大设计原则。

它们分别是开闭原则、里氏替换原则、依赖倒置原则、单一职责原则、接口隔离原则、迪米特法则、合成复用原则。

 7 大设计原则的简介(详解见下文):

设计模式的 7  大设计原则,以实现“高内聚、松耦合”的软件系统为目标。

下面,我们逐一详解。


03
  单一职责原则

单一职责原则,英文全称 Single Responsibility Principle,又称为单一功能原则

单一职责原则是指一个类要职责单一,只负责一个特定的功能或任务。

单一职责原则让每个类都专注于一个明确的职责,降低了代码的复杂性,提高代码的可维护性。

单一职责原则的 UML 类图:

单一职责原则的难点是:

如何将类的职责划分得清晰明了,如何识别和消除不必要的职责......。

在实际开发中,我们很容易将不同的责任归类在一起,或者过度拆分。

是否需要拆分职责,参考思路:

当变化发生,只影响其中一个职责,那就需要拆分。如果变化都影响到这两个职责,那就不需要拆分。

完整内容,查看详解篇:一文吃透单一职责原则

 

04
  开闭原则

开闭原则,英文全称 Open/Closed Principle。

开闭原则是指一个软件实体(类、函数等),应该 对扩展开放对修改封闭 

开闭原则是面向对象设计中“可复用设计”的基石。

开闭原则通过实现一个热插拔的效果,在不破坏现有功能、不修改原有代码的情况下,去扩展原有代码,让系统可维护、可扩展、可复用。

开闭原则的 UML 类图:

开闭原则的示例:

假设:

我们要实现一个绘制图表的功能,支持多种图表显示方式,例如柱状图、饼状图...等多种图表。

系统结构:

......

完整内容,查看详解篇3 分钟吃透开闭原则,架构设计筑基必知必会


05
  里氏替换原则

里氏替换原则(LSP),又称为里氏代换原则,英文全称 Liskov Substitution Principle。

里氏替换原则中的“里氏”,取自其提出者麻省理工学院的 Liskov 女士。

里氏替换原则的定义

所有引用基类(父类)的地方,必须能透明地使用其子类的对象,但不能修改父类已有的功能。

即,任何父类在的地方,都可以替换成子类,并且要保证原有程序的逻辑行为和正确性。

里氏替换原则提高了代码的重用性、兼容性、扩展性。

但是,里氏替换原则也有一些缺点。例如,继承是侵入性的,降低了代码的灵活性,增强了耦合性。

里氏替换原则的实例:

假设:

一个电商系统中,用户分为两类:VIP用户、普通用户。

现在,需要实现一个发送邮件的功能。

没有遵循里氏替换原则,是这样设计的:

......

完整内容,查看详解篇: 微信一面挂,痛失 50 W,只因里氏替换原则没说清楚

 

06
  依赖倒置原则

依赖倒置原则(DIP),英文全称 Dependency Inversion Principle。

依赖倒置原则是指要面向接口编程。

高级模块不应该依赖于低级模块,它们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。

依赖倒置的 UML 类图:

依赖倒置原则的两个核心思想:

1) 高层模块不应依赖于底层模块,高层模块、底层模块都应依赖于抽象

2) 抽象不应该依赖于细节,细节应该依赖于抽象

这意味着,

在软件设计中,应该使用抽象类、接口或抽象方法等抽象层,来定义模块之间的通信接口。

而具体实现,应该依赖于这些抽象。

一图释义:

依赖倒置原则的实现示例:

假设:

现在你需要实现一个面包店,你第一件想到的事情是什么?

我想到的是一个面包店,里面有很多具体的面包。

例如:法棍面包、全麦面包、白面包、牛角面包、荞麦面包、法式面包、甜甜圈面包、裸麦面包。

传统依赖关系:

面包店就是上层模块,面包是下层模块。如图:

代码示例:

......

完整内容,查看详解篇: 依赖倒置原则看这篇就够了

 

07
  接口隔离原则

接口隔离原则(ISP),英文全称 Interface Segregation Principle。

接口隔离原则是指在设计接口时要精简单一,只包含客户端需要的方法,而不包含多余的方法。

简单理解:

  • 客户端需要什么接口,就提供什么接口,不需要的就不依赖。

  • 将大接口拆分成多个小接口,每个接口只专注服务于一个子模块或业务逻辑。

  • 使用抽象类或默认方法,来减少接口的改动对原有代码的影响。

接口隔离原则的核心是接口细化,接口细化要合理,结合系统的实际需求,以适度设计为前提,既小而精确。

在软件设计最初,我们的想法是将相同功能的方法放在同一个接口里面。

理论上来说,这貌似没错,我们来看看如何设计。

例如:

类 A 通过接口 I 依赖类 B,类 C 通过接口 I 依赖类 D。

那么,对于类 A 和类 B 来说,接口 I 不是最小接口,则类 B 和类 D 必须去实现它们不需要的方法。

如图:

类 A 依赖接口 I 中的方法 1、方法 2、方法 3,类 B 是对类 A 依赖的实现。

类 C 依赖接口 I 中的方法 1、方法 4、方法 5,类 D 是对类 C 依赖的实现。

对于类 B 和类 D 来说,虽然都有用不到的方法(红色字体),但由于实现了接口 I,所以也必须要实现这些用不到的方法。

代码示例:

......

完整内容,查看详解篇: 精通接口隔离原则,轻松实现高内聚、低耦合架构

 

08
  合成复用原则


合成复用原则(CRP),又称为组合/聚合复用原则,英文全称 Composite Reuse Principle。


合成复用原则要求在实现代码复用时,尽量先使用组合或聚合等关联关系,其次考虑使用继承关系


合成复用原则的核心思想:


  • 将不同的类、模块或组件组合在一起,来创建新的类或对象。

  • 尽量不通过继承已有的类来获得需要的功能。

 合成复用原则的实现示例:

假设:

在一个汽车分类管理程序中,汽车有两种分类方式:

  • 按动力源分类:汽油汽车、电动汽车等;

  • 按颜色分类:白色汽车、黑色汽车和红色汽车等。

如果使用继承,就需要同时考虑这两种分类,将会产生6个组合。

这样的方式会带来两个问题:

  • 导致子类过多。

  • 任何一个分类发生变更,都要修改源代码,违背了开闭原则。


图例:

代码示例:

......

关于合成复用原则的概念、背景、作用、UML、示例、应用,以及组合和继承的选型思路的全面详解。

完整内容,查看详解篇: 合成复用原则全面解析(附图解及源码实例)

 

09
  迪米特法则


迪米特法则(LoD),又称为最少知识原则,英文全称 Least Knowledge Principle。

迪米特法则是指一个模块(类)只和与它高度相关的模块交流,尽量减少与其他模块(类)的直接交流。

大白话就是,模块之间的通信应该简单明了,每个模块只需要关心与它高度相关的模块,而不必了解整个系统的细节。

这有点像在现实生活中,你只与你的朋友直接交流,而不会与朋友的朋友(陌生人)交流。你的任何改变,都不会对朋友的朋友带来影响。

迪米特法则的由来

低耦合、高内聚是软件编程的总原则。

  • 耦合:指模块之间的联系程度。

  • 内聚:指模块内部元素的联系程度。

模块之间了解得越多,耦合就越紧。

任何一个模块的变化,都会影响到其他模块,系统就会变得很复杂。

只有尽可能降低各个模块之间的耦合,才能提高代码的复用率。

怎样才能实现低耦合呢?

这正是迪米特法则要去实现的。

迪米特法则的代码示例:

......

完整内容,查看详解篇: 2分钟通俗理解迪米特法则

 

总结
  

本文主要详解设计模式的 7 大设计原则。

计模式的提出,是为了解决一个常见的问题而总结出来的解决方案设计模式一共有 23 种,不同的设计模式,解决的问题是不一样的,后续我将持续连载更新这个部分

请使用浏览器的分享功能分享到微信等