设计模式系列-第二章(设计原则-SOLID)_设计模式第二章完整代码-程序员宅基地

技术标签: 设计模式  

前言:SOLID 原则并非单纯的 1 个原则,而是由 5 个设计原则组成的,它们分别是:单一职责原则、开闭原则、里式替换原则、接口隔离原则和依赖反转原则,依次对应 SOLID 中的 S、O、L、I、D 这 5 个英文字母。

一、单一职责原则(SRP)

       单一职责原则的英文是 Single Responsibility Principle,缩写为 SRP。一个类或者模块只负责完成一个职责(或者功能)。单一职责原则是为了实现代码高内聚、低耦合,提高代码的复用性、可读性、可维护性。单一职责原则通过避免设计大而全的类,避免将不相关的功能耦合在一起,来提高类的内聚性。同时,类职责单一,类依赖的和被依赖的其他类也会变少,减少了代码的耦合性,以此来实现代码的高内聚、低耦合。但是,如果拆分得过细,实际上会适得其反,反倒会降低内聚性,也会影响代码的可维护性。

判断是否单一职责

  • 类中的代码行数、函数或属性过多,会影响代码的可读性和可维护性,我们就需要考虑对类进行拆分;
  • 类依赖的其他类过多,或者依赖类的其他类过多,不符合高内聚、低耦合的设计思想,我们就需要考虑对类进行拆分;
  • 私有方法过多,我们就要考虑能否将私有方法独立到新的类中,设置为 public 方法,供更多的类使用,从而提高代码的复用性;
  • 比较难给类起一个合适名字,很难用一个业务名词概括,或者只能用一些笼统的 Manager、Context 之类的词语来命名,这就说明类的职责定义得可能不够清晰;
  • 类中大量的方法都是集中操作类中的某几个属性,比如,在 UserInfo 例子中,如果一半的方法都是在操作 address 信息,那就可以考虑将这几个属性和对应的方法拆分出来。

二、开闭原则(OCP)    

       开闭原则的英文全称是 Open Closed Principle,简写为 OCP。详细表述一下,那就是,添加一个新的功能应该是,在已有代码基础上扩展代码(新增模块、类、方法等),而非修改已有代码(修改模块、类、方法等)即对扩展开放、对修改关闭。

       添加一个新功能,不可能任何模块、类、方法的代码都不“修改”,这个是做不到的。类需要创建、组装、并且做一些初始化操作,才能构建成可运行的的程序,这部分代码的修改是在所难免的。我们要做的是尽量让修改操作更集中、更少、更上层,尽量让最核心、最复杂的那部分逻辑代码满足开闭原则。回到这条原则的设计初衷:只要它没有破坏原有的代码的正常运行,没有破坏原有的单元测试,我们就可以说,这是一个合格的代码改动。

       很多设计原则、设计思想、设计模式,都是以提高代码的扩展性为最终目的的。特别是 23 种经典设计模式,大部分都是为了解决代码的扩展性问题而总结出来的,都是以开闭原则为指导原则的。最常用来提高代码扩展性的方法有:多态、依赖注入、基于接口而非实现编程,以及大部分的设计模式(比如,装饰、策略、模板、职责链、状态)。

       基于一定的粒度(例如模块,类,属性等),扩展是平行地增加,修改是变更更细粒度的子集。扩展和修改和具体的粒度有关。不同的粒度下,扩展和修改定义不同。我个人以为,扩展的结果是引入了更多的平行结构(例如相似的派生类handler),以及支持这些平行结构的代码(利用多态,在关键的地方使用接口)。这些引入会让代码结构变的扁平一些,但是也更晦涩一些。修改,往往会增加代码的深度(这里指更低粒度的复杂度),例如,文中log例子,修改后,check函数有五个参数,内部的if else逻辑更多。但是,如果从参数以及if作用域的角度,这也可算作扩展。所以,扩展还是修改更本质的区别在于修改发生的粒度和层次。通常偏好修改发生在更高的层次上,这要求我们能够用接口和组合把系统合理的切分,做到高内聚和低耦合。高内聚可以让修改发生在更高层次上,替换掉整个低层次实现细节。低耦合,可以让模块之间的调用最小化,可以让高层次的修改最小化。支持高层次的平行结构不是免费的,除非有明确的收益(例如文中隔离Kafka实现细节的例子),不然还是让重构等待到需要的那一刻,预测未来的大部分平行结构其实不会被真正用到。

