程序设计原则-单一职责原则

前言

软件开发设计中最大的难题就是应对需求的变化,而各种各样的需求变化又是不可预料的,我们要为这种不可预料的变化做好准备,这本身是一件十分痛苦的事情,通常涉及到功能的变更、扩展和删除等,所幸前辈们已经给我们提出了经典的六大设计原则23种设计模式来“封装”未来的变化。

在程序设计领域, SOLID(单一功能、开闭原则、里氏替换、接口隔离以及依赖反转)是由罗伯特·C·马丁在21世纪早期引入的记忆术首字母缩略字,指代了面向对象编程和面向对象设计的五个基本原则。六大设计原则中多了一个“迪米特法则”。

本文只针对六大设计原则的单一职责原则进行介绍。

六大设计原则和23种设计模式主要适用于面向对象的编程语言,而非面向过程语言,即C语言。熟练理解6大设计原则后,在面向过程语言中也能有一定的借鉴。

定义

在面向对象编程领域中,单一功能原则(Single responsibility principle)规定每个类都应该有一个单一的功能,并且该功能应该由这个类完全封装起来。所有它的(这个类的)服务都应该严密的和该功能平行(功能平行,意味着没有依赖)。单一职责原则又称单一功能原则,不要让一个类承担过多的职责。避免职责耦合在一起,避免一个职责的变化影响到其他职责。所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。

一个具体的例子就是,想象有一个用于编辑和打印报表的模块。这样的一个模块存在两个改变的原因。第一,报表的内容可以改变(编辑)。第二,报表的格式可以改变(打印)。这两方面的改变会因为完全不同的起因而发生:一个是本质的修改,一个是表面的修改。单一功能原则认为这两方面的问题事实上是两个分离的功能,因此他们应该分离在不同的类或者模块里。

原则

如果一个类或者模块承担的职责过多,就等于把这些职责耦合在一起了。一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当发生变化时,设计会遭受到意想不到的破坏。而如果想要避免这种现象的发生,就要尽可能的遵守单一职责原则。

比如功能1和功能2,功能1由于需求变更导致功能1模块需要调整,而调整后可能导致功能2原本正常的功能出现异常,这就表明功能1和功能2存在耦合

因此此原则的核心就是解耦增强内聚性,控制类的粒度大小(模块或函数功能的粒度大小)

C语言中可以理解为功能模块化、单一功能文件、单一功能函数等,如实现oled功能模块、由具体功能实现接口函数文件、硬件接口功能文件、配置文件和字体数据文件组成;同时每个文件中的每个函数只具备一个功能,如画点、画线、画圆,甚至细分到光标定位函数。

其实熟练的程序设计人员都清楚应该写出高内聚低耦合的程序,但是实际开发过程中很多耦合常常发生在不经意之间。

职责扩散:因为某种原因,某一职责被分化为颗粒度更细的多个职责了;比如光标定位函数过度地细分了多个函数进行实现

因此在实现中,也需要把握尺度,避免过度细分功能函数。

优点

功能单一后,复杂度降低,自然可读性增强

扩展性增强,针对某一个功能更加容易变更变更

引起的风险降低,由于功能单一,相互独立,因此功能更改基本不会影响其他功能

总结

从字面上理解不难。但是“看懂”和“会用”是两回事,而“用好”更是难上加难。从工作经历来看,很多朋友因为对这些原则理解得不够透彻,导致在使用的时候过于教条主义,拿原则当真理,生搬硬套,适得其反。

如何理解?

一个类或模块只负责完成一个职责或者功能。不要设计大而全的类或模块,要设计粒度小、功能单一的类或模块。但是,如果拆分得过细,实际上会适得其反,反倒会降低内聚性,也会影响代码的可维护性。单一职责原则是为了实现代码高内聚、低耦合,提高代码的复用性、可读性、可维护性

如何判断类的职责是否足够单一?

在不同的应用场景、不同阶段的需求背景、不同的业务层面,对同一个类的或模块职责是否单一,可能会有不同的判定结果。实际上,一些侧面的判断指标更具有指导意义和可执行性,比如,出现下面这些情况就有可能说明这类或模块的设计不满足单一职责原则:

类(模块)中的代码行数、函数或者变量过多(关联小);

类(模块)依赖的其他类(模块)过多,或者依赖类(模块)的其他类(模块)过多;

函数过多(可以再具体分类);

比较难给类(模块)起一个合适的名字;

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 2
收藏 2
关注 23
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