30-2 之软件架构设计原则 1 - SRP 单一职责原则

软件架构设计原则 1 - SRP 单一职责原则

在软件设计有个 『 SOLID 原则 』的几个原则,它是由 5 个原则所组成,而这 5 个原则所想要达的的事情为以下两点 :

  • 低耦合
  • 高内聚

接下来这篇文章我们将要谈谈第一个原则 SRP 单一职责原则

SRP ( Single-Responsibility Principle ) 是什麽呢 ?

SRP 单一职责原则,最一开始是由一位叫 Robert Cecil Martin 在他的 《敏捷软件开发,原则,模式和实践》一书中所提到的『 物件导向设计原则 』

一个 『 类别 』只对一个『 原因 』引起变化 ( A class should have only one reason to change )

然後这位作者在之後出版的一本书《 Clean Architecture 》又将定义修改成如下 :

一个 『 类别 』只有一个『 角色 』引起『 变化 』

那这一个『 角色 』指的是什麽呢 ? 而 『 变化 』 又是什麽呢 ? 我这里自已的想法为 :

『 角色 』代表这个类别的使用者 ( 想成实体化後执行方法的地方 ),而『 变化 』代表『 因为这角色某个需求,而需要去修改程序码。

上面这句话,我们接下来用下面的范例,来简单说明。

范例 - 订单计算直播人数

假设我们有个类别,计算直播的观看数,就是简单的去资料库拿资料 ( 这只是范例,我知道有些情况不适合去 DB 拿这个数字 )。

// Bad SRP
class LiveViewCountCalculator{
    constructor(){
        // 假设每个笔单只有一种类型的产品
    }

    calcFee(){
        let viewCount = 0
        viewCount = await _getViewCountFromDB()
        return viewCount
    }
}

然後目前会使用这个方法的两种角色『 前台给观众看 』、『 後台给直播主、工作人陨看 』,在需求没有变动的情况下没什麽问题。

但如果这时前台给观众看的决定灌水怎麽办呢 ?

如果这时改了,『 就同时会影响到後台给直播主看的实际数字 』,所以如果修改成如下会比较好点,根据『 角色 』来拆,这样一个角色的改变,就不会影响到另一个角色。

// Good SRP

class AdminLiveViewCountCalculator{
    calcFee(){
        let viewCount = 0
        viewCount = await _getViewCountFromDB()
        return viewCount
    }
}

class GeneralLiveViewCountCalculator{
    calcFee(){
        let viewCount = 0
        viewCount = await _getViewCountFromDB()
        return viewCount * 2
    }
}

那是不是一切都要『 根据角色 』切分呢 ?

事实上是不一定,在《敏捷软件开发,原则,模式和实践》里有提到 :

If the application changes in ways that affect the signature of the connection functions, then the design will smell of Rigidity... In that case the two responsibilities should be separated. If, on the other hand, the application is not changing in ways that cause the two responsibilities to change at different times, then there is no need to separate them.

这个是我自已的理解的想法,如果每一次的改动对不同的角色事实上都是连动的,那就没必要拆开,而如果是一个角色动,会影响到另一个角色使用,则拆。

小总结

SRP 单一职则原则,虽然定义上为如下,但事实上我觉得还有很多东西也适合这个原则。

一个 『 类别 』只有一个『 角色 』引起『 变化 』

像是在《 架构师的自我修链中 》有提到建议一个实践 :

一个 class or function 打开来以後,不要超过一个萤幕

我觉得这是个不错的建议,毕竟一个太长的 class 或 function 虽然不能说是一定,但基本上就有一定等级的坏味道,可以考虑往不同角色用他的情况,会不会世界炸掉。

下面这一段是我最近从某个 youtbue 上看到的学到的方法,也就是每一次学习完,问这三个问题,就可以加深记忆,对我这种老人脑袋 ~ 希望有点帮助

这个知识点可以用来解释什麽现象

  • 我觉得分层架构的出现,事实上也符合 SRP 原则,都是为了达到高内聚与代耦合
  • 记得我有一次在改一个 function ,结果其它地方也有使用到他结果导致世界炸掉。

这个知识点可以和以前的什麽知识连结呢 ?

记忆中和 clear code 这本书中有提到,一个方法只做一件事情,这点我觉得也算是 SRP 原则

我要如何运用这个知识点 ?

  • 每一次在开发一个方法或类别时,记得要想像使用它的角色,会不会和其它地方打架
  • 假设一个叫 Get 的方法中,不要在加什麽 Update 或 Set 啥的会改变的东西
  • 一个类别只做自已分内的事情,例如购物车类型,不要处理付款与订单相关的东西
  • 一个方法名为 getXXX 时就别偷偷的再里面进行状态改变。

参考资料


<<:  CSS Position

>>:  [Day 2]我也好想要有监定技能(後端篇)

冒险村12 - rescue exception

12 - rescue exception 异常处理在开发过程中时常可见,举例来说 Rails 中找...

组策略和登录档监控--gpedit.msc及Process Monitor

今天预计要来介绍两支程序,让编辑登录档稍微安全的组策略编辑器(gpedit.msc)跟监控系统大小变...

韩乡韩国料理 #韩式小菜吃到饱

这是我第一次去韩乡,也是唯一的一次。 上图是「韩式起司辣鸡」。韩乡的料理还不错,价位介於200元上下...

透过数位逻辑电路学习 Bitwise 操作

本文目标 学习基础的数位逻辑概念 认识撰写系统软件常用的 Bitwise 技巧 位移操作 认识多工器...

蓝牙小知识

名称的由来 Bluetooth是斯堪地那维亚语言的Blåtand/Blåtann 借10世纪丹麦和...