除了重复的代码编译,违反SRP还会带来以下2个常见的问题:
1、代码冲突 。程序员A修改了模块的A功能,而程序员B在不知情的情况下也在修改该模块的B功能(因为A功能和B功能面向不同的用户,完全可能由2位不同的程序员来维护),当他们同时提交修改时,代码冲突就会发生(修改了同一个源文件) 。
2、A功能的修改影响了B功能 。如果A功能和B功能都使用了模块里的一个公共函数C,现在A功能有新的需求需要修改函数C,那么如果修改人没有考虑到B功能,那么B功能的原有逻辑就会受到影响 。
由此可见,违反SRP会导致软件的可维护性变得极差 。但是,我们也不能盲目地进行模块拆分,这样会导致代码过于碎片化,同样也会提升软件的复杂性 。比如,在前面的例子中,我们就没有必要再对服务管理模块进行拆分为服务注册模块、服务更新模块和服务去注册模块,一是因为它们面向的用户是一致的;二是在可预见的未来它们要么同时变化,要么都不变 。
因此,我们可以得出这样的结论:
如果一个模块面向的都是同一类用户(变化原因一致),那么就没必要进行拆分 。如果缺乏用户归类的判断,那么最好的拆分时机是变化发生时 。
SRP是聚合和拆分的一个平衡,太过聚合会导致牵一发动全身,拆分过细又会提升复杂性 。要从用户的视角来把握拆分的度,把面向不同用户的功能拆分开 。如果实在无法判断/预测,那就等变化发生时再拆分,避免过度的设计 。
OCP:开闭原则
开闭原则(The Open-Close,OCP)中,“开”指的是对扩展开放,“闭”指的是对修改封闭,它的完整解释为:
Abe open forbutfor .
通俗地讲就是,一个软件系统应该具备良好的可扩展性,新增功能应当通过扩展的方式实现,而不是在已有的代码基础上修改 。
然而,从字面意思上看,OCP貌似又是自相矛盾的:想要给一个模块新增功能,但是又不能修改它 。
*如何才能打破这个困境呢?*关键是抽象!优秀的软件系统总是建立在良好的抽象的基础上,抽象化可以降低软件系统的复杂性 。
*那么什么是抽象呢?*抽象不仅存在于软件领域,在我们的生活中也随处可见 。下面以《语言学的邀请》中的一个例子来解释抽象的含义:
假设某农庄有一头叫“阿花”的母牛,那么:
1、当把它称为“阿花”时,我们看到的是它独一无二的一些特征:身上有很多斑点花纹、额头上还有一个闪电形状的伤疤 。
2、当把它称为母牛时,我们忽略了它的独有特征,看到的是它与母牛“阿黑”,母牛“阿黄”的共同点:是一头牛、雌性的 。
3、当把它称为家畜时,我们又忽略了它作为母牛的特征,而是看到了它和猪、鸡、羊一样的特点:是一个动物,在农庄里圈养 。
4、当把它称为农庄财产时,我们只关注了它和农庄上其他可售对象的共同点:可以卖钱、转让 。
从“阿花”,到母牛,到家畜,再到农庄财产,这就是一个不断抽象化的过程 。
从上述例子中,我们可以得出这样的结论:
文章插图
抽象就是不断忽略细节,找到事物间共同点的过程 。抽象是分层的,抽象层次越高,细节也就越少 。
再回到软件领域,我们也可以把上述的例子类比到数据库上,数据库的抽象层次从低至高可以是这样的:MySQL 8.0版本 -> MySQL -> 关系型数据库 -> 数据库 。现在假设有一个需求,需要业务模块将业务数据保存到数据库上,那么就有以下几种设计方案:
- librosa库 【NLP】音频特征工程(1)
- 亚运会的简单介绍 亚运会几年一次
- AQS源码分析 ---- 1
- 【苹果推送】推信?具体流程和安装教程
- 芈月传小说作者是谁 芈月传小说原著
- 无代码开发平台的设计与实现
- xr防水吗 xr是什么意思
- 【PET材料的生产设备】——导电滑环应用实例,厂家讲解
- AI模拟人脑新突破:新型人造突触研究已公布
- 【论文笔记】ICRA2019 视觉里程计的损失函数:Beyond Photome