五种常见的 PHP 设计模式

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

      设计模式不仅代表着更快开发健壮软件的有用方法,而且还提供了以友好的术语封装大型理念的方法。例如,您可以说您正在编写一个提供松散耦合的消息传递系统,也可以说你正在编写名称为观察者 的模式。
      用较小的示例展示模式的价值是非常困难的。这往往有些大材小用的意味,因为模式实际上是在大型代码库中发挥作用的。本文不展示大型应用程序,所以您需要思索的是在您自己的大型应用程序中应用示例原理的方法 ——而不是本文演示的代码本身。这不是说您不应该在小应用程序中使用模式。很多良好的应用程序都以小应用程序为起点,逐渐发展到大型应用程序,所以没有理由不以此类扎实的编码实践为基础。
既然您已经了解了设计模式以及它们的有用之处,现在我们来看看 PHP5 的五种常用模式。


工厂模式

      最初在设计模式 一书中,许多设计模式都鼓励使用松散耦合。要理解这个概念,让我们最好谈一下许多开发人员从事大型系统的艰苦历程。在更改一个代码片段时,就会发生问题,系统其他部分 —— 您曾认为完全不相关的部分中也有可能出现级联破坏。
该问题在于紧密耦合 。系统某个部分中的函数和类严重依赖于系统的其他部分中函数和类的行为和结构。您需要一组模式,使这些类能够相互通信,但不希望将它们紧密绑定在一起,以避免出现联锁。
      在大型系统中,许多代码依赖于少数几个关键类。需要更改这些类时,可能会出现困难。例如,假设您有一个从文件读取的 User 类。您希望将其更改为从数据库读取的其他类,但是,所有的代码都引用从文件读取的原始类。这时候,使用工厂模式会很方便。
工厂模式 是一种类,它具有为您创建对象的某些方法。您可以使用工厂类创建对象,而不直接使用 new。这样,如果您想要更改所创建的对象类型,只需更改该工厂即可。使用该工厂的所有代码会自动更改。
      清单 1 显示工厂类的一个示列。等式的服务器端包括两个部分:数据库和一组 PHP页面,这些页面允许您添加反馈、请求反馈列表并获取与特定反馈相关的文章。

清单 1. Factory1.php
<?php
interface IUser
{
  function getName();
}

class User implements IUser
{
  public function __construct( $id ) { }

  public function getName()
  {
    return “Jack”;
  }
}

class UserFactory
{
  public static function Create( $id )
  {
    return new User( $id );
  }
}

$uo = UserFactory::Create( 1 );
echo( $uo->getName().”\n” );
?>

      IUser 接口定义用户对象应执行什么操作。IUser 的实现称为 User,UserFactory 工厂类则创建 IUser 对象。此关系可以用图 1 中的 UML 表示。

图 1. 工厂类及其相关 IUser 接口和用户类

      如果您使用 php 解释器在命令行上运行此代码,将得到如下结果:
      测试代码会向工厂请求 User 对象,并输出 getName 方法的结果。
            % php factory1.php
            Jack
            %

      有一种工厂模式的变体使用工厂方法。类中的这些公共静态方法构造该类型的对象。如果创建此类型的对象非常重要,此方法非常有用。例如,假设您需要先创建对象,然后设置许多属性。此版本的工厂模式会将该进程封装在单个位置中,这样,不用复制复杂的初始化代码,也不必将复制好的代码在在代码库中到处粘贴。
      清单 2 显示使用工厂方法的一个示例。

清单 2. Factory2.php

<?php
interface IUser<
br />{
  function getName();
}

class User implements IUser
{
  public static function Load( $id )
  {
        return new User( $id );
  }

  public static function Create( )
  {
        return new User( null );
  }

  public function __construct( $id ) { }

  public function getName()
  {
    return “Jack”;
  }
}

$uo = User::Load( 1 );
echo( $uo->getName().”\n” );
?>

      这段代码要简单得多。它仅有一个接口 IUser 和一个实现此接口的 User 类。User 类有两个创建对象的静态方法。此关系可用图 2 中的 UML 表示。

图 2. IUser 接口和带有工厂方法的 user 类

      在命令行中运行脚本产生的结果与清单 1 的结果相同,如下所示:
                % php factory2.php
            Jack
            %

      如上所述,有时此类模式在规模较小的环境中似乎有些大材小用。不过,最好还是学习这种扎实的编码形式,以便应用于任意规模的项目中。

单元素模式

      某些应用程序资源是独占的,因为有且只有一个此类型的资源。例如,通过数据库句柄到数据库的连接是独占的。您希望在应用程序中共享数据库句柄,因为在保持连接打开或关闭时,它是一种开销,在获取单个页面的过程中更是如此。

      单元素模式可以满足此要求。如果应用程序每次包含且仅包含一个对象,那么这个对象就是一个单元素(Singleton)。清单 3 中的代码显示了 PHP V5 中的一个数据库连接单元素。

