当前位置: 首页 > news >正文

PHP常用几种设计模式的应用场景

码字不易,转载请附原链,搬砖繁忙回复不及时见谅,技术交流请加QQ群:909211071

1.单例设计模式

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

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

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

单例类不能直接实例化创建,而是只能由类本身实例化。因此,要获得这样的限制效果,构造函数必须标记为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.  
  private function__construct()  
  {  
    // Do nothing.  
  }  
    
  private function__clone()   
  {  
    // Do nothing.  
  }  
    
  public static function getInstance()   
  {  
    if (!(self::$instance instanceof self)) {  
      self::$instance = new self();  
    }  
    
    return self::$instance;  
  }  
}  
    
$a =Database::getInstance();  
$b =Database::getInstance();  
    
// true  
var_dump($a === $b);  

 

2.工厂设计模式

主要是当操作类的参数变化时,只用改相应的工厂类就可以

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

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

<?php  
    
interface InterfaceShape   
{  
 function getArea();  
 function getCircumference();  
}  
    
/** 
* 矩形 
*/  
class Rectangle implements InterfaceShape  
{  
  private $width;  
  private $height;  
     
  public function __construct($width, $height)  
  {  
    $this->width = $width;  
    $this->height = $height;  
  }  
    
  public function getArea()   
  {  
    return $this->width* $this->height;  
  }  
    
  public function getCircumference()  
  {  
    return 2 * $this->width + 2 * $this->height;  
  }  
}  
    
/** 
* 圆形 
*/  
class Circle implements InterfaceShape  
{  
  private $radius;  
    
  function __construct($radius)  
  {  
    $this->radius = $radius;  
  }  
    
    
  public function getArea()   
  {  
    return M_PI * pow($this->radius, 2);  
  }  
    
  public function getCircumference()  
  {  
    return 2 * M_PI * $this->radius;  
  }  
}  
    
/** 
* 形状工厂类 
*/  
class FactoryShape   
{   
  public static function create()  
  {  
    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);  
 

 

3.观察者设计模式

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

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

<?php  
    
/* 
观察者接口 
*/  
interface InterfaceObserver  
{  
  function onListen($sender, $args);  
  function getObserverName();  
}  
    
// 可被观察者接口  
interface InterfaceObservable  
{  
  function addObserver($observer);  
  function removeObserver($observer_name);  
}  
    
// 观察者抽象类  
abstract class Observer implements InterfaceObserver  
{  
  protected $observer_name;  
    
  function getObserverName()   
  {  
    return $this->observer_name;  
  }  
    
  function onListen($sender, $args)  
  {  
    
  }  
}  
    
// 可被观察类  
abstract class Observable implements InterfaceObservable   
{  
  protected $observers = array();  
    
  public function addObserver($observer)   
  {  
    if ($observerinstanceofInterfaceObserver)   
    {  
      $this->observers[] = $observer;  
    }  
  }  
    
  public function removeObserver($observer_name)   
  {  
    foreach ($this->observersas $index => $observer)   
    {  
      if ($observer->getObserverName() === $observer_name)   
      {  
        array_splice($this->observers, $index, 1);  
        return;  
      }  
    }  
  }  
}  
    
// 模拟一个可以被观察的类  
class A extends Observable   
{  
  public function addListener($listener)   
  {  
    foreach ($this->observersas $observer)   
    {  
      $observer->onListen($this, $listener);  
    }  
  }  
}  
    
// 模拟一个观察者类  
class B extends Observer   
{  
  protected $observer_name = 'B';  
    
  public function onListen($sender, $args)   
  {  
    var_dump($sender);  
    echo "<br>";  
    var_dump($args);  
    echo "<br>";  
  }  
}  
    
// 模拟另外一个观察者类  
class C extends Observer   
{  
  protected $observer_name = 'C';  
    
