设计模式六⼤原则(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分别与他们需要的接⼝建⽴依赖关系。这就是接⼝隔离原则。举个栗⼦:
php实例化后获取子类名称可以看出,接⼝中出现的⽅法,不管对依赖于它的类有没有作⽤,实现类都必须实现这些⽅法。这个时候我们把接⼝拆分下,实现接⼝隔离原则。举个栗⼦:
看到这⾥,⼤家可能会觉得接⼝隔离原则和单⼀职责原则很相似。其实不是的,1.单⼀职责原则是注重的这个类的职责,⽽接⼝隔离原则注重对接⼝依赖的隔离2.单⼀职责约束的是类,其次是⽅法,针对的是程序中的实现和细节,⽽接⼝隔离原则约束的是接⼝,是抽象,是程序框架整体的构建。
5.迪⽶特原则(Law of Demeter,也称为最少知识原则Least Knowledge Principle)
⼀个对象应该对其他对象保持最少的了解。类与类之间的关系越密切,耦合度越⼤。迪⽶特原则⼜叫最少知道原则,即⼀个类对⾃⼰依赖的类知道的越少越好。也就是说,⽆论被依赖的类多么复杂,都尽量将逻辑封装在类的内部。对外只提供public⽅法,⽽不对外泄露任何信息。迪⽶特原则还有个更简单的定义:只与直接的朋友通信。什么是直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就称这两个对象之间是朋友关系。耦合的⽅式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,⽅法参数,⽅法返回值中的类为直接的朋友,⽽出现在局部变量中的类不是直接的朋友。也就是说,陌⽣的类最好不要以局部变量的形式出现在类的内部。举个栗⼦:
这个设计的问题在于CompanyManager中,SubCompanyManager类并不是它的直接朋友。按照迪⽶特法则,应该避免类中出现这样⾮直接朋友关系的耦合。修改如下
迪⽶特法则降低类之间的耦合,让每个类都减少了不必要的依赖;但是过度使⽤迪⽶特法则会产⽣⼤量的中介类和传递类,导致系统复杂度变⼤。所以在采⽤迪⽶特法则的时候要反复权衡,既要做到结构清晰,同时做到⾼内聚低耦合。
开闭原则(Open Close Principle)
⼀个软件实体如类,模块和函数应该对扩展开放,对修改关闭。⽤抽象构建框架,⽤实现扩展细节。当软件需要变化时,尽量通过扩展软件实体的⾏为来实现变化,⽽不是通过修改已有的代码来实现变化。当我们遵循前⾯介绍的五⼤原则,以及使⽤23种设计模式的⽬的就是遵循开闭原则。简单的理解就是构建框架的时候要保持⾜够的扩展性,通扩展来实现修改代码⽽不是直接修改代码。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论