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

5年以前  |  阅读数:767 次  |  编程语言:PHP 

本篇文章是学习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分页显示制作详细讲解
SSH 登录失败:Host key verification failed
获取IMSI
将二进制数据转为16进制以便显示
贪吃蛇
文件下载
获取IMEI
双位运算符
发送邮件
PHP自定义函数获取搜索引擎来源关键字的方法
Java生成UUID
提取后缀名
年的日历图
在Zeus Web Server中安装PHP语言支持
让你成为最历害的git提交人
Yii2汉字转拼音类的实例代码
再谈PHP中单双引号的区别详解
指定应用ID以获取对应的应用名称
Python 2与Python 3版本和编码的对比
php封装的page分页类完整实例