【www.bbyears.com--php应用】
一、值对象模式
再说设计模式-值对象模式之前,你要了解值传递和引用传递:
1.值对象模式概念:
如果你把同一个对象资源赋值给两个不同的变量,然后改变其中的一个变量,另一个变量仍然不受影响。这就是使用值对象模式的目的。
看下面例子:
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.策略模式结构图
3.策略模式角色说明
抽象策略(Strategy)角色:定义所有支持的算法的公共接口。通常是以一个接口或抽象来实现。Context使用这个接口来调用其ConcreteStrategy定义的算法。
具体策略(ConcreteStrategy)角色:以Strategy接口实现某具体算法
环境(Context)角色:持有一个Strategy类的引用,用一个ConcreteStrategy对象来配置
4.策略模式实例
比如说购物车系统,在给商品计算总价的时候,普通会员肯定是商品单价乘以数量,但是对中级会员提供8者折扣,对高级会员提供7折折扣,这种场景就可以使用策略模式实现:
//抽象策略角色《为接口或者抽象类,给具体策略类继承》
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.参与者:
代码如下 //命令
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.使用观察者模式实现消息推送
//观察者
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}
";
}
//通知观察者方法
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(); //通过所有有效的观察者