萬盛學電腦網

 萬盛學電腦網 >> 網絡編程 >> php編程 >> PHP設計模式實例學習筆記

PHP設計模式實例學習筆記

本文章要講到的PHP設計模式中包括有值對象模式、策略模式、觀察者模式、命令模式四種模式,下面我一一給各位同學詳細介紹希望文章對大家會帶來幫助。

一、值對象模式

再說設計模式-值對象模式之前,你要了解值傳遞和引用傳遞:

PHP設計模式實例學習筆記
1.值對象模式概念:
如果你把同一個對象資源賦值給兩個不同的變量,然後改變其中的一個變量,另一個變量仍然不受影響。這就是使用值對象模式的目的。
看下面例子:

 代碼如下 復制代碼 <?php
 
class BadDollar {
  protected $amount;
 
  public function __construct($amount=0) {
    $this->amount = (float)$amount;
  }
 
  public function getAmount() {
    return $this->amount;
  }
 
  public function add($dollar) {
    $this->amount += $dollar->getAmount();
  }
}
 
class Work {
  protected $salary;
 
  public function __construct() {
    $this->salary = new BadDollar(200);
  }
 
  public function payDay() {
    return $this->salary;
  }
 
}
 
class Person {
  public $wallet;
}
 
 
$job = new Work;
$p1 = new Person;
$p2 = new Person;
$p1->wallet = $job->payDay();
print_r($p1->wallet->getAmount()); //200
 
$p2->wallet = $job->payDay();
print_r($p2->wallet->getAmount()); //200
 
$p1->wallet->add($job->payDay());
print_r($p1->wallet->getAmount()); //400
 
//this is bad — actually 400
print_r($p2->wallet->getAmount()); //400
 
//this is really bad — actually 400
print_r($job->payDay()->getAmount()); //400


看上面例子,可以知道明顯的錯誤是$p1和$p2使用的是同一個BadDollar對象,首先,類Work和類Person的實例已經創建。那麼,假設每一個雇員最初有一個空的電子錢包,雇員的電子錢包Person:wallet是通過Work::payDay()函數返回的對象資源變量賦值的,所以被設定為一個BadDollar類的對象實例。實際上,$job::salary,、$p1::wallet和$p2::wallet指向的是同一個對象的實例。
使用值對象模式,重新設計Dollar對象如下

 代碼如下 復制代碼

class Dollar {
  protected $amount;
 
  public function __construct($amount=0) {
    $this->amount = (float)$amount;
  }
 
  public function getAmount() {
    return $this->amount;
  }
 
  public function add($dollar) {
    return new Dollar($this->amount + $dollar->getAmount());
  }
}

可以看到,主要的變化在於Dollar:add()函數中,它是創建並返回一個新的Dollar實例,所以,盡管你指定當前對象給多個變量,但是每一個變量的變化都不會影響其它的變量實例。
值對象模式設計注意:

1.保護值對象的屬性,禁止被直接訪問。

2.在構造函數中就對屬性進行賦值。

3.去掉任何一個會改變屬性值的方式函數(setter),否則屬性值很容易被改變

二、策略模式

1.策略模式概念
策略模式針對一組算法,將每一個算法封裝到具有共同接口的獨立的類中,此模式讓算法的變化獨立於使用算法的客戶。從而讓程序結構更靈活,具有更好的擴展性和維護性
2.策略模式結構圖

PHP設計模式實例學習筆記

3.策略模式角色說明
    抽象策略(Strategy)角色:定義所有支持的算法的公共接口。通常是以一個接口或抽象來實現。Context使用這個接口來調用其ConcreteStrategy定義的算法。
    具體策略(ConcreteStrategy)角色:以Strategy接口實現某具體算法
    環境(Context)角色:持有一個Strategy類的引用,用一個ConcreteStrategy對象來配置
4.策略模式實例 
比如說購物車系統,在給商品計算總價的時候,普通會員肯定是商品單價乘以數量,但是對中級會員提供8者折扣,對高級會員提供7折折扣,這種場景就可以使用策略模式實現:

 代碼如下 復制代碼

<?php

//抽象策略角色《為接口或者抽象類,給具體策略類繼承》
interface Strategy
{
    public function computePrice($price);
}
 
//具體策略角色-普通會員策略類
class GenernalMember implements Strategy
{
    public function computePrice($price)
    {
        return $price;
    }
}
 
//具體策略角色-中級會員策略類
class MiddleMember implements Strategy
{
    public function computePrice($price)
    {
        return $price * 0.8;
    }
}
 
//具體策略角色-高級會員策略類
class HignMember implements Strategy
{
    public function computePrice($price)
    {
        return $price * 0.7;
    }
}
 
//環境角色實現類
class Price
{
    //具體策略對象
    private $strategyInstance;
   
    //構造函數
    public function __construct($instance)
    {
        $this->strategyInstance = $instance;
    }
   
    public function compute($price)
    {
        return $this->strategyInstance->computePrice($price);
    }
}
 
//客戶端使用
$p = new Price(new HignMember());
 
$totalPrice = $p->compute(100);
 
echo $totalPrice; //70


三、命令模式

