软件设计原则之单一职责原则、开闭原则

系列文章目录

软件设计原则之单一职责原则、开闭原则
软件设计原则之里氏替换原则、依赖倒置原则
软件设计原则之接口隔离原则、合成复用原则、迪米特原则


文章目录

  • 系列文章目录
  • 前言
  • 一、单一职责原则
    • 什么是单一职责原则(What)
    • 为什么使用单一职责原则(Why)
    • 如何使用单一职责原则(How)
  • 二、开闭原则
    • 什么是开闭原则(What)
    • 为什么使用开闭原则(Why)
    • 如何使用开闭原则(How)


前言

面向对象设计原则是评价每个设计模式应用效果的重要依据。几乎每个设计模式都符合一个或多个面向对象设计原则(个别模式除外),这些原则都是从无数项目中提取出来的经验性原则,它们为消除软件设计和实现中的“臭味(Bad Smell)”而诞生,力图为当前系统提供最好的设计方案。简单来说,设计原则是描述“面向对象开发”需要注意的代码原则。
用武侠小说的话来说,如果把设计模式比作剑法招式,那设计模式就是内功心法,而心法就像“道”,关键在于“悟”。怎么“悟”呢,还是要考虑程序员的功力。设计原则只是一把量尺、准则,但怎么用,还要结合具体的业务、场景,不能一概而论。必要的时候,甚至需要违背某些设计原则来进行编程。
下面是我自己的一些学习笔记,有些语句摘自刘伟老师的《设计模式的艺术》一书,这是一本很优秀的书籍,感谢刘伟老师。


一、单一职责原则

什么是单一职责原则(What)

单一职责原则,SRP,Single Responsibility Principle
定义:不要存在多于一个导致类变更的原因。
定义补充:一个类、接口、方法,都只负责一项职责。

为什么使用单一职责原则(Why)

  • 降低复杂度
  • 提高可读性
  • 提高可维护性
  • 降低变更引起的分险

如果一个对象承担了太多的职责,会出现以下问题:

  • 承担的职责越多,被复用的可能性越小
  • 承担的职责过多,就相当于将这些职责耦合在一起,当其中一个职责变化时,可能会影响其他职责的运作
  • 当客户端需要该对象的某一个职责时,不得不将其他不需要的职责全都包含进来,从而造成冗余代码或代码的浪费,也违背了【接口隔离原则】

如何使用单一职责原则(How)

单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离,这需要设计人员具有较强的分析设计能力和相关实践经验。
“职责”这个词,其实是没有衡量标准的,具体粒度大小,其实在不同业务场景、不同开发人员看来,都是不一样的。
在实际开发中,建议的做法,一开始可以先不不用过分考虑;而当类太大、方法太长的时候,再使用该原则进行重构。
这个原则可以用于类、接口、方法、模块。


“一个方法,只做一件事情” ,这句话的其中一个理解,是 方法体的代码的实现 只做 方法名的名字的定义 的事情。譬如:
setX() 方法,就只对 x 这个属性进行进行赋值,这种方法,一般是系统生成的。但如果对这个方法进行重定义了,比如增加了持久化的操作,把 x 的值保存到 数据库 或者 SharePreference/NSUserDefaults 中,就是违背了【单一职责原则】。
解决办法如下:
方法1:可以分割为两个方法,一个只修改 x 属性的值,另一个进行持久化操作,从而保证每个方法的单一职责;
方法2:修改方法名,比如改为 updateX() , 从而扩大方法的职责。—— 这里就体现了 职责 的 粒度 其实是可变的,在不同业务情况下,可以灵活处理。

二、开闭原则

什么是开闭原则(What)

开闭原则,OCP,Open Close Principle
定义:一个软件实体——如类、模块和函数——应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
定义补充:用抽象构建框架,用实现扩展细节。
核心思想:拥抱变化;面向抽象编程;解耦。

为什么使用开闭原则(Why)

任何软件都需要面临一个很重要的问题,即它们的需求会随时间的推移而发生变化。当软件系统需要面对新的需求时,应该尽量保证系统的设计框架是稳定的。如果一个软件设计符合开闭原则,那么可以非常方便地对系统进行扩展,而且在扩展时无须修改现有代码,使得软件系统在拥有适应性和灵活性的同时具备较好的稳定性和延续性。随着软件规模越来越大,软件寿命越来越长,软件维护成本越来越高,设计满足开闭原则的软件系统也变得越来越重要。
开闭原则是衡量每个设计模式优缺点的重要评价依据,是面向对象的可复用设计的第一块基石,是最重要的面向对象设计原则。
使用开闭原则有利于提高软件系统的可复用性、可维护性,实现稳定、灵活的系统架构。

如何使用开闭原则(How)

如何“用抽象构建框架,用实现扩展细节”
为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键。在Java、C#等编程语言中,可以为系统定义一个相对稳定的抽象层,而将不同的实现行为移至具体的实现层中完成。在很多面向对象编程语言中都提供了接口、抽象类等机制,可以通过它们定义系统的抽象层,再通过具体类来进行扩展。如果需要修改系统的行为,无须对抽象层进行任何改动,只需要增加新的具体类来实现新的业务功能即可,实现在不修改已有代码的基础上扩展系统的功能,达到开闭原则的要求。


如何通过开闭原则实现“向下兼容,平滑升级”
对于枚举:不建议在已有枚举的数值中插入新的值,而是在已有枚举的数值后追加新的值。
对于函数:不要修改原来函数的参数和返回值,但可以增加重载方法(语法上,不能单独重载返回值!)。
对于类1-原有类:不要修改类原有的属性和方法,但可以在原来的类中增加新的属性和方法。
对于类2-派生:不要修改原有类的原有属性和方法,但可以通过派生子类的方式来增加新的属性和方法;
对于模块:不要修改对外暴露的头文件定义的属性和方法,但可以增加。
对于后端接口:不要修改原来的参数,但可以增加参数。


参考书籍

[1] 设计模式的艺术 作者:刘伟

你可能感兴趣的:(软件设计,设计原则)