设计模式的目的是为了更好的代码重用性,可读性,可靠性和可维护性。常用的六大设计模式有:单一职责原则(SRP),里氏替换原则(LSP),依赖倒转原则(DIP),接口隔离原则(ISP),迪米特法则(LOD),开闭原则(OCP)。

1.单一职责原则(Single Responsibility Principle)

该原则是针对类来说的,即一个类应该只负责一项职责。假设有一个部门的类叫做T,他的下面有两个职责的方法叫做P1,P2。假如P1的职责发生改变时去修改这个部门类T,那么有可能造成职责P2发生故障。

举个栗子:

我们用动物呼吸的场景来表现一下

输出结果:

但是呢,我们发现并不是所有的动物都是呼吸空气的,比如说鱼它是呼吸水的。根据SRP原则,我们应该将Animal类分为陆地动物和海洋生物,如下所示:

但是我们发现这样修改花销很大,既要将原来的类分解,又要修改客户端。而直接修改Animal类则违背了单一职责原则,但花销很小 如下所示:

这种修改方式没有改变原来的方法,而是在类中新加了一个方法,这样虽然违反了单一职责原则,但是在方法级别上却是符合单一职责原则的。在实际的编程中,只有逻辑足够简单,才可能在代码级违反单一职责原则;只有类中的方法数量足够少,才可以在方法级别上违反单一职责原则。

遵循单一职责的优点:

(1)降低类的复杂度,一个类只负责一项职责。

(2)提高类的可读性,可维护性。

(1)降低变更引起的风险。

2.里氏替换原则(Liskov Substitution Principle)

该原则提出,如果对每个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。这话原句,不知道是翻译的锅还是咋地,看起来就晦涩难懂。其实可以简单地理解为所有引用基类的地方必须能够透明的使用其子类的对象,在子类中尽量不要重写和重载父类的方法。

继承作为面向对象的三大特性之一,在给程序带来巨大便利的同时,也带来了弊端。比如继承会给程序带来可入侵行,程序的可移植性降低,增加了对象间的耦合性。如果一个类被其他类所继承,那么这个类在被修改的时候,必须考虑到所有的子类。并且父类在修改后,所以涉及到子类的功能都有可能发生故障。

举个栗子:

运行结果:

后来呢,我们想做个功能,将两个数相加并且乘以100.这个时候我们看到上面那个类也是两个参数,只不过是相减。我们继承一下A重写下那个方法不就完成求和再求积吗?代码如下:

运行结果:

结果我们发现,在业务逻辑代码没变的情况下结果居然跟预期的结果不一样了。因为C类虽然继承了A类,但是它重写了A类的subtract方法,造成了原有功能的错误。在实际的编码过程中我们通常会重写父类的方法来完成新的功能,但是这样会使得类的继承体系复用性特别差。这个时候我们可以选择让A和C共同继承一个更通俗的基类,然后实现他的方法,去掉A和C的继承关系,采用依赖、聚合、组合等关系代替。举个栗子:

这样我们既可以保持原有的业务关系,又可以实现更多的功能。

3.依赖倒转原则(Dependence Inversion Principle)

依赖倒置规定:高层模块不应该依赖于低层模块,二者都应该依赖其抽象;抽象不应该依赖于细节,细节应该依赖于抽象。因为相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构要比以细节为基础的架构要稳定的多。依赖倒置的中心思想是面向接口编程。上层模块不应该依赖于下层模块,应该依赖于接口。从而使得下层模块依赖于上层的接口,降低耦合度,提高系统的弹性。这六大原则是最虚,最抽象的,很难理解。举个栗子说明:

但是如果我们读的是报纸,杂志呢,发现book并不适用了。我们引入一个抽象的接口IReader,代表读物。让Mother类与接口IReader发生依赖关系,而Book和Newspaper都属于读物的范畴,让他们各自都去实现IReader接口,这样就符合高层不应该依赖低层,应该依赖于接口的依赖倒置原则,修改后代码如下:

用了依赖倒置原则之后会发现带给我们极大的便利,比如例子,一开始Mother类与Book类耦合,如果要修改读物的话,必须要创建一个新的读物类,然后修改Mother类中传入的类名,非常的麻烦。而修改后Mother类则直接依赖了IReader接口,这样与Book解耦,每次只需要创建一个新的读物类实现IReader接口即可调用

依赖关系的传递有三种办法,分别是接口传递、构造方法传递以及setter方法传递。

