一、值對象模式
再說設計模式-值對象模式之前,你要了解值傳遞和引用傳遞:
1.值對象模式概念:
如果你把同一個對象資源賦值給兩個不同的變量,然後改變其中的一個變量,另一個變量仍然不受影響。這就是使用值對象模式的目的。
看下面例子:
看上面例子,可以知道明顯的錯誤是$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.策略模式結構圖
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.參與者:
代碼如下 復制代碼 <?php
在這個模式中,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(); //通過所有有效的觀察者