三、里式替换原则(LSP)

        里式替换原则的英文翻译是:Liskov Substitution Principle,缩写为 LSP。

        里式替换原则是用来指导,继承关系中子类该如何设计的一个原则。理解里式替换原则,最核心的就是理解“design by contract,按照协议来设计”这几个字。父类定义了函数的“约定”(或者叫协议),那子类可以改变函数的内部实现逻辑,但不能改变函数原有的“约定”。这里的约定包括:函数声明要实现的功能;对输入、输出、异常的约定;甚至包括注释中所罗列的任何特殊说明。理解这个原则,我们还要弄明白里式替换原则跟多态的区别。虽然从定义描述和代码实现上来看,多态和里式替换有点类似,但它们关注的角度是不一样的。多态是面向对象编程的一大特性,也是面向对象编程语言的一种语法。它是一种代码实现的思路。而里式替换是一种设计原则,用来指导继承关系中子类该如何设计,子类的设计要保证在替换父类的时候,不改变原有程序的逻辑及不破坏原有程序的正确性。

四、接口隔离原则(ISP)

        接口隔离原则的英文翻译是“ Interface Segregation Principle”,缩写为 ISP。直译成中文的话就是:客户端不应该被强迫依赖它不需要的接口。其中的“客户端”,可以理解为接口的调用者或者使用者。

        如果把“接口”理解为一组接口集合,可以是某个微服务的接口,也可以是某个类库的接口等。如果部分接口只被部分调用者使用,我们就需要将这部分接口隔离出来,单独给这部分调用者使用,而不强迫其他调用者也依赖这部分不会被用到的接口。如果把“接口”理解为单个 API 接口或函数,部分调用者只需要函数中的部分功能,那我们就需要把函数拆分成粒度更细的多个函数,让调用者只依赖它需要的那个细粒度函数。

接口隔离原则与单一职责原则的区别

       单一职责原则针对的是模块、类、接口的设计。接口隔离原则相对于单一职责原则,一方面更侧重于接口的设计,另一方面它的思考角度也是不同的。接口隔离原则提供了一种判断接口的职责是否单一的标准:通过调用者如何使用接口来间接地判定。如果调用者只使用部分接口或接口的部分功能,那接口的设计就不够职责单一。

五、依赖反转原则(DIP)

       依赖反转原则。依赖反转原则的英文翻译是 Dependency Inversion Principle,缩写为 DIP。依赖反转原则也叫作依赖倒置原则。这条原则跟控制反转有点类似,主要用来指导框架层面的设计。高层模块不依赖低层模块,它们共同依赖同一个抽象。抽象不要依赖具体实现细节,具体实现细节依赖抽象。

举例就是tomcat和Web 应用程序代码。Tomcat 和应用程序代码之间并没有直接的依赖关系,两者都依赖同一个“抽象”,也就是 Servlet 规范。Servlet 规范不依赖具体的 Tomcat 容器和应用程序的实现细节,而 Tomcat 容器和应用程序依赖 Servlet 规范。

控制反转(IOC)

控制反转的英文翻译是 Inversion Of Control,缩写为 IOC。

控制反转是一个比较笼统的设计思想,并不是一种具体的实现方法,一般用来指导框架层面的设计。这里所说的“控制”指的是对程序执行流程的控制,而“反转”指的是在没有使用框架之前,程序员自己控制整个程序的执行。在使用框架之后,整个程序的执行流程通过框架来控制。流程的控制权从程序员“反转”给了框架。
控制反转是一种编程思想,把控制权交给第三方。依赖注入是实现控制反转最典型的方法。

依赖注入(DI)

依赖注入是一种具体的编码技巧。我们不通过 new 的方式在类内部创建依赖类的对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类来使用。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/king13127/article/details/115326631

智能推荐

Android adb shell相关命令_android的shell命令工具:设备规范管理-程序员宅基地

文章浏览阅读711次。adb(调试桥):debug工具。adb作用:借助adb工具,可以管理设备或手机模拟器状态。adb相关操作命令如下: 1. 显示系统中全部Android平台: android list targets2. 显示系统中全部AVD(模拟器): android list avd3. 创建AVD(模拟器): android create avd_android的shell命令工具:设备规范管理