1.接口传递

2.构造方法传入(常用)

3.setter方法传递

在实际的编程中尽量注意以下三点:1.低层模块尽量都要有抽象类或者接口类,或者两者都有2.变量的声明类型尽量是抽象类或者接口(这里是指传入的那个变量代表的类)3.遵循里氏替换原则。控制反转(IOC)和依赖注入(DI)也是基于此原则,把所有类的实例化放在了一个容器中,从容器中获取调用,降低了高层类对低层类的依赖。有学习IOC和DI的,可以留个邮箱,我会把一些理解的例子发一下。

4.接口隔离原则(InterfaceSegregation Principles)

一个类不应该依赖他不需要的接口;一个类对另一个类的依赖应该建立在最小接口上。比如类A通过接口E依赖类B,类C通过接口E依赖类D,如果接口E对于类A和类C来说不是最小接口的话,则类B和类D必须去实现他们不需要的方法。这个时候我们将臃肿的接口拆分成独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。这就是接口隔离原则。举个栗子:





可以看出,接口中出现的方法,不管对依赖于它的类有没有作用,实现类都必须实现这些方法。这个时候我们把接口拆分下,实现接口隔离原则。举个栗子:

看到这里,大家可能会觉得接口隔离原则和单一职责原则很相似。其实不是的,1.单一职责原则是注重的这个类的职责,而接口隔离原则注重对接口依赖的隔离2.单一职责约束的是类,其次是方法,针对的是程序中的实现和细节,而接口隔离原则约束的是接口,是抽象,是程序框架整体的构建。

5.迪米特原则(Law of Demeter,也称为最少知识原则Least Knowledge Principle)

一个对象应该对其他对象保持最少的了解。类与类之间的关系越密切,耦合度越大。迪米特原则又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,无论被依赖的类多么复杂,都尽量将逻辑封装在类的内部。对外只提供public方法,而不对外泄露任何信息。迪米特原则还有个更简单的定义:只与直接的朋友通信。什么是直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就称这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。举个栗子:

这个设计的问题在于CompanyManager中,SubCompanyManager类并不是它的直接朋友。按照迪米特法则,应该避免类中出现这样非直接朋友关系的耦合。修改如下

迪米特法则降低类之间的耦合,让每个类都减少了不必要的依赖;但是过度使用迪米特法则会产生大量的中介类和传递类,导致系统复杂度变大。所以在采用迪米特法则的时候要反复权衡,既要做到结构清晰,同时做到高内聚低耦合。

开闭原则(Open Close Principle)

一个 软件实体如类,模块和函数应该对扩展开放,对修改关闭。用抽象构建框架,用实现扩展细节。当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。当我们遵循前面介绍的五大原则,以及使用23种设计模式的目的就是遵循开闭原则。简单的理解就是构建框架的时候要保持足够的扩展性,通扩展来实现修改代码而不是直接修改代码。