清单 3. Singleton.php
<?php
require_once(“DB.php”);

class DatabaseConnection
{
  public static function get()
  {
    static $db = null;
    if ( $db == null )
      $db = new DatabaseConnection();
    return $db;
  }

  private $_handle = null;

  private function __construct()
  {
    $dsn = ‘mysql://root:password@localhost/photos’;
    $this->_handle =& DB::Connect( $dsn, array() );
  }
  
  public function handle()
  {
    return $this->_handle;
  }
}

print( “Handle = “.DatabaseConnection::get()->handle().”\n” );
print( “Handle = “.DatabaseConnection::get()->handle().”\n” );
?>

      此代码显示名为 DatabaseConnection 的单个类。您不能创建自已的 DatabaseConnection,因为构造函数是专用的。但使用静态 get 方法,您可以获得且仅获得一个 DatabaseConnection 对象。此代码的 UML 如图 3 所示。

图 3. 数据库连接单元素

      在两次调用间,handle 方法返回的数据库句柄是相同的,这就是最好的证明。您可以在命令行中运行代码来观察这一点。
            % php singleton.php
            Handle = Object id #3
            Handle = Object id #3
            %

      返回的两个句柄是同一对象。如果您在整个应用程序中使用数据库连接单元素,那么就可以在任何地方重用同一句柄。
      您可以使用全局变量存储数据库句柄,但是,该方法仅适用于较小的应用程序。在较大的应用程序中,应避免使用全局变量,并使用对象和方法访问资源。

