设计模式的六大原则

单一职责原则:

定义:不要存在多于一个导致类变更的原因。

通俗地说:一个类只负责一项职责。

问题来源:一个类T负责两个职责:职责1和职责2,当因为职责1因需求变化时,可能会导致职责2的功能发生故障。

解决方案:遵循单一职责原则,分别建立两个类:T1负责职责1,T2负责职责2。这样当因需求修改类时就不会导致别的功能出现异常。

看似简单但实际上因为开发时间的不同,或者是业务需求的变化可能会导致本来符合单一职责原则的类变得不符合这一原则。

所以涉及到开发或模块涉及时尽量将业务逻辑简单化,细分化。这样出现问题的时候,在做添加的时候,可以避免耦合过高影响其他功能的情况出现。

优点:

  • 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;
  • 提高类的可读性,提高系统的可维护性;
  • 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。

需要说明的一点是单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则。

里氏替换原则:

定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。

(这个定义,我表示。。。。。。。。)

定义2:所有引用基类的地方必须能透明地使用其子类的对象。

定义3:子类型必须能够替换掉它们的父类型。

大众点的感觉:子类可以扩展父类的功能,但是不能改变父类的功能。(如果改变了父类的功能,会导致子类无法替换父类,导致引用出现异常)。

个人理解的话,更像是因为假如子类篡改了父类的功能,会导致在多态的时候父类无法成功地指向子类最终引起程序的功能瘫痪。

里氏替换原则是开闭原则的补充,实现开闭原则的关键就是抽象化,而基类与子类的继承关系就是抽象化的具体体现。里氏原则是对实现抽象化的具体规范。

在进行设计时,我们应该尽量从抽象类继承,而不是从具体类继承。如果从继承树上来看,所有的叶子节点都应该是具体类,而所有的树枝节点应该是抽象类或者接口。

感觉里氏替换原则在框架中非常常见,看过Spring的一点源码跟源码解析,其中Spring容器的继承树就非常符合里氏替换原则(当然也很符合其他的设计原则,比如单一功能原则之类的)。

依赖倒置原则:

定义:高层模块不应该依赖低层模块。两个都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象;(针对接口编程,而不是针对实现;)

我感觉这个好像没什么需要太分析的吧?

抽象(接口)应该是一切模块的依赖起源。具体的实现(细节),应该依赖于接口(抽象)而存在。

通过抽象来规范业务方向,然后通过细节来实现抽象,当实际需求发生变化的时候,可以直接修改细节来实现而不需要对抽象进行修改(当然你的抽象得考虑周全,不过也可以利用接口的多实现来弥补这个问题。果然规则制定者是最厉害的啊)。

接口隔离原则/合成聚合原则:

定义:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。 

个人感觉这就像是避免出现规模庞大的接口,可以将复杂的功能分散到多个接口中,最终通过多实现了灵活性与复用性。

(假如你们源接口功能庞大,你要实现的功能位于其中,但是你只是想实现其部分功能,那多余的功能对于你来说是不是像鸡肋一样,不可不实现,但是实现了也是空白。食之无味,弃之可惜啊)

注意情况:

  • 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
  • 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
  • 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。

感觉这些设计模式的原则,不仅仅是对设计模式有用,实际对于项目的开发也很有用,如果项目开发时能遵循这些原则,那么后续维护和升级就会相对简单很多。或者说代码的可读性什么的都能得到很好的继承和维护。但是一旦你设计出了问题,在后续的开发过程中可能需要你用别的方法来解决,最终导致出现莫名其妙的bug,导致后期维护难度增大。

果然应该多看多想,形成思路之后再往后走。

迪米特法则:

定义1:一个对象应该对其他对象保持最少的了解。

定义2:如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用,如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。

核心思想是:类之间的松耦合(不管对于什么项目来说,你中有我我中有你都不是一个很好的现象。也是这几个原则看到现在的感受,无时无刻不在提示,不要造成相互纠缠,或者说降低耦合性)。

实质是尽量避免出现类作为成员变量存在。(感觉这样又有点跟面向接口编程有冲突,不过应该不算冲突的意思吧。反正目前在我看来是有点这么个意思)。

开闭原则:

定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

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

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

这样做,面对需求变化,通过扩展来实现新需求,可以使整个程序从第一个版本开始就有很好的功能性(第一版设计完成实现之后就能满足其业务需要)跟拓展性(面对新需求新需要,可以通过拓展功能来实现。)

(但是根据上面括号的内容想来,程序的体谅会越来越大越来越难以维护,就目前看我感觉这是所有程序的最终宿命)。

上述就是六大原则跟我对这些原则的理解。鉴于学习过程的局限性,或者说知识体系的局限性,可能还有很多问题。如果有朋友看到可以放心大胆地指出。

我很欢迎批评,也很乐于接受批评,也很愿意跟各位在交流中相互学习。

期待你的到来

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏我就是马云飞

设计模式二十四章经之六大设计原则

1242
来自专栏phodal

五个简单的原则,带你写出整洁代码

每个人都有自己对于代码的看法,有自己的偏好。对于我来说,也是如此。作为一个实用主义者,我遵循的东西,比较少,也比较简单。多了,记不住,也不实用。

481
来自专栏Golang语言社区

行为树behavior3go介绍

在游戏开发中,以状态切换来驱动其执行流程的系统,引入行为树可以大大简化编码和配置。

743
来自专栏小程序·云开发专栏

你不知道的Node.js性能优化

仅仅是简单的升级 Node.js 版本就可以轻松地获得性能提升,因为几乎任何新版本的 Node.js 都会比老版本性能更好,为什么?

7.4K4
来自专栏领域驱动设计DDD实战进阶

微服务实战(九):落地微服务架构到直销系统(回顾总结)

这个系列我们大概写了八篇文章,将微服务的最重要的内容过了一遍。当然其中有些内容还没有涉及到,比如Docker(不是微服务架构风格中必须的)等,关于Docker我...

781
来自专栏牛客网

知识总结:java的web开发常用框架

今年我一直在思考web开发里的前后端分离的问题,到了现在也颇有点心得了,随着这个问题的深入,再加以现在公司很多web项目的控制层的技术框架由struts2迁移到...

37313
来自专栏java一日一条

为什么做java的web开发我们会使用struts2,springMVC和spring这样的框架?

今年我一直在思考web开发里的前后端分离的问题,到了现在也颇有点心得了,随着这个问题的深入,再加以现在公司很多web项目的控制层的技术框架由struts2迁移到...

901
来自专栏Python

操作系统简介

一 为什么要有操作系统 现代计算机系统是一个复杂的系统,程序员无法把所有的硬件操作细节都了解到,管理这些硬件并且加以优化使用是非常繁琐的工作,为了将程序员就从这...

1847
来自专栏喔家ArchiSelf

IoT设备的自我测试

东西坏了,事情也出了差错。 简单的说就是 XX发生了。 不管用什么词,事实上我们都生活在一个不完美的世界里。 在嵌入式系统中,有很多失败的可能。 在简单的系统中...

863
来自专栏老九学堂

【方法】Java语言学习六点要点

学习的目的是为了将来进行应用程序的开发,而不是进行语言理论研究 ;将来的应用开发是在成熟的平台上展开,而不是自己从底层开发平台 。 ? 一、掌握静态方法和属性 ...

2904

扫码关注云+社区