设计模式六大原则(PHP)的更多相关文章

  1. 设计模式六大原则——合成/聚合复用原则(CARP)

    1.定义 简而言之,对于合成/聚合复用原则的定义就是:要尽量使用合成和聚合,尽量不要使用继承. 2.释义 为什么"要尽量使用合成和聚合.尽量不要使用继承"呢? 这是由于: 第一,继 ...

  2. GOF提出的23种设计模式是哪些 设计模式有创建形、行为形、结构形三种类别 常用的Javascript中常用设计模式的其中17种 详解设计模式六大原则

    20151218mark 延伸扩展: -设计模式在很多语言PHP.JAVA.C#.C++.JS等都有各自的使用,但原理是相同的,比如JS常用的Javascript设计模式 -详解设计模式六大原则 设计 ...

  3. PHP 设计模式六大原则

    http://www.cnblogs.com/yujon/p/5536118.html 设计模式六大原则(1):单一职责原则 不要存在多于一个导致类变更的原因.通俗的说,即一个类只负责一项职责 设计模 ...

  4. ZT 设计模式六大原则(1):单一职责原则

    zt 设计模式六大原则(1):单一职责原则 分类: 设计模式 2012-02-21 09:52 25059人阅读 评论(65) 收藏 举报 设计模式stringclass编程 (THERE SHOUL ...

  5. ZT 设计模式六大原则(2):里氏替换原则

    设计模式六大原则(2):里氏替换原则 分类: 设计模式 2012-02-22 08:46 23330人阅读 评论(41) 收藏 举报 设计模式class扩展string编程2010 肯定有不少人跟我刚 ...

  6. zt 设计模式六大原则(3):依赖倒置原则

    下面说法对不对? 父类将算法(逻辑)封装起来,子类实现细节:这个就叫DIP(依赖倒置:Dependency Inversion Principles),模板模式就是这个原则的实现.如果在父类中加一个t ...

  7. ZT 设计模式六大原则(6):开闭原则

    ZT 设计模式六大原则(6):开闭原则 分类: 设计模式 2012-02-27 08:48 24870人阅读 评论(72) 收藏 举报 设计模式扩展框架编程测试 定义:一个软件实体如类.模块和函数应该 ...

  8. ZT 设计模式六大原则(5):迪米特法则

    转贴: 设计模式六大原则(5):迪米特法则   原帖子的后续评论里面很多值得仔细去看 切记!像21楼 21楼 chenshufei2 2012-09-23 12:47发表 [回复] 上个例子,就是方法 ...

  9. ZT 设计模式六大原则(4):接口隔离原则

    设计模式六大原则(4):接口隔离原则 分类: 设计模式 2012-02-27 08:32 17948人阅读 评论(21) 收藏 举报 设计模式classinterfacecstring框架 定义:客户 ...

  10. Java设计模式六大原则-2

    Java设计模式六大原则-2 做Java程序开发的每天都在使用JDK,Spring,SpringMvc,Mybatis,Netty,MINA等框架,但很少有人懂得背后的原理.即使打开跟下原码也是一头雾 ...

随机推荐

  1. Vue深度学习(6)- 组件

    使用组件 在Vue中,可以用 Vue.extend() 创建一个组件构造器: var MyComponent = Vue.extend({ template:'..........' //选项 }) ...

  2. Vue深度学习(3)

    基础 Vue.js允许自定义指令,实质上是让你教 Vue一些新技巧:怎样将数据的变化映射到 DOM 的行为.可以使用 Vue.directive(id, definition) 的方法传入指令 id  ...

  3. ASP.MVC当URL跳转时候参数的安全性

    一个页面跳转到另外一个页面直接将参数写在URL上面并不安全比如 http://XXXXXXXXXXX/meeting/shakeGroup?id=5381&uid=o0En_sj1J0bFgI ...

  4. 腾讯Web工程师的前端书单

    2014年一月以来,自己接触web前端开发已经两年多了,记录一下自己前端学习路上看过的,以及道听途说的一些书,基本上按照由浅入深来介绍. JavaScript 入门 <JavaScript权威指 ...

  5. ME01:猎场中猎头的内核

    前几天追了下<猎场>,只看了前面10多集,觉得下面的对话有点意思. 是关于猎头是干什么的? 猎头具备的素质. 对我们普通人是不是也有启发意义呢? 如何看人, 找到靠谱的合作人?找打好的老板 ...

  6. HTML5 Canvas:初始Canvas

    Canvas ,HTML 5中引入它,可以做很多事情:画图.动画.游戏开发等等. Canvas 元素 Canvas 中文翻译为:画布. <canvas id=”yourCanvasId” wid ...

  7. JAVA IO分析三:IO总结&文件分割与合并实例

    时间飞逝,马上就要到2018年了,今天我们将要学习的是IO流学习的最后一节,即总结回顾前面所学,并学习一个案例用于前面所学的实际操作,下面我们就开始本节的学习: 一.原理与概念 一.概念流:流动 .流 ...

  8. MySQL的存储引擎与日志说明

    1.1 存储引擎的介绍 1.1.1 文件系统存储 文件系统:操作系统组织和存取数据的一种机制.文件系统是一种软件. 类型:ext2 3 4 ,xfs 数据.  不管使用什么文件系统,数据内容不会变化, ...

  9. 微信小程序教学第二章:小程序中级实战教程之预备篇 - 项目结构设计 |基于最新版1.0开发者工具

    iKcamp官网:http://www.ikcamp.com 访问官网更快阅读全部免费分享课程:<iKcamp出品|全网最新|微信小程序|基于最新版1.0开发者工具之初中级培训教程分享>. ...

  10. 动态WebApi

    动态WebApi实现了直接对Service的调用,其实没有跨过ApiController,只是我们自己创建出ApiController 实现主要分以下几步 一 对默认WebApi服务的替换 ApiGl ...