设计模式六大原则(PHP)

  设计模式的目的是为了更好的代码重用性,可读性,可靠性和可维护性。经常使用的六大设计模式有:单一职责原则(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种设计模式的目的就是遵循开闭原则。简单的理解就是构建框架的时候要保持足够的扩展性,通扩展来实现修改代码而不是直接修改代码。

相关文章
相关标签/搜索