设计模式六大原则

开放封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

里氏替换原则:所有引用基类的地方必须能透明地使用其子类的对象.

依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。

单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。

接口隔离原则:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。

迪米特法则:一个对象应该对其他对象保持最少的了解。

1.单例设计模式

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

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

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

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

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

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

使用场景:只实例化一次,内部实例化,对外只有一个开放方法,只能通过调取该方法进行调取实例化对象。数据库连接

单例模式的例子:

<?php  

/** 
* Singleton of Database 
*/  
class Database  
{  
  // We need a static private variable to store a Database instance.  
  private static $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.工厂设计模式

工厂模式是另一种非常常用的模式,正如其名字所示:确实是对象实例的生产工厂。某些意义上,工厂模式提供了通用的方法有助于我们去获取对象,而不需要关心其具体的内在的实现

使用场景:使用方法 new实例化类,每次实例化只需调用工厂类中的方法实例化即可。

我们举例子,假设矩形、圆都有同样的一个方法,那么我们用基类提供的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.策略模式

将一组特定的行为和算法封装成类,以适应某些特定的上下文环境。

例如:一个电商网站系统,针对男性女性用户要各自跳转到不同的商品类目,并且所有广告位展示不同的广告

MaleUserStrategy.php

<?php   
namespace IMooc;  
class MaleUserStrategy implements UserStrategy  {  
    function showAd()  
    {  
        echo "IPhone6";  
    }       function showCategory()  
    {  
        echo "电子产品";  
    }  
}   

FemaleUserStrategy.php

<?php   
namespace IMooc;  
class FemaleUserStrategy implements UserStrategy {  
    function showAd()  
    {  
        echo "2017新款女装";  
    }  
    function showCategory()  
    {  
        echo "女装";  
    }  
}   

UserStrategy.php

<?php   
namespace IMooc;  
interface UserStrategy {  
    function showAd();  
    function showCategory();  
}     

 

<?php  
interface FlyBehavior{  
    public function fly();  
}   class FlyWithWings implements FlyBehavior{  
    public function fly(){  
        echo "Fly With Wings \n";  
    }  
}   class FlyWithNo implements FlyBehavior{  
    public function fly(){  
        echo "Fly With No Wings \n";  
    }  
}  
class Duck{  
    private $_flyBehavior;  
    public function performFly(){  
        $this->_flyBehavior->fly();  
    }       public function setFlyBehavior(FlyBehavior $behavior){  
        $this->_flyBehavior = $behavior;  
    }  
}   class RubberDuck extends Duck{  
}  
// Test Case  
$duck = new RubberDuck();   /*  想让鸭子用翅膀飞行 */  
$duck->setFlyBehavior(new FlyWithWings());  
$duck->performFly();               /*  想让鸭子不用翅膀飞行 */  
$duck->setFlyBehavior(new FlyWithNo());  
$duck->performFly();      

PHP常用的 五种设计模式及应用场景的更多相关文章

  1. iOS App之间常用的五种通信方式及适用场景总结

    iOS系统是相对封闭的系统,App各自在各自的沙盒(sandbox)中运行,每个App都只能读取iPhone上iOS系统为该应用程序程序创建的文件夹AppData下的内容,不能随意跨越自己的沙盒去访问 ...

  2. iOS日常学习 - App之间常用的五种通信方式及适用场景总结

    本文为转载学习,原文地址 iOS系统是相对封闭的系统,App各自在各自的沙盒(sandbox)中运行,每个App都只能读取iPhone上iOS系统为该应用程序程序创建的文件夹AppData下的内容,不 ...

  3. 关于W3Cschool定义的设计模式-常用的9种设计模式的介绍

    一.设计模式 tip:每种设计模式,其实都是为了更高效的,更方便的解决在面对对象编程中所遇到的问题. 什么是设计模式:     是一套经过反复使用.多人知晓的.经过分类的.代码设计经验的总结   为什 ...

  4. Java常用的几种设计模式

    本来想写点spring相关的东西的,想来想去,先写点设计模式的东西吧 什么是设计模式?套用百度百科的话解释吧 设计模式(Design Pattern)是一套被反复使用.多数人知晓的.经过分类的.代码设 ...

