php常见开发模式

来源:互联网 发布:centos 安装无线网卡 编辑:程序博客网 时间:2024/06/06 02:14

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,即是特定环境下同类问题的一种解决方案。使用设计模式是为了可重用代码、让代码灵活易维护、扩展方便,降低耦合,保证代码可靠性。

1、单例模式

单例模式顾名思义,就是只有一个实例。作为对象的创建模式, 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

单例模式的要点有三个:

  1. 一是某个类只能有一个实例;
  2. 二是它必须自行创建这个实例;
  3. 三是它必须自行向整个系统提供这个实例。
为什么要使用PHP单例模式
  1. php的应用主要在于数据库应用, 一个应用中会存在大量的数据库操作, 在使用面向对象的方式开发时, 如果使用单例模式, 则可以避免大量的new创建对象操作消耗的资源,还可以减少数据库连接这样就不容易出现 too many connections情况。
  2. 如果系统中需要有一个类来全局控制某些配置信息, 那么使用单例模式可以很方便的实现. 这个可以参看zend Framework的FrontController和CI的CI_controller。
  3. 在一次页面请求中, 便于进行调试, 因为所有的代码(例如数据库操作类db)都集中在一个类中, 我们可以在类中设置钩子, 输出日志,从而避免到处var_dump, echo。

例子:

/**
 * 设计模式之单例模式
 * $_instance必须声明为静态的私有变量
 * 构造函数必须声明为私有,防止外部程序new类从而失去单例模式的意义
 * getInstance()方法必须设置为公有的,必须调用此方法以返回实例的一个引用
 * ::操作符只能访问静态属性和静态函数
 * new对象都会消耗内存
 * 使用场景:最常用的地方是数据库连接。
 * 使用单例模式生成一个对象后,该对象可以被其它众多对象所使用。
 
*/

class man
{
    //保存例实例在此属性中
    private static $_instance;
    //构造函数声明为private,防止直接创建对象
    private function __construct()
    {
        echo '我被实例化了!';
    }
    //单例方法
    public static function get_instance()
    {
if(!isset(self::$_instance))
        {
            self::$_instance=new self();
        }
        return self::$_instance;
    }

    //阻止用户复制对象实例
    private function __clone()
    {
        trigger_error('Clone is not allow' ,E_USER_ERROR);
    }

    function test()
    {
        echo("test");
    }
}
// 这个写法会出错,因为构造方法被声明为private
//$test = new man;
// 下面将得到Example类的单例对象
$test = man::get_instance();
$test->test();

// 复制对象将导致一个E_USER_ERROR.
//$test_clone = clone $test;

2、工厂模式

工厂模式 是一种类,它具有为您创建对象的某些方法。您可以使用工厂类创建对象,而不直接使用 new。这样,如果您想要更改所创建的对象类型,只需更改该工厂即可。使用该工厂的所有代码会自动更改。


    /**
     * 
     * 定义个抽象的类,让子类去继承实现它
     *
     
*/
     abstract class Operation{
         //抽象方法不能包含函数体
         abstract public function getValue($num1,$num2);//强烈要求子类必须实现该功能函数
     }
     /**
      * 加法类
      
*/
     class OperationAdd extends Operation {
         public function getValue($num1,$num2){
             return $num1+$num2;
         }
     }
     /**
      * 减法类
      
*/
     class OperationSub extends Operation {
         public function getValue($num1,$num2){
             return $num1-$num2;
         }
     }
     /**
      * 乘法类
      
*/
     class OperationMul extends Operation {
         public function getValue($num1,$num2){
             return $num1*$num2;
         }
     }
     /**
      * 除法类
      
*/
     class OperationDiv extends Operation {
         public function getValue($num1,$num2){
             try {
                 if ($num2==0){
                     throw new Exception("除数不能为0");
                 }else {
                     return $num1/$num2;
                 }
             }catch (Exception $e){
                 echo "错误信息:".$e->getMessage();
             }
         }
     }


通过采用面向对象的继承特性,我们可以很容易就能对原有程序进行扩展,比如:‘乘方’,‘开方’,‘对数’,‘三角函数’,‘统计’等,以还可以避免加载没有必要的代码。

如果我们现在需要增加一个求余的类,会非常的简单,我们只需要另外写一个类(该类继承虚拟基类),在类中完成相应的功能(比如:求乘方的运算),而且大大的降低了耦合度,方便日后的维护及扩展

    /**
     * 求余类(remainder)
     *
     
*/
    class OperationRem extends Operation {
        public function getValue($num1,$num2){
            return $num1%$num12;
        }
    }

