设计模式的六大原则

单一职责原则:

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

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

问题来源:一个类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 条评论
登录 后参与评论

相关文章

来自专栏小巫技术博客

代码Review的一些事

793
来自专栏技术博客

设计模式原则(单一、开放封闭、里氏代换、依赖倒转、迪米特法则五大原则)

        如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力,当变化发生时,设计会遭受到意想不...

742
来自专栏精讲JAVA

Gof设计模式之建造者模式(二)

建造模式属于创建性模式,它就是将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部...

1938
来自专栏令仔很忙

软件工程---软件需求分析

   需求分析是软件定义时期的最后一个阶段,它的基本任务是准确回答“系统必须做什么?”

642
来自专栏Albert陈凯

Scala学习路线

这是一篇为公司内部”scala热情workshop”活动准备的文章,面向Scala初学者,目的在于帮助大家能尽早就建立起对Scala的整体认识,少走弯路。当然由...

3335
来自专栏Java学习网

优秀程序员的 18 大法则

优秀程序员的 18 大法则 经过多年的积累,我发现,下面这些基本的指导法则,可以帮助我成为一个更加高效的程序员。 程序设计法则,与设计和工程的原理密切相关。下面...

2205
来自专栏CSDN技术头条

6个编写优质干净代码的技巧

编写干净的代码并不是一件容易的事情,这需要尝试不同的技巧和实践。问题是,在这个问题上有太多的实践和技巧,因此开发人员很难进行选择,所以要把这个问题简化一下。在本...

17610
来自专栏数据科学与人工智能

【Python环境】为什么要选择Python语言实现机器学习算法?

基于以下三个原因,我们选择Python作为实现机器学习算法的编程语言:(1) Python的语法清晰;(2) 易于操作纯文本文件;(3) 使用广泛,存在大量的开...

1898
来自专栏编程

大数据学习,为什么要先学Java?

计算机编程语言有很多,目前用的多的就是Java,C++,Python,PHP等等。目前大多数学习大数据的人都是选择学习Java,那Java到底好在哪呢?为什么学...

2568
来自专栏应用案例

C语言C加加新手入门基础学习书籍资料推荐

接下来会陆续介绍各自编程语言和各个领域的学习建议,本文先讲C语言。 ? ? 1、C语言适合当第一门编程语言学习 、C语言语法相对简单,但又比较完整和严谨,包含该...

18810

扫码关注云+社区