PHP常用的三种设计模式汇总


Posted in PHP onAugust 28, 2016

本篇文章是学习PHP中常用的三种设计模式的笔记及总结,不管采用哪一门语言开发什么,几乎都会使用到设计模式,我们为什么需要设计模式呢?它的诞生对于我们开发人员来说有什么样的作用与意义呢?

相信做iOS开发的人员对设计模式也会挺熟悉吧?比如单例设计模式、工厂设计模式、观察者模式、MVC框架结构设计模式等。

接下来我们一起来学习PHP中最常用的三种设计模式:单例设计模式、工厂设计模式和观察者设计模式。

单例设计模式

所谓单例模式,即在应用程序中最多只有该类的一个实例存在,一旦创建,就会一直存在于内存中!

单例设计模式常应用于数据库类设计,采用单例模式,只连接一次数据库,防止打开多个数据库连接。

一个单例类应具备以下特点:

单例类不能直接实例化创建,而是只能由类本身实例化。因此,要获得这样的限制效果,构造函数必须标记为private,从而防止类被实例化。

需要一个私有静态成员变量来保存类实例和公开一个能访问到实例的公开静态方法。

在PHP中,为了防止他人对单例类实例克隆,通常还为其提供一个空的私有__clone()方法。

单例模式的例子:

<?php
 
/**
* Singleton of Database
*/
class Database
{
  // We need a static private variable to store a Database instance.
  privatestatic $instance;
 
  // Mark as private to prevent it from being instanced.
  privatefunction__construct()
  {
    // Do nothing.
  }
 
  privatefunction__clone() 
  {
    // Do nothing.
  }
 
  publicstatic functiongetInstance() 
  {
    if (!(self::$instanceinstanceofself)) {
      self::$instance = newself();
    }
 
    returnself::$instance;
  }
}
 
$a =Database::getInstance();
$b =Database::getInstance();
 
// true
var_dump($a === $b);

工厂设计模式

工厂设计模式常用于根据输入参数的不同或者应用程序配置的不同来创建一种专门用来实例化并返回其对应的类的实例。

我们举例子,假设矩形、圆都有同样的一个方法,那么我们用基类提供的API来创建实例时,通过传参数来自动创建对应的类的实例,他们都有获取周长和面积的功能。

<?php
 
interfaceInterfaceShape 
{
 functiongetArea();
 functiongetCircumference();
}
 
/**
* 矩形
*/
class Rectangle implementsInterfaceShape
{
  private $width;
  private $height;
  
  publicfunction__construct($width, $height)
  {
    $this->width = $width;
    $this->height = $height;
  }
 
  publicfunctiongetArea() 
  {
    return $this->width* $this->height;
  }
 
  publicfunctiongetCircumference()
  {
    return 2 * $this->width + 2 * $this->height;
  }
}
 
/**
* 圆形
*/
class Circle implementsInterfaceShape
{
  private $radius;
 
  function__construct($radius)
  {
    $this->radius = $radius;
  }
 
 
  publicfunctiongetArea() 
  {
    return M_PI * pow($this->radius, 2);
  }
 
  publicfunctiongetCircumference()
  {
    return 2 * M_PI * $this->radius;
  }
}
 
/**
* 形状工厂类
*/
class FactoryShape 
{ 
  publicstatic functioncreate()
  {
    switch (func_num_args()) {
      case1:
      return newCircle(func_get_arg(0));
      case2:
      return newRectangle(func_get_arg(0), func_get_arg(1));
      default:
        # code...
        break;
    }
  } 
}
 
$rect =FactoryShape::create(5, 5);
// object(Rectangle)#1 (2) { ["width":"Rectangle":private]=> int(5) ["height":"Rectangle":private]=> int(5) }
var_dump($rect);
echo "<br>";
 
// object(Circle)#2 (1) { ["radius":"Circle":private]=> int(4) }
$circle =FactoryShape::create(4);
var_dump($circle);

观察者设计模式

观察者模式是挺常见的一种设计模式,使用得当会给程序带来非常大的便利,使用得不当,会给后来人一种难以维护的想法。

什么是观察者模式?一个对象通过提供方法允许另一个对象即观察者 注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可以相互对话,而不必了解原因。观察者模式是一种事件系统,意味着这一模式允许某个类观察另一个类的状态,当被观察的类状态发生改变的时候,观察类可以收到通知并且做出相应的动作;观察者模式为您提供了避免组件之间紧密耦。看下面例子你就明白了!

<?php
 
/*
观察者接口
*/
interfaceInterfaceObserver
{
  functiononListen($sender, $args);
  functiongetObserverName();
}
 
// 可被观察者接口
interfaceInterfaceObservable
{
  functionaddObserver($observer);
  functionremoveObserver($observer_name);
}
 
// 观察者抽象类
abstractclass Observer implementsInterfaceObserver
{
  protected $observer_name;
 
  functiongetObserverName() 
  {
    return $this->observer_name;
  }
 
  functiononListen($sender, $args)
  {
 
  }
}
 
// 可被观察类
abstractclass Observable implementsInterfaceObservable 
{
  protected $observers = array();
 
  publicfunctionaddObserver($observer) 
  {
    if ($observerinstanceofInterfaceObserver) 
    {
      $this->observers[] = $observer;
    }
  }
 
  publicfunctionremoveObserver($observer_name) 
  {
    foreach ($this->observersas $index => $observer) 
    {
      if ($observer->getObserverName() === $observer_name) 
      {
        array_splice($this->observers, $index, 1);
        return;
      }
    }
  }
}
 
// 模拟一个可以被观察的类
class A extendsObservable 
{
  publicfunctionaddListener($listener) 
  {
    foreach ($this->observersas $observer) 
    {
      $observer->onListen($this, $listener);
    }
  }
}
 
