软件设计七大原则

软件设计原则是设计模式的基石。目的只有一个,降低对象之间的耦合,增加程序的可复用性、可扩展性、可维护性。

开闭原则 OCP

定义:软件实体对扩展开放,对修改关闭。

  • 对扩展开发,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。

  • 对修改关闭,意味着类一旦设计完成,就可以独立的工作,而不要对其进行任何的修改。

在面向对象设计中,我们通常通过继承和多态来实现OCP,即封装不变部分。

比如需求要实现2种状态的业务。

  • 如果用if else来判断,那么后面加第三种状态,就还需要在此接口上增加else逻辑,不符合开闭原则。

  • 用策略类实现,则定义策略接口,策略A和策略B为具体实现类,分别对应两种状态。假如下一次需求要实现第三种状态,那么直接定义一个StrategyC实现类就可满足。原有代码不变,符合开闭原则。

详情可点击:策略模式文章

里氏替换原则 LSP

定义:程序中的父类型都可以正确的被子类型替换。

程序中的对象可以在不改变程序正确性的前提下被它的子类所替换,即子类可以替换任何基类能够出现的地方,并且经过替换后,代码还能正确工作。

根据LSP的定义,如果在程序中出现使用instanceof、强制类型转换或者函数覆盖,很可能意味着是对LSP的破坏。

假设定义一个抽象禽类,有一个飞翔方法fly(), 我们就可以自由的继承禽类衍生出各种鸟儿,并调用其飞翔方法。如果鸵鸟加入禽类行列,继承禽类,但不会飞,那么飞翔方法fly()就显得多余。而且在所有禽类出现的地方,无法用鸵鸟替换(此时不满足正确业务逻辑)。违反了里氏替换原则。

经过反思,是设计问题,禽类和飞翔无必然联系,所以禽类不应该定义飞翔方法fly(),把禽类飞翔方法fly()抽离出去单独定义飞翔接口Flyable。

对于有飞翔能力的鸟儿继承禽类并实现飞翔接口。鸵鸟继承禽类,但不实现飞翔接口,是否是鸟儿取决于是否继承自禽类,能不能飞取决于是否实现飞翔接口。所有禽类出现的地方都可以用子类进行替换,所有飞翔接口出现的地方都可以被其替换为实现。

依赖倒置原则 DIP

定义:模块之间交互应该依赖抽象,而非实现。

DIP要求高层模块不应该依赖于底层模块,二者都应该依赖于抽象。抽象不应该依赖细节,细节应该依赖抽象。

比如某个人喂养小动物,如果依赖了具体的实现,则每新增一个动物,需要在Person内加一个对应的方法。违背了开闭原则,也不符合依赖倒置原则。

重新修改后,如下。新增一个Birds抽象类,具体的动物继承自父类Birds,Person中的方法参数依赖于抽象,而不是具体的实现。符合依赖倒置原则。

单一职责原则 SRP

定义:对任何类的修改只能有一个原因。换句话说,一个类只应该负责一项职责。

SRP要求每个软件模块职责要单一,衡量标准是模块是否只有一个被修改的原因。职责越单一,被修改的原因就越少,模块的内聚性就越高,被复用的可能性就越大,也更容易被理解。

举例员工类 Employee,开发工作变了,需要修改Employee类,测试工作变了需要修改Employee类,不符合单一职责原则,类的复杂性也高。

  • 职责多,引起此类变化的原因也多。后续变更的风险就大。

  • 后续需求变更,会造成职责的混乱,类结构的不稳定。

改造后,类的职责单一。开发者的职责就是“写代码”,那么对其进行的修改只有与“写代码”相关的一个原因(画类图也是为了指导代码落地),这样才能确保类职责的单一性原则。

同时,类与类之间虽有着明确的职责划分,但又一起合作完成任务,它们保持着一种“对立且统一”的辩证关系。

  • 以责任链模式为例,每个处理者类职责清晰,只处理与自己职责相关的业务。

  • 以员工类为例,拆分后,各个员工完成相应的职责,共同保障项目上线。

这种清晰的职责范围划分就是单一职责原则的最佳实践。符合单一职责原则的设计能使类具备高内聚性,让单个模块变得简单易懂,如此才能增强代码的可读性和可复用性。并提高系统的易维护性和易测试性。

