PHP面向对象设计模式

雨点打透心脏的1/2处 2022-03-31 06:30 358阅读 0赞

转载:https://blog.csdn.net/weixin\_41163355/article/details/78624565

PHP设计模式——概述

常见的面向对象设计模式大约有23种,但是自从接触PHP后,渐渐发现常见的设计模式好像少了很多,网络上的资料也比较少,身边的PHP同事们有的甚至没有听说过设计模式,这也有可能是PHP的发展所带来的,因为PHP对面向对象支持的比较晚,好多PHP程序员还按照面向过程的思想写代码。于是,我决定把原来用C#写的面向对象设计模式用PHP改写。

  1. 经常听见其他程序员([Java][]、 C\#)等说PHP是不是运行在浏览器端的脚本语言,其实我在接触PHP之前也这样认为过,后来发现PHP是用C语言开发出来的一种语言,C语言是真正意义 上跨平台的语言,这也注定PHP是跨平台的,PHP是可运行在Windows ServerLinux操作系统的服务器上的语言,它和Java以及C\#一样,代码存储并运行在服务器端,它将浏览器端可执行的HTML以及脚本发送给 浏览器执行,PHP相对JavaC\#对于面向过程的封装更多,减少部分数据类型的支持。
  2. PHP是面向对象的,PHP能够得到这样快速的发展,能够被互联网大企业所广泛应用,证明PHP是经得住考验的,随着移动互联网的不断发展,PHP还会更广阔的天地。
  3. 什么是设计模式?
  4. 设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
  5. 项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。
  6. 设计模式的优点:
  7. 1).复用解决方案: 设计模式本身就是对某一类问题的通用解决方案,是更高级别的复用,已经超出了代码复用.
  8. 2).确定通用术语:开发中的交流和协作都需要共同的词汇其础和对问题的共识. 当你有想表达却又表达不清楚的设计思路,即使表达出来也会被同事误解的时候,设计模式就显出沟通的优势了。
  9. 3).代码更易于修改与维护。因为设计模式都是久经考验的解决方案,它们的结构都是经过长期的发展形成的,善于应对变化,设计模式本身也是对变化点的封装。
  10. 4).模式有助于提高思考层次。学习模式后,就算不用模式中的方法,也会更好的采取更好的策略去解决问题。
  11. 在接下来的篇幅里会详细介绍PHP面向对象设计模式,本系列博客以设计模式的原理为核心,列举最简单的例子,让只要有一点面向对象基础的读者都能看明白。

PHP设计模式——六大原则

  1. 一般认为遵从以下六大原则的代码是易扩展可复用的代码:
  2. ![SouthEast][]
  3. 这六大原则任何面向对象的语言都应该遵守的,要想让你的代码易扩展高服用就尽量去满足这六大原则吧,不一定严格按照某种设计模式,但是如果你的代码符合这六大原则,那么你的代码就是好代码了,好的代码不一定是严格按照设计模式写的代码。
  4. 1.单一职责
  5. 定义:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
  6. 场景:类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障,关系如下图:
  7. ![SouthEast 1][]
  8. 修改:遵循单一职责原则。分别建立两个类T1T2,使T1完成职责P1功能,T2完成职责P2功能。这样,当修改类T1时,不会使职责P2发生故障风险;同理,当修改T2时,也不会使职责P1发生故障风险,结构如下图:
  9. ![SouthEast 2][]
  10. 优点:
  11. 1)、可以降低类的复杂度,一个类只负责一项职责,逻辑简单;
  12. 2)、提高类的可读性,提高系统的可维护性;
  13. 3)、变更引起的风险降低,变更是必然的。
  14. 2.里氏代换原则
  15. 定义:所有引用基类的地方必须能透明地使用其子类的对象,也就是说子类可以扩展父类的功能,但不能改变父类原有的功能
  16. 场景:有一功能P1,由类A完成。现需要将功能P1进行扩展,扩展后的功能为P,其中P由原有功能P1与新功能P2组成。新功能P由类A的子类B来完成,则子类B在完成新功能P2的同时,有可能会导致原有功能P1发生故障,如下图:
  17. ![SouthEast 3][]
  18. CountPriceByJKL类继承于CountPrice类,CountPriceByJKL重写了Count()方法,这样可能影响到原来Count方法的功能。
  19. 修改:当使用继承时,遵循里氏替换原则。类B继承类A时,除添加新的方法完成新增功能P2外,尽量不要重写父类A的方法,也尽量不要重载父类A的方法。
  20. 3.依赖倒置原则
  21. 定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
  22. 此处理解起来是最困难的,一般会在项目框架的搭建的时候用到,例如,业务逻辑层相对于数据层是高层模块,因为业务逻辑层需要调用数据层去连接[数据库][Link 1],但是要做到可扩展高复用,尽量不要让业务逻辑层依赖数据层,可以在数据层抽象出一个接口,让业务逻辑层依赖于这个抽象接口。
  23. 场景:类A(高层模块)直接依赖类B(低层模块),假如要将类A改为依赖类C(低层模块),则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
  24. ![SouthEast 4][]
  25. AutoSystem类直接依赖于HondaCarFordCar两个类,这样就产生了一个高耦合,AutoSystem类想操控HondaCar或者FordCar必须直接创建相应对象。
  26. 修改:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率,如下图:
  27. ![SouthEast 5][]
  28. 经过此番修改,HondaFord实现ICar接口,提供了RunStop以及Turn功能方法,AutoSystem依赖ICar接口,这样迫使AutoSystem依赖抽象接口,这就使得AutoSystem类能够应对更多的需求变化。
  29. 优点:
  30. 1)、低层模块尽量都要有抽象类或接口,或者两者都有。
  31. 2)、变量的声明类型尽量是抽象类或接口。
  32. 3)、使用继承时遵循里氏替换原则。
  33. 4.接口隔离原则
  34. 定义:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
  35. 场景:类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不需要的方法,如下图:

        SouthEast 6

   修改:将臃肿的接口I拆分为独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则。

        SouthEast 7

   注意:

     1)、接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性 是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。

     2)、为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。

    3)、提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。

   5.迪米特法则(最少知道原则)

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

  场景:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。

  简单的理解就是高内聚,一个类尽量减少对其他对象的依赖,并且这个类的方法和属性能用私有的就尽量私有化。

  注意:

  1. 1)、只与直接的朋友通信,不要和陌生人说话。
  2. 2)、过分的使用该原则,将导致系统复杂度变大。所以在采用迪米特法则时要反复权衡,既做到结构清晰,又要高内聚低耦合。
  3. 6.开闭原则
  4. 定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
  5. 场景:在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试。
  6. 建议:当软件需求变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。

