![](https://www.qzq.world/wp-content/uploads/2024/12/image-24.png)
定义
这个原则还是挺简单易懂的,就是一个类应该只负责具体的一项工作。那完成计时也是工作,完成AI模型训练也是工作,工作大小如何界定?
单一职责原则的原话是:
一个类应该有且只有一个变化的原因。
为什么将不同的职责分离到单独的类中是如此的重要呢?
因为每一个职责都是一个变化的中心。当需求变化时,这个变化将通过更改职责相关的类来体现。
如果一个类拥有多于一个的职责,则这些职责就耦合到在了一起,那么就会有多于一个原因来导致这个类的变化。对于某一职责的更改可能会损害类满足其他耦合职责的能力。这样职责的耦合会导致设计的脆弱,以至于当职责发生更改时产生无法预期的破坏。
案例理解
我们设计一个矩形类,这个矩形类有两个职能,一是计算面积,二是生成矩形图形并且绘制到窗口中。
class Rectangle:
def __init__(self, width, height):
# 一个简单的矩形类,拥有长和高
self.width = width
self.height = height
def area(self):
return self.width * self.height
def draw(self):
import cv2
import numpy as np
# 这里调用python-opencv库为我们绘制矩形,用法就不介绍了
img = np.zeros((512, 512, 3), np.uint8)
cv2.rectangle(img, (0, 0), (self.width, self.height), (0, 0, 255))
cv2.imshow("image", img)
cv2.waitKey(0)
emm,由于我们用的是python,所以其实很多之前的编程语言要考虑的问题,我们其实不需要太担心。
比如:
我们必须在计算几何应用中包含对 GUI 库的引用。这导致应用程序无谓的消耗了链接时间、编译时间、内存空间和存储空间等。
python是动态语言,所有的代码都经过翻译后交给解释器来直接运行。之前这项原则考虑的是:“如果有一个用户用不到绘制图形的函数,那么事先要求该用户准备有关图形显示的环境会引起资源的老费”。这在我们这个案例的函数中是这两行:
import cv2
import numpy as np
然而,由于python的特性,你如果并不使用draw
函数,那么这两个库根本不会进行导入操作(因为我们把导入库的语句写到了函数里),且你的环境中没有这个包也不会报错!
当然,如果你将这两句导入语言写到文件头部那自然该报错还是会报错,而且这种写法更常见。
话题有点偏了,回来看看一般会造成什么样的问题:
- 代码难以理解与维护:由于
Rectangle
类包含了多种不相关的职责,其他开发者在阅读或修改代码时可能会感到困惑,难以快速定位问题。 - 高耦合度:不同的职责之间可能存在紧密的联系,一旦某个职责的实现发生变化,就可能影响到其他职责。(本例中,所有的函数都需要调用类的自身属性,即
self.width
,self.height
,扩写很可能会产生属性冲突之类的问题) - 难以复用:由于功能混杂,
Rectangle
类很难被其他系统或模块重用。 - 扩展性差:当需要添加新的功能时,由于类的职责已经过多,可能不得不继续在这个类中增加方法,导致类变得更加庞大和复杂。
解决办法自然是将我们的Rectangle
类分开,一个专注于数学运算成为“几何矩形”,另一个就专注实现图像显示即可。当然,由于“几何矩形”是非常精简的,可以考虑让“几何矩形”成为基类,代码就会成为下面这样:
class GeometricRectangle:
def __init__(self, width, height):
# 一个简单的矩形类,拥有长和高
self.width = width
self.height = height
def area(self):
return self.width * self.height
class GraphicRectangle(GeometricRectangle):
def __init__(self, width, height):
# 一个简单的矩形类,拥有长和高
super().__init__(width, height)
def draw(self):
import cv2
import numpy as np
# 这里调用python-opencv库为我们绘制矩形,用法就不介绍了
img = np.zeros((512, 512, 3), np.uint8)
cv2.rectangle(img, (0, 0), (self.width, self.height), (0, 0, 255))
cv2.imshow("image", img)
cv2.waitKey(0)
这样耦合就解开了,如果我们之后有什么应用需要调用几何矩形,就可以尽管使用这个较为简洁的几何矩形类,而不用考虑额外的环境配置和类方法间的影响了。
参考
单一职责原则(Single Responsibility Principle) - sangmado - 博客园
为什么强调单一职责,为什么那么多人都习惯违反这一职责? - 知乎
文章评论