上面的例子是类职责单一,那么微服务划分也同理,采用单一职责原则,每个服务负责一块业务。同一类业务的变更落在单个服务内变更

接口隔离原则 ISP

定义:客户端对类的依赖基于最小接口,而不依赖不需要的接口。

接口隔离原则认为不能强迫用户去依赖那些他们不使用的接口。换句话说,使用多个专门的接口比使用单一的总接口要好。做接口拆分时,也要尽量满足单一职责原则。将外部依赖减到最少,降低模块间的耦合。

比如类A只需要使用方法1、方法3,类B只需要使用方法2、方法4,但在源代码层次上与所有方法形成依赖关系。这种依赖意味着我们对接口I的方法2修改,即使不会影响A所依赖的方法1、方法3的功能,也会导致它需要重新部署和编译。

改造后,类A不需要用到方法2、方法4,就可以选择不依赖它们。代码更加清晰,接口职责更加明确。

迪米特法则 LOD

定义:一个类对于其它类知道的越少越好。

迪米特法则也被称为最少知识原则,它提出一个模块对其他模块应该知之甚少,或者说模块之间应该彼此保持陌生,甚至意识不到对方的存在,以此最小化、简单化模块间的通信,并达到松耦合的目的。

反之,模块之间若存在过多的关联,那么一个很小的变动则可能会引发蝴蝶效应般的连锁反应,最终会波及大范围的系统变动。我们说,缺乏良好封装性的系统模块是违反迪米特法则的,牵一发动全身的设计使系统的扩展与维护变的举步维艰。

门面模式和中介者模式迪米特法则极好的范例。 Tomcat中 RequestFacade类就使用了外观模式。RequestFacade是对Request类封装,屏蔽内部属性和方法,避免暴露。

合成复用原则 CRP

定义:优先使用合成/聚合,而不是类继承。

比如对象的继承关系是在编译时就定义好了,所以无法在运行时改变从父类继承的实现。子类的实现与它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。当你需要复用子类时,如果继承下来的实现不适合解决新的问题,则父类必须重写或被其它更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。

合成(组合)和聚合都是关联的特殊种类。

  • 聚合表示一种弱的拥有关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分;

  • 合成则是一种强大的“拥有”关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样。

合成/聚合复用原则好处:优先使用对象的合成/聚合将有助于你保持每个类被封装,并被集中在单个任务上。这样类和类继承层次会保持较小规模。

举例:手机软件划分可分为QQ、微信等,按品牌划分可分为华为、小米等。如果同时考虑这两种分类,其组合就很多。往下继续扩展软件、手机品牌,都会新增许多子类。违背了开闭原则,也限制了复用性。

用聚合关系实现的类图:后面新增软件,手机品牌类不用变更代码。继承的层次也少了。

参考资料

  1. 刘韬:《秒懂设计模式》

  2. 张建飞:《代码精进之路:从码农到工匠》

  3. Robert C. Martin:《架构整洁之道》

  4. 程杰:《大话设计模式》

关注公众号,后台回复【笔记】获取技术笔记PDF。