  5. APP界面常用的五种颜色搭配

    众所周知,每一种颜色带给用户的视觉感受也是不同的.现在人们对手机的依赖程度,就能看到手机中APP的发展前景,那今天就跟大家聊聊如何通过颜色搭配的不同来进行移动端APP界面的布局和排版设计.移动端UI界 ...

  6. PHP中常见的五种设计模式

    设计模式只是为 Java架构师准备的 — 至少您可能一直这样认为.实际上,设计模式对于每个人都非常有用.如果这些工具不是 “架构太空人” 的专利,那么它们又是什么?为什么说它们在 PHP 应用程序中非 ...

  7. PHP常用的三种设计模式

    本文为大家介绍常用的三种php设计模式:单例模式.工厂模式.观察者模式,有需要的朋友可以参考下. 一.首先来看,单例模式 所谓单例模式,就是确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实 ...

  8. php常用几种设计模式的应用场景

    1.单例设计模式 所谓单例模式,即在应用程序中最多只有该类的一个实例存在,一旦创建,就会一直存在于内存中! 单例设计模式常应用于数据库类设计,采用单例模式,只连接一次数据库,防止打开多个数据库连接. ...

  9. iOS开发中数组常用的五种遍历方式

    随着iOS的不断发展,apple也不断推出性能更高的数组遍历方式,下面将对熟悉的五种遍历方式进行列举. 首先定义一个数组,并获取数组长度 NSArray *array=@[",]; NSIn ...

随机推荐

  1. java 使用poi读取word文档存入数据库

    使用的poi jar包需要自己下载 读取的word文档中含有多个图片,所以分为两个部分,一个部分读取各个表格中内容,一个是将所有图片截取出来: /** * 遍历段落内容 * docxReadPath ...

  2. OI视角浅谈布隆过滤器

    简要谈及布隆过滤器 Preface 不负责的出题人扔了一道5e5,2M卡内存的题,标算布隆过滤器,然而std自己用std::set 70M碾过去了. 没学OI时候草草看过这个,不过忘得差不多了. 今天 ...

  3. 【Wince-ListView】Wince中的 ListView怎么显示网格?

    using System.Runtime.InteropServices; using System.Windows.Forms; namespace CETEST { public class Co ...

  4. ant-design-vue 报错 ReferenceError: h is not defined

    使用表格,在配置 columns时用到了 customRender,然后就报错了 <script> import FileName from '@/views/admin/document ...

  5. SuperSocket框架的系列博文

    官方文档 http://docs.supersocket.net/v1-6/zh-CN 对于我等小白,此系列博文,受益匪浅,慢慢看 https://www.cnblogs.com/fly-bird/c ...

  6. Java进阶知识01 Struts2下的 jquery+ajax+struts 技术实现异步刷新功能

    1.效果图示 横线上方的部分不动(没有刷新),下方实现刷新(异步刷新) 2.实现步骤 jquery+ajax+struts技术实现异步刷新功能的步骤:    1.需要用到 jquery+ajax+st ...

  7. 深度理解链式前向星——转载自ACdreamer

      转载自ACdreamer [转载]深度理解链式前向星 我们首先来看一下什么是前向星. 前向星是一种特殊的边集数组,我们把边集数组中的每一条边按照起点从小到大排序,如果起点相同就按照终点从小到大排序 ...

  8. CUDA-F-2-2-核函数计时

    Abstract: 本文介绍CUDA核函数计时方法 Keywords: gettimeofday,nvprof 开篇废话 继续更新CUDA,同时概率和数学分析也在更新,欢迎大家访问www.face2a ...

  9. delphi请求http接口并上传附件

    实现附件的上传:需要使用TIdMultiPartFormDataStream控件, uses IdMultipartFormData; 例子: procedure TClientForm.Button ...

  10. vue刷新子页面,跳到主页,params传参引起的血案!

    今天,算是真正认识了params传参,为什么说params传参引起了血案? 起因是这样的,我正在做一个登陆的模块,公司想根据url不同的参数来区分是什么类型的会议, 于是后端推荐我用params传参的 ...