您好,欢迎访问一九零五行业门户网

Php设计模式:行为型模式(二)

fddbeefbe254614385b24a85ee7a2454
4、观察者模式(observer):
         又叫发布订阅模式,当一个主体对象发生改变时,依赖它的多个观察者对象都得到通知并自动更新响应。就像报社一样,今天发布的消息只要是看这份报纸的人看到的都是同样的内容。如果发布另一份报纸,也是一样的。
         好处:广播式通信,范围大,一呼百应,便于操作一个组团,“公有制”。
         弊端:不能单独操作组团里的个体,不能实行按需分配。
         应用场景:操作多个对象,并操作相同。
代码实现:
[php] view plaincopy
<?php /** * 优才网公开课示例代码 * * 观察者模式 observer * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function output($string) { echo $string . "\n"; } //订单数据对象简单模拟,这个是实际需要被观察的对象(subject),但是我们将其独立,然后 //通过构造方法传入到我们模式中的subject中,这样使具体业务更加独立 class order{ //订单号 private $id = ''; //用户id private $userid = ''; //用户名 private $username = ''; //价格 private $price = ''; //下单时间 private $ordertime = ''; //订单数据填充简单模拟,实际应用中可能会读取用户表单输入并处理 public function __set($name, $value){ if (isset($this->$name)){ $this->$name = $value; } } //获取订单属性 public function __get($name){ if (isset($this->$name)){ return $this->$name; } return ""; } } //假设的db类,便于测试,实际会存入真实数据库 class fakedb{ public function save($data){ return true; } } class client { public static function test() { //初始化一个订单数据 $order = new order(); $order->id = 1001; $order->userid = 9527; $order->username = "god"; $order->price = 20.0; $order->ordertime = time(); //向数据库保存订单 $db = new fakedb(); $result = $db->save($order); if ($result){ //实际应用可能会写到日志文件中,这里直接输出 output( "[orderid:{$order->id}] [useid:{$order->userid}] [price:{$order->price}]" ); //实际应用会调用邮件发送服务如sendmail,这里直接输出 output( "dear {$order->username}: your order {$order->id} was confirmed!" ); //实际应用会调用邮件发送服务如sendmail,这里直接输出 output( "dear manager: user {$order->username}(id:{$order->userid}) submitted a new order {$order->id}, please handle it asap!" ); } } } client::test();
<?php /** * 优才网公开课示例代码 * * 观察者模式 observer * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function output($string) { echo $string . "\n"; } //订单数据对象简单模拟,这个是实际需要被观察的对象(subject),但是我们将其独立,然后 //通过构造方法传入到我们模式中的subject中,这样使具体业务更加独立 class order{ //订单号 private $id = ''; //用户id private $userid = ''; //用户名 private $username = ''; //价格 private $price = ''; //下单时间 private $ordertime = ''; //订单数据填充简单模拟,实际应用中可能会读取用户表单输入并处理 public function __set($name, $value){ if (isset($this->$name)){ $this->$name = $value; } } //获取订单属性 public function __get($name){ if (isset($this->$name)){ return $this->$name; } return ""; } } //被观察者, 负责维护观察者并在变化发生是通知观察者 class ordersubject implements splsubject { private $observers; private $order; public function __construct(order $order) { $this->observers = new splobjectstorage(); $this->order = $order; } //增加一个观察者 public function attach(splobserver $observer) { $this->observers->attach($observer); } //移除一个观察者 public function detach(splobserver $observer) { $this->observers->detach($observer); } //通知所有观察者 public function notify() { foreach ($this->observers as $observer) { $observer->update($this); } } //返回主体对象的具体实现,供观察者调用 public function getorder() { return $this->order; } } //记录业务数据日志 (actionlogobserver),实际可能还要抽象一层以处理不同的action(业务操作),这里省略 class actionlogobserver implements splobserver{ public function update(splsubject $subject) { $order = $subject->getorder(); //实际应用可能会写到日志文件中,这里直接输出 output( "[orderid:{$order->id}] [useid:{$order->userid}] [price:{$order->price}]" ); } } //给用户发送订单确认邮件 (usermailobserver) class usermailobserver implements splobserver{ public function update(splsubject $subject) { $order = $subject->getorder(); //实际应用会调用邮件发送服务如sendmail,这里直接输出 output( "dear {$order->username}: your order {$order->id} was confirmed!" ); } } //给管理人员发订单处理通知邮件 (adminmailobserver) class adminmailobserver implements splobserver{ public function update(splsubject $subject) { $order = $subject->getorder(); //实际应用会调用邮件发送服务如sendmail,这里直接输出 output( "dear manager: user {$order->username}(id:{$order->userid}) submitted a new order {$order->id}, please handle it asap!" ); } } //假设的db类,便于测试,实际会存入真实数据库 class fakedb{ public function save($data){ return true; } } class client { public static function test() { //初始化一个订单数据 $order = new order(); $order->id = 1001; $order->userid = 9527; $order->username = "god"; $order->price = 20.0; $order->ordertime = time(); //绑定观察者 $subject = new ordersubject($order); $actionlogobserver = new actionlogobserver(); $usermailobserver = new usermailobserver(); $adminmailobserver = new adminmailobserver(); $subject->attach($actionlogobserver); $subject->attach($usermailobserver); $subject->attach($adminmailobserver); //向数据库保存订单 $db = new fakedb(); $result = $db->save($order); if ($result){ //通知观察者 $subject->notify(); } } } client::test();
5、中介者模式(mediator):
用中介对象封装一系列的对象交互,中介使各对象不需要显式地相互引用。类似于邮局,邮寄者和收件者不用自己跑很远路,通过邮局就可以。
好处:简化了对象之间的关系,减少子类的生成。
弊端:中介对象可能变得非常复杂,系统难以维护。
应用场景:不需要显示地建立交互。
代码实现:
[php] view plaincopy
<?php /** * 优才网公开课示例代码 * * 中介者模式 mediator * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function output($string) { echo $string . "\n"; } abstract class mediator { // 中介者角色 abstract public function send($message,$colleague); } abstract class colleague { // 抽象对象 private $_mediator = null; public function __construct($mediator) { $this->_mediator = $mediator; } public function send($message) { $this->_mediator->send($message,$this); } abstract public function notify($message); } class concretemediator extends mediator { // 具体中介者角色 private $_colleague1 = null; private $_colleague2 = null; public function send($message,$colleague) { if($colleague == $this->_colleague1) { $this->_colleague1->notify($message); } else { $this->_colleague2->notify($message); } } public function set($colleague1,$colleague2) { $this->_colleague1 = $colleague1; $this->_colleague2 = $colleague2; } } class colleague1 extends colleague { // 具体对象角色 public function notify($message) { output(sprintf('colleague-1: %s', $message)); } } class colleague2 extends colleague { // 具体对象角色 public function notify($message) { output(sprintf('colleague-2: %s', $message)); } } class client { public static function test(){ // client $objmediator = new concretemediator(); $objc1 = new colleague1($objmediator); $objc2 = new colleague2($objmediator); $objmediator->set($objc1,$objc2); $objc1->send("to c2 from c1"); $objc2->send("to c1 from c2"); } } client::test();
6、状态模式(state) :
对象在不同状态下表现出不同的行为。就像女朋友一样,高兴了牵你的手,不高兴了遛狗。在两种状态下变现出不同的行为。
好处:避免if语句实用,方便增加新状态,封装了状态转换规则。
弊端:增加系统类和对象的数量。
应用场景:用于对象的不同功能的转换。
代码实现:
[php] view plaincopy
<?php /** * 优才网公开课示例代码 * * 状态模式 state * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function output($string) { echo $string . "\n"; } abstract class ilift { //电梯的四个状态 const opening_state = 1; //门敞状态 const closing_state = 2; //门闭状态 const running_state = 3; //运行状态 const stopping_state = 4; //停止状态; //设置电梯的状态 public abstract function setstate($state); //首先电梯门开启动作 public abstract function open(); //电梯门有开启,那当然也就有关闭了 public abstract function close(); //电梯要能上能下,跑起来 public abstract function run(); //电梯还要能停下来 public abstract function stop(); } /** * 电梯的实现类 */ class lift extends ilift { private $state; public function setstate($state) { $this->state = $state; } //电梯门关闭 public function close() { //电梯在什么状态下才能关闭 switch ($this->state) { case ilift::opening_state: //如果是则可以关门,同时修改电梯状态 $this->setstate(ilift::closing_state); break; case ilift::closing_state: //如果电梯就是关门状态,则什么都不做 //do nothing; return ; break; case ilift::running_state: //如果是正在运行,门本来就是关闭的,也说明都不做 //do nothing; return ; break; case ilift::stopping_state: //如果是停止状态,本也是关闭的,什么也不做 //do nothing; return ; break; } output('lift colse'); } //电梯门开启 public function open() { //电梯在什么状态才能开启 switch($this->state){ case ilift::opening_state: //如果已经在门敞状态,则什么都不做 //do nothing; return ; break; case ilift::closing_state: //如是电梯时关闭状态,则可以开启 $this->setstate(ilift::opening_state); break; case ilift::running_state: //正在运行状态,则不能开门,什么都不做 //do nothing; return ; break; case ilift::stopping_state: //停止状态,淡然要开门了 $this->setstate(ilift::opening_state); break; } output('lift open'); } ///电梯开始跑起来 public function run() { switch($this->state){ case ilift::opening_state: //如果已经在门敞状态,则不你能运行,什么都不做 //do nothing; return ; break; case ilift::closing_state: //如是电梯时关闭状态,则可以运行 $this->setstate(ilift::running_state); break; case ilift::running_state: //正在运行状态,则什么都不做 //do nothing; return ; break; case ilift::stopping_state: //停止状态,可以运行 $this->setstate(ilift::running_state); } output('lift run'); } //电梯停止 public function stop() { switch($this->state){ case ilift::opening_state: //如果已经在门敞状态,那肯定要先停下来的,什么都不做 //do nothing; return ; break; case ilift::closing_state: //如是电梯时关闭状态,则当然可以停止了 $this->setstate(ilift::closing_state); break; case ilift::running_state: //正在运行状态,有运行当然那也就有停止了 $this->setstate(ilift::closing_state); break; case ilift::stopping_state: //停止状态,什么都不做 //do nothing; return ; break; } output('lift stop'); } } class client { public static function test() { $lift = new lift(); //电梯的初始条件应该是停止状态 $lift->setstate(ilift::stopping_state); //首先是电梯门开启,人进去 $lift->open(); //然后电梯门关闭 $lift->close(); //再然后,电梯跑起来,向上或者向下 $lift->run(); //最后到达目的地,电梯挺下来 $lift->stop(); } } client::test();
<?php /** * 优才网公开课示例代码 * * 状态模式 state * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function output($string) { echo $string . "\n"; } /** * * 定义一个电梯的接口 */ abstract class liftstate{ //定义一个环境角色,也就是封装状态的变换引起的功能变化 protected $_context; public function setcontext(context $context){ $this->_context = $context; } //首先电梯门开启动作 public abstract function open(); //电梯门有开启,那当然也就有关闭了 public abstract function close(); //电梯要能上能下,跑起来 public abstract function run(); //电梯还要能停下来,停不下来那就扯淡了 public abstract function stop(); } /** * 环境类:定义客户感兴趣的接口。维护一个concretestate子类的实例,这个实例定义当前状态。 */ class context { //定义出所有的电梯状态 static $openningstate = null; static $closeingstate = null; static $runningstate = null; static $stoppingstate = null; public function __construct() { self::$openningstate = new openningstate(); self::$closeingstate = new closingstate(); self::$runningstate = new runningstate(); self::$stoppingstate = new stoppingstate(); } //定一个当前电梯状态 private $_liftstate; public function getliftstate() { return $this->_liftstate; } public function setliftstate($liftstate) { $this->_liftstate = $liftstate; //把当前的环境通知到各个实现类中 $this->_liftstate->setcontext($this); } public function open(){ $this->_liftstate->open(); } public function close(){ $this->_liftstate->close(); } public function run(){ $this->_liftstate->run(); } public function stop(){ $this->_liftstate->stop(); } } /** * 在电梯门开启的状态下能做什么事情 */ class openningstate extends liftstate { /** * 开启当然可以关闭了,我就想测试一下电梯门开关功能 * */ public function close() { //状态修改 $this->_context->setliftstate(context::$closeingstate); //动作委托为closestate来执行 $this->_context->getliftstate()->close(); } //打开电梯门 public function open() { output('lift open...'); } //门开着电梯就想跑,这电梯,吓死你! public function run() { //do nothing; } //开门还不停止? public function stop() { //do nothing; } } /** * 电梯门关闭以后,电梯可以做哪些事情 */ class closingstate extends liftstate { //电梯门关闭,这是关闭状态要实现的动作 public function close() { output('lift close...'); } //电梯门关了再打开,逗你玩呢,那这个允许呀 public function open() { $this->_context->setliftstate(context::$openningstate); //置为门敞状态 $this->_context->getliftstate()->open(); } //电梯门关了就跑,这是再正常不过了 public function run() { $this->_context->setliftstate(context::$runningstate); //设置为运行状态; $this->_context->getliftstate()->run(); } //电梯门关着,我就不按楼层 public function stop() { $this->_context->setliftstate(context::$stoppingstate); //设置为停止状态; $this->_context->getliftstate()->stop(); } } /** * 电梯在运行状态下能做哪些动作 */ class runningstate extends liftstate { //电梯门关闭?这是肯定了 public function close() { //do nothing } //运行的时候开电梯门?你疯了!电梯不会给你开的 public function open() { //do nothing } //这是在运行状态下要实现的方法 public function run() { output('lift run...'); } //这个事绝对是合理的,光运行不停止还有谁敢做这个电梯?!估计只有上帝了 public function stop() { $this->_context->setliftstate(context::$stoppingstate); //环境设置为停止状态; $this->_context->getliftstate()->stop(); } } /** * 在停止状态下能做什么事情 */ class stoppingstate extends liftstate { //停止状态关门?电梯门本来就是关着的! public function close() { //do nothing; } //停止状态,开门,那是要的! public function open() { $this->_context->setliftstate(context::$openningstate); $this->_context->getliftstate()->open(); } //停止状态再跑起来,正常的很 public function run() { $this->_context->setliftstate(context::$runningstate); $this->_context->getliftstate()->run(); } //停止状态是怎么发生的呢?当然是停止方法执行了 public function stop() { output('lift stop...'); } } /** * 模拟电梯的动作 */ class client { public static function test() { $context = new context(); $context->setliftstate(new closingstate()); $context->open(); $context->close(); $context->run(); $context->stop(); } } client::test();
其它类似信息

推荐信息