// 模拟一个观察者类
class B extendsObserver 
{
  protected $observer_name = 'B';
 
  publicfunctiononListen($sender, $args) 
  {
    var_dump($sender);
    echo "<br>";
    var_dump($args);
    echo "<br>";
  }
}
 
// 模拟另外一个观察者类
class C extendsObserver 
{
  protected $observer_name = 'C';
 
  publicfunctiononListen($sender, $args) 
  {
    var_dump($sender);
    echo "<br>";
    var_dump($args);
    echo "<br>";
  }
}
 
$a = new A();
// 注入观察者
$a->addObserver(new B());
$a->addObserver(new C());
 
// 可以看到观察到的信息
$a->addListener('D');
 
// 移除观察者
$a->removeObserver('B');
 
// 打印的信息:
// object(A)#1 (1) { ["observers":protected]=> array(2) { [0]=> object(B)#2 (1) { ["observer_name":protected]=> string(1) "B" } [1]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } }
// string(1) "D"
// object(A)#1 (1) { ["observers":protected]=> array(2) { [0]=> object(B)#2 (1) { ["observer_name":protected]=> string(1) "B" } [1]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } }
// string(1) "D"

小结

初入PHP的世界,目前只了解这些基本的设计模式,慢慢学着去应用!如果文中有不对之处,请在评论中指出,我会在明确之后更正文章内容!

PHP 相关文章推荐
PHP开发中常用的8个小技巧
Aug 27 PHP
一个PHP的QRcode类与大家分享
Nov 13 PHP
linux命令之调试工具strace的深入分析
Jun 03 PHP
解析关于java,php以及html的所有文件编码与乱码的处理方法汇总
Jun 24 PHP
PHP登录环节防止sql注入的方法浅析
Jun 30 PHP
php中文验证码实现方法
Jun 18 PHP
PHP如何将log信息写入服务器中的log文件
Jul 29 PHP
PHP分页初探 一个最简单的PHP分页代码的简单实现
Jun 21 PHP
[原创]解决wincache不支持64位PHP5.5/5.6的问题(提供64位wincache下载)
Jun 22 PHP
浅谈PHP中静态方法和非静态方法的相互调用
Oct 04 PHP
解决php 处理 form 表单提交多个 name 属性值相同的 input 标签问题
May 11 PHP
tp5(thinkPHP5)框架数据库Db增删改查常见操作总结
Jan 10 PHP
Apache PHP MySql安装配置图文教程
Aug 27 #PHP
php微信开发接入
Aug 27 #PHP
php微信开发自定义菜单
Aug 27 #PHP
PHP7新特性foreach 修改示例介绍
Aug 26 #PHP
简单的自定义php模板引擎
Aug 26 #PHP
PHP flush 函数使用注意事项
Aug 26 #PHP
PHP获取不了React Native Fecth参数的解决办法
Aug 26 #PHP
You might like
php操作excel文件 基于phpexcel
2010/07/02 PHP
PHP操作MySQL的mysql_fetch_* 函数的常见用法教程
2015/12/25 PHP
PHP页面跳转操作实例分析(header方法)
2016/09/28 PHP
PHP安装memcache扩展的步骤讲解
2019/02/14 PHP
Laravel如何创建服务器提供者实例代码
2019/04/15 PHP
JS的反射问题
2010/04/07 Javascript
JS trim去空格的最佳实践
2011/10/30 Javascript
jquery.pagination.js 无刷新分页实现步骤分享
2012/05/23 Javascript
JavaScript生成福利彩票双色球号码
2015/05/15 Javascript
基于jquery实现轮播特效
2016/04/22 Javascript
JavaScript+Java实现HTML页面转为PDF文件保存的方法
2016/05/30 Javascript
使用Angular.js开发的注意事项
2016/10/19 Javascript
js Canvas绘制圆形时钟教程
2017/02/06 Javascript
Vue修改项目启动端口号方法
2019/11/07 Javascript
浅谈Vue.use到底是什么鬼
2020/01/21 Javascript
webpack安装配置与常见使用过程详解(结合vue)
2020/06/01 Javascript
vue 使用vant插件做tabs切换和无限加载功能的实现
2020/11/04 Javascript
js实现随机点名功能
2020/12/23 Javascript
原生jQuery实现只显示年份下拉框
2020/12/24 jQuery
[02:28]DOTA2 2015国际邀请赛中国区预选赛首日现场百态
2015/05/26 DOTA
基于Python中capitalize()与title()的区别详解
2017/12/09 Python
Django项目开发中cookies和session的常用操作分析
2018/07/03 Python
Python定时任务sched模块用法示例
2018/07/16 Python
使用Windows批处理和WMI设置Python的环境变量方法
2019/08/14 Python
Python: 传递列表副本方式
2019/12/19 Python
Python字符编码转码之GBK,UTF8互转
2020/02/09 Python
python安装cx_Oracle和wxPython的方法
2020/09/14 Python
CSS3实现大小不一的粒子旋转加载动画
2016/04/21 HTML / CSS
Kate Spade美国官网:纽约新兴时尚品牌,以包包闻名于世
2017/11/09 全球购物
德国2018年度最佳在线药房:Bodfeld Apotheke
2019/11/04 全球购物
大学生学期自我鉴定
2014/03/19 职场文书
《理想的风筝》教学反思
2014/04/11 职场文书
一年级小学生评语
2014/04/22 职场文书
领导班子对照检查剖析材料
2014/10/13 职场文书
分居协议书范本
2014/11/03 职场文书
Nginx优化服务之网页压缩的实现方法
2021/03/31 Servers