现在还有一个问题未解决,就是如何让程序根据用户输入的操作符实例化相应的对象呢?
解决办法:使用一个单独的类来实现实例化的过程,这个类就是工厂

    /**
     * 工厂类,主要用来创建对象
     * 功能:根据输入的运算符号,工厂就能实例化出合适的对象
     *
     
*/
    class Factory{
        public static function createObj($operate){
            switch ($operate){
                case '+':
                    return new OperationAdd();
                    break;
                case '-':
                    return new OperationSub();
                    break;
                case '*':
                    return new OperationSub();
                    break;
                case '/':
                    return new OperationDiv();
                    break;
            }
        }
    }
    $test=Factory::createObj('/');
    $result=$test->getValue(23,0);
    echo $result;


3、观察者模式

观察者模式属于行为模式,观察者模式定义了对象间的一种一对多的依赖关系,当被观察的对象发生改变时,所有依赖于它的对象都会得到通知并被自动更新,而且被观察的对象和观察者之间是松耦合的。在该模式中,有目标(Subject)和观察者(Observer)两种角色。目标角色是被观察的对象,持有并控制着某种状态,可以被任意多个观察者作为观察的目标,SPL(Standard PHP Library即标准 PHP 库,是 PHP 5 在面向对象上能力提升的真实写照,它由一系列内置的类、接口和函数构成。) 中使用 SplSubject接口规范了该角色的行为。

一个对象通过添加一个方法(该方法允许另一个对象,即观察者注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可以相互对话,而不必了解原因。

  1. <?php  
  2. interface IObserver  //定义个一个接口  
  3. {  
  4.   function onChanged( $sender$args );  
  5. }  
  6.   
  7. interface IObservable //定义个二个接口  
  8. {  
  9.   function addObserver( $observer );  
  10. }  
  11.   
  12. class UserList implements IObservable //继承第二个接口  
  13. {  
  14.   private $_observers = array();  
  15.   
  16.   public function addCustomer( $name )  
  17.   {  
  18.     foreach$this->_observers as $obs )  
  19.       $obs->onChanged( $this$name );//调用观察者接口来使用多个接口  
  20.   }  
  21.   
  22.   public function addObserver( $observer ) //添加观察者模式接口  
  23.   {  
  24.     $this->_observers []= $observer;  
  25.   }  
  26. }  
  27.   
  28. class UserListLogger implements IObserver //继承第一个接口  
  29. {  
  30.   public function onChanged( $sender$args )   
  31.   {  
  32.     echo"'$args' added to user list/n" );  
  33.   }  
  34. }  
  35.   
  36. class UserListLogger2 implements IObserver //继承第一个接口2  
  37. {  
  38.   public function onChanged( $sender$args )  
  39.   {  
  40.     echo"'$args' 2222222222222222 list/n" );  
  41.   }  
  42. }  
  43.   
  44. $ul = new UserList();  
  45. $ul->addObserver( new UserListLogger() );  
  46. $ul->addObserver( new UserListLogger2() );  
  47. $ul->addCustomer( "Jack" );  
  48. ?> 


4、策略模式

策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换。

至少在在以下两种情况下,大家可以考虑使用策略模式,

  • 几个类的主要逻辑相同,只在部分逻辑的算法和行为上稍有区别的情况。
  • 有几种相似的行为,或者说算法,客户端需要动态地决定使用哪一种,那么可以使用策略模式,将这些算法封装起来供客户端调用。

interface IStrategy {
public function doSomething();
}

class Strategy1 implements IStrategy {
public function doSomething(){
echo '具体策略1';
}
}
class Strategy2 implements IStrategy {
public function doSomething(){
echo '具体策略2';
}
}
class Context {
private $strategy;
public function __construct(IStrategy $strategy){
$this->strategy = $strategy;
}

public function execute(){
$this->strategy->doSomething();
}
}

$context = new Context(new Strategy1);
$context->execute();