1.命令模式概念:
將來自客戶端的請求傳入一個對象,從而使你可用不同的請求對客戶進行參數化。用於“行為請求者”與“行為實現者”解耦,可實現二者之間的松耦合,以便適應變化。 
2.參與者:

  • Command(命令):在一個方法調用之上定義一個抽象;
  • ConcreteCommand(具體的命令):一個操作的實現;
  • Invoker(調用者):引用Command實例作為它可用的操作。

 

 代碼如下 復制代碼 <?php
//命令
interface Validator 

    /** 
     * The method could have any parameters. 
     * @param mixed 
     * @return boolean 
     */
    public function isValid($value); 

 
//具體命令
class MoreThanZeroValidator implements Validator 

    public function isValid($value) 
    { 
        return $value > 0; 
    } 

 
//具體命令
class EvenValidator implements Validator 

    public function isValid($value) 
    { 
        return $value % 2 == 0; 
    } 

 
//調用者
class ArrayProcessor 

    protected $_rule; 
 
    public function __construct (Validator $rule) 
    { 
        $this->_rule = $rule; 
    } 
 
    public function process(array $numbers) 
    { 
        foreach ($numbers as $n) { 
            if ($this->_rule->IsValid($n)) { 
                echo $n, " "; 
            } 
        } 
    } 

 
//客戶端
$processor = new ArrayProcessor(new EvenValidator()); 
$processor->process(array(1, 20, 18, 5, 0, 31, 42));

在這個模式中,Invoker(調用者)知道傳遞給它的Command,無需依賴於真實的ConcreteCommand(具體的命令)實現,解決了通過配置進行方法調用相關的問題,如UI控件按鈕和菜單等引用一個Command,它們的行為是通過通用的ConcreteCommand實例呈現的。

四、觀察者模式

首先了解觀察者模式的概念:一個對象通過添加一個方法(該方法允許另一個對象,即觀察者 注冊自己)使本身變得可觀察。當可觀察的對象更改時,它會將消息發送到已注冊的觀察者。這些觀察者使用該信息執行的操作與可觀察的對象無關。結果是對象可以相互對話,而不必了解原因。觀察者模式是一種事件系統,意味著這一模式允許某個類觀察另一個類的狀態,當被觀察的類狀態發生改變的時候,觀察類可以收到通知並且做出相應的動作;觀察者模式為您提供了避免組件之間緊密耦。看下面例子你就明白了!
1.使用觀察者模式實現消息推送

 代碼如下 復制代碼

<?php

//觀察者
interface IObserver
{
 public function notify();
}
 
//定義可以被觀察的對象接口
interface IObservable
{
 public function addObserver($observer);
}
 
//實現IObservable接口
class MessageSystem Implements IObservable
{
 private $_observers = array();
 
 public function addObserver($observer)
 {
  $this->_observers = $observer;
 }
 
 public function doNotify()
 {
  foreach($this->_observers as $o)
  {
   $o->notify();
  }
 }
}
 
//實現IObserver接口
class User Implements IObserver
{
 public function __construct($username)
 {
  echo "我是新用戶{$username}<br/>";
 }
 //通知觀察者方法
 public function notify()
 {
  echo '歡迎新用戶';
 }
}
 
//使用
$u = new MessageSystem();
 
$u->addObserver(new User('小明'));
//$u->addObserver(new User('小紅'));
//$u->addObserver(new User('小黑'));
 
$u->doNotify();


2.摘自PHPCHINA的一個不錯例子:


/**
* 定義觀察接口
*/
interface Subject
{
    public function Attach($Observer); //添加觀察者
    public function Detach($Observer); //踢出觀察者
    public function Notify(); //滿足條件時通知觀察者
    public function SubjectState($Subject); //觀察條件
}
 
/**
* 觀察類的具體實現
*/
class Boss Implements Subject
{
    public $_action;
   
    private $_Observer;
   
    public function Attach($Observer)
    {
        $this->_Observer[] = $Observer;
    }
   
    public function Detach($Observer)
    {
        $ObserverKey = array_search($Observer, $this->_Observer);
       
        if($ObserverKey !== false)
        {
            unset($this->_Observer[$ObserverKey]);
        }
    }
   
    public function Notify()
    {
        foreach($this->_Observer as $value )
        {
            $value->Update();
        }
    }
   
    public function SubjectState($Subject)
    {
        $this->_action = $Subject;
    }
}
 
/**
* 抽象觀察者
*
*/
abstract class Observer
{
    protected $_UserName;
   
    protected $_Sub;
   
    public function __construct($Name,$Sub)
    {
        $this->_UserName = $Name;
        $this->_Sub = $Sub;
    }
   
    public abstract function Update(); //接收通過方法
}
 
/**
* 觀察者
*/
class StockObserver extends Observer
{
    public function __construct($name,$sub)
    {
        parent::__construct($name,$sub);
    }
   
    public function Update()
    {
        echo $this->_Sub->_action.$this->_UserName." 你趕快跑...";
    }
}
 
$huhansan = new Boss(); //被觀察者
 
$gongshil = new StockObserver("三毛",$huhansan); //初始化觀察者
 
$huhansan->Attach($gongshil); //添加一個觀察者
$huhansan->Attach($gongshil); //添加一個相同的觀察者
$huhansan->Detach($gongshil); //踢出基中一個觀察者
 
$huhansan->SubjectState("警察來了"); //達到滿足的條件
 
$huhansan->Notify(); //通過所有有效的觀察者

 

copyright © 萬盛學電腦網 all rights reserved