PHP设计模式——简单工厂

前面两节内容介绍了什么是设计模式以及六大原则,相信看完前两节内容大家对设计模式已经有了初步的认识,接下来说一下设计模式的分类。

  1. 一般将面向对象设计模式分为三类:创建型、结构型、行为型三种。
  2. 创建型:创建对象时,不再由我们直接实例化对象;而是根据特定场景,由程序来确定创建对象的方式,从而保证更大的性能、更好的[架构][Link 2]优势。创建型模式主要有简单工厂模式(并不是23种设计模式之一)、工厂方法、抽象工厂模式、单例模式、生成器模式、原型模式。
  3. 结构型:用于帮助将多个对象组织成更大的结构。结构型模式主要有适配器模式、桥接模式、组合器模式、装饰器模式、门面模式、亨元模式和代理模式。
  4. 行为型:用于帮助系统间各对象的通信,以及如何控制复杂系统中流程。行为型模式主要有命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板模式、访问者模式和职责链模式。
  5. 今天主要介绍创建型的第一种简单工厂模式。
  6. 注意:在阅读本系列博客的时候一定要有阅读UML类图、面向对象PHP编程基础。
  7. 简单工厂模式不属于23种常用面向对象设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。其实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。
  8. ![SouthEast 8][]
  9. 角色及职责:
  10. 工厂(SimpleFactory)角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。
  11. 抽象产品(IProduct)角色:简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
  12. 具体产品(Concrete Product)角色:是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。
  13. 需求:根据提供相应的属性值由简单工厂创建具有相应特性的产品对象。
  14. 现根据以上UML类图编写如下PHP代码。