  public function onListen($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"  
 
 

4.适配器模式

将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本的由于接口不兼容而不能一起工作的那些类可以一起工作。
应用场景:老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。例如:php连接数据库的方法:mysql,,mysqli,pdo,可以用适配器统一
//老的代码       
  
class User {      
  
    private $name;      
  
    function __construct($name) {      
  
        $this->name = $name;      
  
    }      
  
    public function getName() {      
  
        return $this->name;      
  
    }      
  
}     
//新代码,开放平台标准接口      
  
interface UserInterface {      
  
    function getUserName();      
  
}      
  
class UserInfo implements UserInterface {      
  
    protected $user;      
  
    function __construct($user) {      
  
        $this->user = $user;      
  
    }      
  
    public function getUserName() {      
  
        return $this->user->getName();      
  
    }      
  
}     
$olduser = new User('张三');      
  
echo $olduser->getName()."n";      
  
$newuser = new UserInfo($olduser);      
  
echo $newuser->getUserName()."n";      

 

 

5.策略模式

将一组特定的行为和算法封装成类,以适应某些特定的上下文环境。
例如:一个电商网站系统,针对男性女性用户要各自跳转到不同的商品类目,并且所有广告位展示不同的广告
 
<?php
interface UserStrategy
{

    public function showAd();
    public function showCategory();
}

class MaleUserStrategy implements UserStrategy
{

    public function showAd()
    {
        echo 'iphone';
    }

    public function showCategory()
    {
        echo '电子产品';
    }
}

class FemaleUserStrategy implements UserStrategy
{
    public function showAd()
    {
        echo '新款女装';
    }

    public function showCategory()
    {
        echo '女装';
    }
}

class Ad
{
    protected $obj;

    public function __construct($obj)
    {
        $this->obj = $obj;
    }

    public function showAd()
    {
        $this->obj->showAd();
    }

    public function showCategory()
    {
        $this->obj->showCategory();
    }
}

$maleUser = new Ad(new MaleUserStrategy());
$famaleUser = new Ad(new FemaleUserStrategy());

$maleUser->showAd();
$famaleUser->showCategory();

比如monolog就用到了策略者模式:


 

6.装饰器模式

使用场景:当某一功能或方法draw,要满足不同的功能需求时,可以使用装饰器模式;实现方式:在方法的类中建addDecorator(添加装饰器),beforeDraw,afterDraw 3个新方法, 后2个分别放置在要修改的方法draw首尾.然后创建不同的装器类(其中要包含相同的,beforeDraw,afterDraw方法)能过addDecorator添加进去,然后在beforeDraw,afterDraw中循环处理,与观察者模式使用有点相似
1.装饰器模式(Decorator),可以动态地添加修改类的功能
2.一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重新实现类的方法
3.使用装饰器模式,仅需在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性
DrawDecorator.php

<?php  
namespace IMooc;  
  
interface DrawDecorator  
{  
    function beforeDraw();  
    function afterDraw();  
}  
Canvas.php
<?php  
namespace IMooc;  
  
class Canvas  
{  
    public $data;  
    protected $decorators = array();  
  
    //Decorator  
    function init($width = 20, $height = 10)  
    {  
        $data = array();  
        for($i = 0; $i < $height; $i++)  
        {  
            for($j = 0; $j < $width; $j++)  
            {  
                $data[$i][$j] = '*';  
            }  
        }  
        $this->data = $data;  
    }  
  
    function addDecorator(DrawDecorator $decorator)  
    {  
        $this->decorators[] = $decorator;  
    }  
  
    function beforeDraw()  
    {  
        foreach($this->decorators as $decorator)  
        {  
            $decorator->beforeDraw();  
        }  
    }  
  
    function afterDraw()  
    {  
        $decorators = array_reverse($this->decorators);  
        foreach($decorators as $decorator)  
        {  
            $decorator->afterDraw();  
        }  
    }  
  
    function draw()  
    {  
        $this->beforeDraw();  
        foreach($this->data as $line)  
        {  
            foreach($line as $char)  
            {  
                echo $char;  
            }  
            echo "<br />\n";  
        }  
        $this->afterDraw();  
    }  
  
    function rect($a1, $a2, $b1, $b2)  
    {  
        foreach($this->data as $k1 => $line)  
        {  
            if ($k1 < $a1 or $k1 > $a2) continue;  
            foreach($line as $k2 => $char)  
            {  
                if ($k2 < $b1 or $k2 > $b2) continue;  
                $this->data[$k1][$k2] = ' ';  
            }  
        }  
    }  
}  

ColorDrawDecorator.php

<?php  
namespace IMooc;  
  
class ColorDrawDecorator implements DrawDecorator  
{  
    protected $color;  
    function __construct($color = 'red')  
    {  
        $this->color = $color;  
    }  
    function beforeDraw()  
    {  
        echo "<div style='color: {$this->color};'>";  
    }  
    function afterDraw()  
    {  
        echo "</div>";  
    }  
}  

index.php

<?php  
define('BASEDIR', __DIR__);  
include BASEDIR.'/IMooc/Loader.php';  
spl_autoload_register('\\IMooc\\Loader::autoload');  
   
$canvas = new IMooc\Canvas();  
$canvas->init();  
$canvas->addDecorator(new \IMooc\ColorDrawDecorator('green'));  
$canvas->rect(3,6,4,12);  
$canvas->draw();  
 

相关文章:

  • PHP ob缓存页面静态化技术
  • 伪静态以及应用(rewrite)
  • 服务器表单处理
  • PHP+JQ实现ajax
  • PHP+JS实现Ajax
  • 从输入url到显示网页,后台发生了什么?
  • array_map,array_walk,array_filter的区别
  • ThinkPHP5.0的助手函数汇总
  • PHP实现微信支付流程分享
  • PHP开发微信支付和支付宝支付实例
  • PHP微信支付开发之微信退款功能示例
  • Yii2.0数据库join关联查询
  • python 读写、创建 文件
  • TMUX会话的使用
  • Git远程操作详解
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • CAP理论的例子讲解
  • ES6语法详解(一)
  • ES学习笔记(10)--ES6中的函数和数组补漏
  • java概述
  • Joomla 2.x, 3.x useful code cheatsheet
  • JS正则表达式精简教程(JavaScript RegExp 对象)
  • OSS Web直传 (文件图片)
  • Python学习之路13-记分
  • SwizzleMethod 黑魔法
  • webpack入门学习手记(二)
  • 大型网站性能监测、分析与优化常见问题QA
  • 当SetTimeout遇到了字符串
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 马上搞懂 GeoJSON
  • 使用API自动生成工具优化前端工作流
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 一文看透浏览器架构
  • 转载:[译] 内容加速黑科技趣谈
  • nb
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • ​queue --- 一个同步的队列类​
  • #Linux杂记--将Python3的源码编译为.so文件方法与Linux环境下的交叉编译方法
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • #在 README.md 中生成项目目录结构
  • $(selector).each()和$.each()的区别
  • (zt)最盛行的警世狂言(爆笑)
  • (二)springcloud实战之config配置中心
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (附源码)基于SSM多源异构数据关联技术构建智能校园-计算机毕设 64366
  • (学习日记)2024.01.09
  • (转)大道至简,职场上做人做事做管理
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • ***测试-HTTP方法
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .net连接MySQL的方法
  • .NET中的Event与Delegates,从Publisher到Subscriber的衔接!
  • :O)修改linux硬件时间