$context = new Context(new Strategy2);
$context->execute();

      策略模式的主要优点有:

  • 策略类之间可以自由切换,由于策略类实现自同一个抽象,所以他们之间可以自由切换。
  • 易于扩展,增加一个新的策略对策略模式来说非常容易,基本上可以在不改变原有代码的基础上进行扩展。
  • 避免使用多重条件,如果不使用策略模式,对于所有的算法,必须使用条件语句进行连接,通过条件判断来决定使用哪一种算法,在上一篇文章中我们已经提到,使用多重条件判断是非常不容易维护的。

       策略模式的缺点主要有两个:

  • 维护各个策略类会给开发带来额外开销,可能大家在这方面都有经验:一般来说,策略类的数量超过5个,就比较令人头疼了。
  • 必须对客户端(调用者)暴露所有的策略类,因为使用哪种策略是由客户端来决定的,因此,客户端应该知道有什么策略,并且了解各种策略之间的区别,否则,后果很严重。例如,有一个排序算法的策略模式,提供了快速排序、冒泡排序、选择排序这三种算法,客户端在使用这些算法之前,是不是先要明白这三种算法的适用情况?再比如,客户端要使用一个容器,有链表实现的,也有数组实现的,客户端是不是也要明白链表和数组有什么区别?就这一点来说是有悖于迪米特法则的。

5、命令链模式

命令链模式以松散耦合主题为基础,发送消息、命令和请求,或通过一组处理程序发送任意内容。每个处理程序都会自行判断自己能否处理请求。如果可以,该请求被处理,进程停止。您可以为系统添加或移除处理程序,而不影响其他处理程序。

总体来说命令链模式就是让系统定义多个执行接口,而通过一个命令链接口来执行!

  1. <?php  
  2. interface ICommand   //定义一个接口  
  3. {  
  4.   function onCommand( $name$args );  
  5. }  
  6.   
  7. class CommandChain  //一个命令链接口类  
  8. {  
  9.   private $_commands = array();  
  10.   
  11.   public function addCommand( $cmd )//增加命令链接口  
  12.   {  
  13.     $this->_commands []= $cmd;  
  14.   }  
  15.   
  16.   public function runCommand( $name$args )//执行命令链函数接口  
  17.   {  
  18.     foreach$this->_commands as $cmd )  
  19.     {  
  20.       if ( $cmd->onCommand( $name$args ) )  
  21.         return;  
  22.     }  
  23.   }  
  24. }  
  25.   
  26. class UserCommand implements ICommand  //定义一个接口类  
  27. {  
  28.   public function onCommand( $name$args )  
  29.   {  
  30.     if ( $name != 'addUser' ) return false;  
  31.     echo"UserCommand handling 'addUser'/n" );  
  32.     return true;  
  33.   }  
  34. }  
  35.   
  36. class MailCommand implements ICommand  //定义一个接口类  
  37. {  
  38.   public function onCommand( $name$args )  
  39.   {  
  40.     if ( $name != 'mail' ) return false;  
  41.     echo"MailCommand handling 'mail'/n" );  
  42.     return true;  
  43.   }  
  44. }  
  45.   
  46. $cc = new CommandChain();  
  47. $cc->addCommand( new UserCommand() );  
  48. $cc->addCommand( new MailCommand() );  
  49. $cc->runCommand( 'addUser', null );  
  50. $cc->runCommand( 'mail', null );  
  51. ?> 


        工厂模式与策略模式的主要差异:

        1、作用

         工厂模式主要的用途是创建对象,根据在客户端传入一个数据,在工厂类中创建相应的对象,然后返回给客户端,它使对象的创建独立于使用对象的客户,它属于创建型模型;

         策略模式主要用于选择策略方法,在客户端中根据你所选择的行为或者策略创建一个对象。策略模式就是为了解决策略的切换和扩展,它定义了策略族,并将它们封装起来,策略模式将策略的变换独立于使用策略的客户,它属于行为型模型;

        2、关注点

        工厂模式关注的是对象的创建

        策略模式关注的是行为的封装


       另外在这里引用两个我在CSDN的帖子里面看到认为比较能让我找到感觉的例子,在此非常感觉写出这个例子的大神。

       一、

       女人有很多种,基本都会生孩子。(不要在意例子本身不雅,注意体会其含义)
       1、找个会生孩子的身材好的女人。(如何找的逻辑就交给女人工厂了,客户端只要得到女人就可以了)。
       2、找个身材好的女人代孕生个孩子,当然到最后只要孩子不要女人。(如何在多种女人中找个身材好的女人代孕生孩子是策略类的职责,最后策略类只要把孩子交给客户端即可)。

      二、

      工厂模式:根据你给出的目的来生产不同用途的斧子,例如要砍人,那么工厂生产砍人斧子,要伐木就生产伐木斧子。即根据你给出一些属性来生产不同行为的一类对象返回给你。关注对象创建
      策略模式:用工厂生产的斧子来做对应的事情,例如用砍人的斧子来砍人,用伐木的斧子来伐木。即根据你给出对应的对象来执行对应的方法。关注行为的选择


0 0
原创粉丝点击