[php设计模式面试题]PHP设计模式实例学习笔记

更新时间:2019-03-20    来源:php应用    手机版     字体:

【www.bbyears.com--php应用】

一、值对象模式

再说设计模式-值对象模式之前,你要了解值传递和引用传递:

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.策略模式结构图

PHP设计模式实例学习笔记

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.参与者:

Command(命令):在一个方法调用之上定义一个抽象; ConcreteCommand(具体的命令):一个操作的实现; Invoker(调用者):引用Command实例作为它可用的操作。

 

 代码如下 //命令
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(); //通过所有有效的观察者

 

本文来源:http://www.bbyears.com/jiaocheng/48820.html

猜你感兴趣

热门标签

更多>>

本类排行