观察者模式

      观察者模式为您提供了避免组件之间紧密耦合的另一种方法。该模式非常简单:一个对象通过添加一个方法(该方法允许另一个对象,即观察者 注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可以相互对话,而不必了解原因。

      一个简单示例是系统中的用户列表。清单 4 中的代码显示一个用户列表,添加用户时,它将发送出一条消息。添加用户时,通过发送消息的日志观察者可以观察此列表。

清单 4. Observer.php
[php]<?php
interface IObserver
{
  function onChanged( $sender, $args );
}

interface IObservable
{
  function addObserver( $observer );
}

class UserList implements IObservable
{
  private $_observers = array();

  public function addCustomer( $name )
  {
    foreach( $this->_observers as $obs )
      $obs->onChanged( $this, $name );
  }

  public function addObserver( $observer )
  {
    $this->_observers []= $observer;
  }
}

class UserListLogger implements IObserver
{
  public function onChanged( $sender, $args )
  {
    echo( “‘$args’ added to user list\n” );
  }
}

$ul = new UserList();
$ul->addObserver( new UserListLogger() );
$ul->addCustomer( “Jack” );
?>[/php]

      此代码定义四个元素:两个接口和两个类。IObservable 接口定义可以被观察的对象,UserList

Share
分类: PHP开发,设计模式 标签: PHP

MVP观察者模式

2009年10月13日 scofield 没有评论

从网上找的两段代码。很好的诠释了MVP观察者模式。

这两段代码可以看成是两个小小的框架了。

从中学习下MVP观察者模式的思想。很有帮助的。

 

java代码

 

//主题基类
import java.util.Vector;
public abstract class Subject {
    //观察者列表
    private Vector<Observer> vectObserver = new Vector<Observer>();
    //增加一个观察者
    public void attach(Observer observer){
        vectObserver.add(observer);
    }
    //去除一个观察者
    public void detach(Observer observer){
        vectObserver.remove(observer);
    }
    //通知观察者更新
    public void notifyObservers(){
        for(int i=0; i<vectObserver.size(); i++){
            Observer observer = vectObserver.get(i);
            observer.update();
        }
    }    
    //获取主题信息
    public abstract String getSubject();
}
//银行柜台类
public class Counter extends Subject{
    //当前业务号
    private String bizNo;
    //柜台名称
    private String name;
    //构造函数
    public Counter(String name){
        this.name = name;
    }
    //获取当前业务号
    public String getBizNo(){
        return this.bizNo;
    }
    //设置当前业务号
    public void setBizNo(String bizNo){
        this.bizNo = bizNo;
    }
    //获取主题信息
    public String getSubject(){
        return “请” + this.bizNo + “号到” + this.name + “号柜台办理业务”;
    }
}
//管理部门类
public class Manager extends Subject{
    //管理部门名称
    private String name;
    //构造函数
    public Manager(String name){
        this.name = name;
    }
    //获取主题信息
    public String getSubject(){
        return this.name + “发布最新紧急公告”;
    }
}
//观察者基类
public abstract class Observer {
    protected String name;
    protected Subject subject;
    //构造函数
    public Observer(String name,Subject subject){
        this.name = name;
        this.subject = subject;
    }    
    //更新信息
    public abstract void update();
}
//小显示屏类
public class SmallScreen extends Observer{
    //构造函数
    public SmallScreen(String name,Subject subject){
        super(name,subject);
    }    
    //更新显示屏
    public void update(){
        try{
            System.out.println(this.name + “:” + subject.getSubject());
        }
        catch(Exception err){
        }
    }        
}
//音箱类
public class Speaker extends Observer{
    //构造函数
    public Speaker(String name,Subject subject){
        super(name,subject);
    }    
    //更新音箱
    public void update(){
        try{
            System.out.println(this.name + “:” + subject.getSubject());
        }
        catch(Exception err){
        }
    }    
}
//业务系统类
public class BankBiz {
    public static void main(String[] args) {
        //银行柜台
        Counter counter = new Counter(“1号柜台”);
        //1,2号小屏、3号音箱
        SmallScreen smallScreen1 = new SmallScreen(“1号小屏”,counter);
        SmallScreen smallScreen2 = new SmallScreen(“2号小屏”,counter);
        Speaker speaker = new Speaker(“3号音箱”,counter);
        //银行柜台加入观察者
        counter.attach(smallScreen1);
        counter.attach(smallScreen2);
        counter.attach(speaker);
        //9号办理业务
        counter.setBizNo(“9″);
        //通知更新
        counter.notifyObservers();
    
        //管理部门
        Manager manager = new Manager(“风险控制部”);    
        //1号小屏
        smallScreen1 = new SmallScreen(“1号小屏”,manager);        
        //管理部门加入观察者
        manager.attach(smallScreen1);
        //通知更新
        manager.notifyObservers();
    }
}

 

 

 

php代码

 

<?php
//主题基类
abstract class Subject {
    //观察者列表
    private $arrObserver = array();
    //增加一个观察者
    public function attach(&$observer){
        $this->arrObserver[] = $observer;
    }
    //去除一个观察者
    public function detach(&$observer){
        for($i=0; $i<count($this->$arrObserver); $i++){
            $objTemp = $this->$arrObserver[$i];
            if($observer === $objTemp){
                array_splice($this->$arrObserver,$i,1);
                break;
            }
        }
    }
    //通知观察者更新
    public function notifyObservers(){
        foreach ($this->arrObserver as $observer){
            $observer->update();
        }
    }    
    //获取主题信息
    public abstract function getSubject();
}
//银行柜台类
class Counter extends Subject {
    //当前业务号
    private $bizNo = “”;
    //柜台名称
    private $name = “”;
    //构造函数
    public function __construct($name){
        $this->name = $name;
    }
    //获取当前业务号
    public function getBizNo(){
        return $this->bizNo;
    }
    //设置当前业务号
    public function setBizNo($bizNo){
        $this->bizNo = $bizNo;
    }
    //获取主题信息
    public function getSubject(){
        return “请” + $this->bizNo . “号到” . $this->name . “号柜台办理业务”;
    }
}
//管理部门类
class Manager extends Subject{
    //管理部门名称
    private $name = “”;
    //构造函数
    public function __construct($name){
        $this->name = $name;
    }
    //获取主题信息
    public function getSubject(){
        return $this->name . “发布最新紧急公告”;
    }
}
//观察者基类
abstract class Observer {
    protected $name = “”;
    protected $subject = “”;
    //构造函数
    public function __construct($name,$subject){
        $this->name = $name;
        $this->subject = $subject;
    }
    //更新信息
    public abstract function update();
}
//小显示屏类
class SmallScreen extends Observer{
    //构造函数
    public function __construct($name,$subject ){
        parent::__construct($name,$subject);
    }
    //更新显示屏
    public function update(){
        echo $this->name . “:” . $this->subject->getSubject();
    }    
}
//音箱类
class Speaker extends Observer{
    //构造函数
    public function __construct($name,$subject){
        parent::__construct($name,$subject);
    }
    //更新音响
    public function update(){
        echo $this->name . “:” . $this->subject->getSubject();
    }    
}
//业务系统类
class BankBiz {
    public static function execute() {
        //银行柜台
        $counter = new Counter(“1号柜台”);
        //1,2号小屏、3号音箱
        $smallScreen1 = new SmallScreen(“1号小屏”,$counter);
        $smallScreen2 = new SmallScreen(“2号小屏”,$counter);
        $speaker = new Speaker(“3号音箱”,$counter);
        //银行柜台加入观察者
        $counter->attach($smallScreen1);
        $counter->attach($smallScreen2);
        $counter->attach($speaker);
        //9号办理业务
        $counter->setBizNo(“9″);
        //通知更新
        $counter->notifyObservers();
        
        //管理部门
        $manager = new Manager(“风险控制部”);    
        //1号小屏
        $smallScreen1 = new SmallScreen(“1号小屏”,$manager);        
        //管理部门加入观察者
        $manager->attach($smallScreen1);
        //通知更新
        $manager->notifyObservers();        
    }
}
BankBiz::execute();
?>

原文地址: http://www.gosoa.com.cn/category/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F

本文地址:http://blog.csdn.net/aerchi/article/details/42131157
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值