深度总结:软件设计七大原则相关推荐

  1. 【学习笔记】慕课网—Java设计模式精讲 第3章 软件设计七大原则-3-6 迪米特原则(最少知道原则)...

    /** * 软件设计七大原则-迪米特原则 学习笔记 * @author cnRicky * @date 2018.11.10 */ 迪米特原则(最少知道原则) 一个对象应该对其他对象保持最少的了解.又 ...

  2. 设计模式-软件设计七大原则

    目录 综述 1.开闭原则 1.1开闭原则的定义 1.2开闭原则的作用 1.3开闭原则的实现方法 2.里氏替换原则 2.1里氏替换原则的定义 2.2里氏替换原则的作用 2.3里氏替换原则的实现方法 3. ...

  3. 【设计模式】软件设计七大原则

    做好自己 软件设计七大原则 开闭原则OCP(Open-Closed Principle) 依赖倒转原则DIP(Dependence Inversion Principle) 单一职责原则SRP(Sin ...

  4. 【设计模式】软件设计七大原则 ( 接口隔离原则 | 代码示例 )

    文章目录 一.接口隔离原则简介 二.接口隔离原则代码示例 ( 反面示例 ) 1.接口定义 ( 接口臃肿 ) 2.实现类 1 3.实现类 2 三.接口隔离原则代码示例 ( 推荐用法 ) 1.接口 1 2 ...

  5. 软件设计七大原则和设计模式

    七大原则 开闭原则 依赖倒置原则 单一职能原则 接口隔离原则 迪米特法则 里氏替换原则 合成复用原则 设计模式 简单工厂 工厂方法模式 抽象工厂模式 建造者模式 单例模式 原型模式 外观模式 装饰者模 ...

  6. 【设计模式】软件设计七大原则 ( 开闭原则 )

    文章目录 一.开闭原则简介 二.开闭原则代码示例 1.商品接口 2.普通商品类 3.折扣商品类 4.测试类 一.开闭原则简介 开闭原则 : 定义 : 一个 软件实体 , 类 / 模块 / 函数 , 对 ...

  7. 软件设计七大原则实战(二)-开闭原则

    1  开闭原则的定义 开闭原则是Java世界里最基础的设计原则,它指导我们如何建立一个稳定的.灵活的系统,先来看开闭原则的定义: Software entities like classes,modu ...

  8. 【设计模式】软件设计七大原则 ( 里氏替换原则 | 定义 | 定义扩展 | 引申 | 意义 | 优点 )

    文章目录 一.里氏替换原则定义 二.里氏替换原则定义扩展 三.里氏替换原则引申意义 四.里氏替换原则意义 五.里氏替换原则优点 一.里氏替换原则定义 里氏替换原则定义 : 如果 对每一个 类型为 T1 ...

  9. 【设计模式】软件设计七大原则 ( 单一职责原则 | 代码示例 )

    文章目录 一.单一职责原则简介 二.单一职责原则代码示例 ( 反面示例 ) 1.不遵循单一职责原则的类 2.测试类 三.单一职责原则代码示例 ( 正面示例 | 类的单一职责 ) 1.用翅膀飞的鸟 2. ...

  10. 软件设计七大原则:(四)接口隔离原则

    一.接口隔离原则简介 用多个专门的接口,而不再使用单一的总接口,客户端不应该依赖它 不需要的接口. 一个类对一个类的依赖应该建立在最小的接口上. 建立单一接口,不要建立庞大臃肿的接口. 尽量细化接口, ...

最新文章

  1. Umbra 3:次世代的遮挡裁剪
  2. 字符串比较--小问题大智慧
  3. 提高CocoaPods速度
  4. torch.nn.BCELoss are unsafe to autocast
  5. ant design select 坑总结
  6. 1.3计算机的性能指标
  7. Boost:使用/type <>语法测试功能对象
  8. HDU_2795 Billboard(线段树)
  9. 如何做到长时间(4 个小时以上)精神专注?
  10. 剑指offer第12题打印从1到n位数以及大整数加法乘法
  11. 树莓派 神经网络植入_使用自动编码器和TensorFlow进行神经植入
  12. 鸟哥的 Linux 私房菜7 -- 首次开机关机与基本指令执行
  13. ODPS技术架构及应用实践
  14. Loading动画加载素材模板,UI设计师好帮手
  15. 2021想学UI设计,你必需要知道这些
  16. 当归饮(茶):治疗血虚
  17. 5.23低版本到高版本问题
  18. 基于python的第三方库Pyautogui实现程序自动控制鼠标与键盘
  19. 输入12V-48V输出5V-12V电流:2A
  20. Android手机管理工具类

热门文章

  1. 使用LOIC 对新搭建的网站迚行DDOS攻击
  2. 运行Arcgis和SWAT模型遇到Error Number 91和Error Number -2147467259报错怎么办?
  3. dosbox详细安装级及使用
  4. 手机输入法带拼音声调_这些神奇的拼音输入法,你都知道几个?
  5. app抓包工具_【旧版IPA抓包教程2】超便捷苹果旧版本APP抓包/轻松抓取你想要的版本,旧版app任意下载...
  6. 测试金士顿固态硬盘软件,金士顿固态硬盘管理工具(Kingston SSD Manager)
  7. 园林景观设计计算机制图,园林景观设计平面图效果图
  8. Fences报错,explorer.exe未正确关闭问题
  9. B2B2C多用户商城系统源码 Java商城源码
  10. JSONP解决前端跨域问题