Centos 7.9 在线安装 VirtualBox 7.0_centos安装virtualbox-程序员宅基地

文章浏览阅读769次,点赞10次,收藏7次。Centos 7.9 在线安装 VirtualBox 7.0_centos安装virtualbox

VsCode 配置java环境(详细教程)_vscode配置java开发环境-程序员宅基地

文章浏览阅读7.3w次,点赞156次,收藏636次。下载和安装java,VsCode 快速配置 java环境,教程带图简单易懂。_vscode配置java开发环境

【Ubuntu命令大全】_ubuntu可执行文件如何用命令执行-程序员宅基地

文章浏览阅读3.1k次,点赞4次,收藏29次。Ubuntu命令大全,方便使用_ubuntu可执行文件如何用命令执行

mysql错误:java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or represents_eclipse连接mysql 出错java.sql.sqlexception: the server-程序员宅基地

文章浏览阅读793次。问题:java.sql.SQLException: The server time zone value ‘�й���׼ʱ��’ is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone con..._eclipse连接mysql 出错java.sql.sqlexception: the server time zone value

c/c++数组详解_c++数组概念-程序员宅基地

本文介绍了C/C++数组的概念和特点,以及一维数组的定义方式。数组是存放相同类型数据元素的集合,具有相同数据类型和连续内存位置的特点。文章以代码示例的方式展示了一维数组的定义和使用。

随便推点

Machine Learning 2 - 非线性回归算法分析_非线性回归分析方法-程序员宅基地

文章浏览阅读2.8k次。2017-08-02@erixhao 技术极客TechBoosterAI 机器学习第二篇 - 非线形回归分析。我们上文深入本质了解了机器学习基础线性回归算法后,本文继续研究非线性回归。非线性回归在机器学习中并非热点,并且较为小众,且其应用范畴也不如其他广。鉴于此,我们本文也将较为简单的介绍,并不会深入展开。非线性回归之后,我们会继续经典机器学习算法包括决策_非线性回归分析方法

hive基本函数_josn mincol-程序员宅基地

文章浏览阅读164次。一、关系运算:1.等值比较: =语法:A=B操作类型:所有基本类型描述:如果表达式A与表达式B相等,则为TRUE;否则为FALSE举例:hive>select 1 from lxw_dual where 1=1;12.不等值比较: <>语法: A <> B操作类型:所有基本类型描述:如果表达式A为NULL,或者表..._josn mincol

FI 与SD MM相关接口配置_sd 和fi 接口产生什么凭证?-程序员宅基地

文章浏览阅读767次。1 FI/SD 借口配置FI/SD通过tcode VKOA为billing设置过帐科目,用户可以创建自己的科目定义数据表。 科目是做到COA级的,通过KOFI/KOFK这两个condition type确定分别过帐到FI和CO凭证中。 由于PricingProc.是同Sale_sd 和fi 接口产生什么凭证?

开发与研发-程序员宅基地

文章浏览阅读229次。转:http://blog.sae.sina.com.cn/archives/981按:这几天我一直在写这篇东西,本来是胸有成竹,没想到后来越写越发现自己在这个题目下有太多话想说,而以我现在的能力又不能很好地概括总结,以至于越写越长,文章结构也变得混乱,到后来修改的时候每次都要考虑好久才能下笔,所以决定拆成两部分来发,以便阅读。这篇写得我心力交瘁,质量不算好,凑合着看吧。同样是写程序..._研发和开发

关于android双进程守护-后台持续定位功能+项目IM中写到自己的即时通讯_jobintentservice跨进程-程序员宅基地

文章浏览阅读1.6k次。1.关于进程守护无非就是6.0以下,6.0以上的高版本保活a.android中6.0以下的保护采用双线程守护即可是aidl (1)创建aidl文件 interface IServiceAidlInterface { String getServiceName(); } (2)创建本地service是LocalService类实现aid..._jobintentservice跨进程

FastGithub:github加速神器,解决github打不开、用户头像无法加载、releases无法上传下载、git-clone、git-pull、git-push失败等问题。_fastgithub 程序将自动关闭:系统已运行其它实例-程序员宅基地

文章浏览阅读657次。FastGithub:github加速神器,解决github打不开、用户头像无法加载、releases无法上传下载、git-clone、git-pull、git-push失败等问题。_fastgithub 程序将自动关闭:系统已运行其它实例

推荐文章

热门文章

相关标签