[php] view plain copy print ? 在CODE上查看代码片派生到我的代码片

  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Jiang
  5. * Date: 2015/4/9
  6. * Time: 21:48
  7. */
  8. /**抽象产品角色
  9. * Interface IProduct 产品接口
  10. */
  11. interface IProduct
  12. {
  13. /**X轴旋转
  14. * @return mixed
  15. */
  16. function XRotate();
  17. /**Y轴旋转
  18. * @return mixed
  19. */
  20. function YRotate();
  21. }
  22. /**具体产品角色
  23. * Class XProduct X轴旋转产品
  24. */
  25. class XProduct implements IProduct
  26. {
  27. private $xMax=1;
  28. private $yMax=1;
  29. function __construct($xMax,$yMax)
  30. {
  31. $this->xMax=$xMax;
  32. $this->yMax=1;
  33. }
  34. function XRotate()
  35. {
  36. echo “您好,我是X轴旋转产品,X轴转转转。。。。。。”;
  37. }
  38. function YRotate()
  39. {
  40. echo “抱歉,我是X轴旋转产品,我没有Y轴。。。。。。”;
  41. }
  42. }
  43. /**具体产品角色
  44. * Class YProduct Y轴旋转产品
  45. */
  46. class YProduct implements IProduct
  47. {
  48. private $xMax=1;
  49. private $yMax=1;
  50. function __construct($xMax,$yMax)
  51. {
  52. $this->xMax=1;
  53. $this->yMax=$yMax;
  54. }
  55. function XRotate()
  56. {
  57. echo “抱歉,我是Y轴旋转产品,我没有X轴。。。。。。”;
  58. }
  59. function YRotate()
  60. {
  61. echo “您好,我是Y轴旋转产品,Y轴转转转。。。。。。”;
  62. }
  63. }
  64. /**具体产品角色
  65. * Class XYProduct XY轴都可旋转产品
  66. */
  67. class XYProduct implements IProduct
  68. {
  69. private $xMax=1;
  70. private $yMax=1;
  71. function __construct($xMax,$yMax)
  72. {
  73. $this->xMax=$xMax;
  74. $this->yMax=$yMax;
  75. }
  76. function XRotate()
  77. {
  78. echo “您好,我是XY轴都可旋转产品,X轴转转转。。。。。。”;
  79. }
  80. function YRotate()
  81. {
  82. echo “您好,我是XY轴都可旋转产品,Y轴转转转。。。。。。”;
  83. }
  84. }
  85. /**工厂角色
  86. * Class ProductFactory
  87. */
  88. class ProductFactory
  89. {
  90. static function GetInstance($xMax,$yMax)
  91. {
  92. if($xMax>1 && $yMax===1)
  93. {
  94. return new XProduct($xMax,$yMax);
  95. }
  96. elseif($xMax===1 && $yMax>1)
  97. {
  98. return new YProduct($xMax,$yMax);
  99. }
  100. elseif($xMax>1 && $yMax>1)
  101. {
  102. return new XYProduct($xMax,$yMax);
  103. }
  104. else
  105. {
  106. return null;
  107. }
  108. }
  109. }
  1. 测试代码:

[php] view plain copy print ? 在CODE上查看代码片派生到我的代码片

  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Jiang
  5. * Date: 2015/4/9
  6. * Time: 21:54
  7. */
  8. require_once “./SimpleFactory/SimpleFactory.php”;
  9. header(“Content-Type:text/html;charset=utf-8”);
  10. $pro=array();
  11. $pro[]=ProductFactory::GetInstance(1,12);
  12. $pro[]=ProductFactory::GetInstance(12,1);
  13. $pro[]=ProductFactory::GetInstance(12,12);
  14. $pro[]=ProductFactory::GetInstance(0,12);
  15. foreach($pro as $v)
  16. {
  17. if($v)
  18. {
  19. echo “
    “;
  20. $v->XRotate();
  21. echo “
    “;
  22. $v->YRotate();
  23. }
  24. else
  25. {
  26. echo “非法产品!
    “;
  27. }
  28. echo “
    “;
  29. }
  1. 用浏览器访问测试代码,我们可以发现创建的对象依次是YProduct,XProduct,XYProduct,null。简单工厂的核心代码在于工厂 (ProductFactory)这个角色,这里根据传入的xMaxyMax值去创建不同的对象,这便是简单工厂的实质,而且我们在测试调用客户端根本 不知道具体的产品类是什么样,这样就做到了调用与创建的分离。
  2. 简单工厂的优点:让对象的调用者和对象创建过程分离,当对象调用者需要对象时,直接向工厂请求即可。从而避免了对象的调用者与对象的实现类以硬编码方式耦合,以提高系统的可维护性、可扩展性。
  3. 简单工厂的缺点:当产品修改时,工厂类也要做相应的修改,比如要增加一种操作类,如求M数的N次方,就得改case,修改原有类,违背了开放-封闭原则。

发表评论

表情:
评论列表 (有 0 条评论,358人围观)

还没有评论,来说两句吧...

相关阅读

    相关 面向对象设计模式--简介

    学了那么久的面向对象。我们会发现,我们写的代码很low。 当然为什么会觉得很LOW,那是因为,我们在写代码的时候往往更加关注的是代码本身, 很少有人去思考怎样才能将代码写的

    相关 面向对象设计模式总结

    一、前言       设计模式是软件编程提升水平的一个重要技能,而且在软件攻城狮中考试里,也是比不可少的,所以小编总结了历年的软考真题,总结了设计模式。希望可以给您带来帮

    相关 面向对象设计模式原则

    设计模式 先来说说设计模式,什么是设计模式呢? > 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计