设计模式六大原则

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

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

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

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

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

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

1.单例设计模式(Singleton)

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

应用场景:

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

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

单例类不能直接实例化创建,而是只能由类本身实例化。因此,要获得这样的限制效果,构造函数必须标记为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.工厂设计模式

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

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

使用场景:使用方法 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 "2014新款女装";  
    }  
    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();

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常见的设计模式的更多相关文章

  1. Android开发中常见的设计模式 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  2. iOS开发——高级篇——iOS中常见的设计模式(MVC/单例/委托/观察者)

    关于设计模式这个问题,在网上也找过一些资料,下面是我自己总结的,分享给大家 如果你刚接触设计模式,我们有好消息告诉你!首先,多亏了Cocoa的构建方式,你已经使用了许多的设计模式以及被鼓励的最佳实践. ...

  3. Android开发中常见的设计模式

    对于开发人员来说,设计模式有时候就是一道坎,但是设计模式又非常有用,过了这道坎,它可以让你水平提高一个档次.而在android开发中,必要的了解一些设计模式又是非常有必要的.对于想系统的学习设计模式的 ...

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

    --------------------- 本文来自 旭日Follow_24 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/xuri24/article/detail ...

  5. Android开发中常见的设计模式(二)——Builder模式

    了解了单例模式,接下来介绍另一个常见的模式--Builder模式. 那么什么是Builder模式呢.通过搜索,会发现大部分网上的定义都是 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建 ...

  6. iOS中常见的设计模式(MVC/单例/委托/观察者)

    关于设计模式这个问题,在网上也找过一些资料,下面是我自己总结的,分享给大家 如果你刚接触设计模式,我们有好消息告诉你!首先,多亏了Cocoa的构建方式,你已经使用了许多的设计模式以及被鼓励的最佳实践. ...

  7. python实现常见的设计模式

    Pyhton实现常用的23种设计模式[详解] 关注公众号[轻松学编程],回复[设计模式],获取本文源代码. 在文章末尾可以扫码关注公众号. 一.概念 软件工程中,设计模式是指软件设计问题的推荐方案. ...

  8. php五种常见的设计模式(转载)

    很多人都想着写博客来记录编程生活中的点滴,我也不例外,但想了好长时间不知道写什么........万事开头难,先转载一篇吧..... 设计模式 一书将设计模式引入软件社区,该书的作者是 Erich Ga ...

  9. iOS中常见的设计模式——单例模式\委托模式\观察者模式\MVC模式

    一.单例模式 1. 什么是单例模式? 在iOS应用的生命周期中,某个类只有一个实例. 2. 单例模式解决了什么问题? 想象一下,如果我们要读取文件配置信息,那么每次要读取,我们就要创建一个文件实例,然 ...

随机推荐

  1. MyBatis 回顾 JDBC(一)

    引言 学过 Java 的童鞋都知道,在 Java 中只有 JDBC 可以访问数据库,但是只要使用过 JDBC 的同学肯定也感受到 JDBC 访问数据库的繁琐, 需要编写大量的代码,经历一系列的步骤. ...

  2. 设置添加SSH-(转自破男孩)

    很多朋友在用github管理项目的时候,都是直接使用https url克隆到本地,当然也有有些人使用 SSH url 克隆到本地.然而,为什么绝大多数人会使用https url克隆呢? 这是因为,使用 ...

  3. 7.6 passwd:修改用户密码

    7.6 passwd:修改用户密码     passwd命令可以修改用户密码及密码过期时间等内容,是工作中很常用的命令.普通用户和超级用户都可以运行passwd命令,但普通用户只能更改自身的用户密码, ...

  4. ExpressionHelp2

    public static class ExpressionHelp { private static Expression<T> Combine<T>(this Expres ...

  5. 『动善时』JMeter基础 — 26、使用txt文件实现JMeter参数化

    目录 1.测试计划中的元件 2.数据文件内容 3.线程组元件内容 4.HTTP信息头管理器组件内容 5.CSV数据文件设置组件内容 6.HTTP请求组件内容 7.脚本运行结果 之前我们都是使用.csv ...

  6. CVPR2020:点云三维目标跟踪的点对盒网络(P2B)

    CVPR2020:点云三维目标跟踪的点对盒网络(P2B) P2B: Point-to-Box Network for 3D Object Tracking in Point Clouds 代码:htt ...

  7. Waymo的激光雷达计划:进展如何?

    Waymo的激光雷达计划:进展如何? Waymo's Lidar Plan: How's It Working out? 许多自动驾驶汽车(AV)开发商一直在热烈追求激光雷达技术,这一技术之所以重要, ...

  8. Python小白的数学建模课-06 固定费用问题

    Python 实例介绍固定费用问题的建模与求解. 学习 PuLP工具包中处理复杂问题的快捷使用方式. 『Python小白的数学建模课 @ Youcans』带你从数模小白成为国赛达人. 前文讲到几种典型 ...

  9. 编译原理-一种词法分析器LEX原理

    1.将所有单词的正规集用正规式描述 2.用正规式到NFA的转换算 得到识别所有单词用NFA 3.用NFA到DFA的转换算法 得到识别所有单词用DFA 4.将DFA的状态转换函数表示成二维数组 并与DF ...

  10. WebRTC 传输安全机制第二话:深入显出 SRTP 协议

    通过 DTLS 协商后,RTC 通信的双方完成 MasterKey 和 MasterSalt 的协商.接下来,我们继续分析在 WebRTC 中,如何使用交换的密钥,来对 RTP 和 RTCP 进行加密 ...