Php设计模式:行为型模式(二)
原文详见:http://www.ucai.cn/blogdetail/7023?mid=1&f=12可以在线运行查看效果哦!
<接上一篇>
4、观察者模式(Observer):
又叫发布订阅模式,当一个主体对象发生改变时,依赖它的多个观察者对象都得到通知并自动更新响应。就像报社一样,今天发布的消息只要是看这份报纸的人看到的都是同样的内容。如果发布另一份报纸,也是一样的。
好处:广播式通信,范围大,一呼百应,便于操作一个组团,“公有制”。
弊端:不能单独操作组团里的个体,不能实行按需分配。
应用场景:操作多个对象,并操作相同。
代码实现:
view plaincopyhttps://code.csdn.net/assets/CODE_ico.pnghttps://code.csdn.net/assets/ico_fork.svg
[*]<?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( " " );
[*]
[*] //实际应用会调用邮件发送服务如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( " " );
[*] }
[*]}
[*]
[*]//给用户发送订单确认邮件 (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):
用中介对象封装一系列的对象交互,中介使各对象不需要显式地相互引用。类似于邮局,邮寄者和收件者不用自己跑很远路,通过邮局就可以。
好处:简化了对象之间的关系,减少子类的生成。
弊端:中介对象可能变得非常复杂,系统难以维护。
应用场景:不需要显示地建立交互。
代码实现:
view plaincopyhttps://code.csdn.net/assets/CODE_ico.pnghttps://code.csdn.net/assets/ico_fork.svg
[*]<?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语句实用,方便增加新状态,封装了状态转换规则。
弊端:增加系统类和对象的数量。
应用场景:用于对象的不同功能的转换。
代码实现:
view plaincopyhttps://code.csdn.net/assets/CODE_ico.pnghttps://code.csdn.net/assets/ico_fork.svg
[*]<?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();
页:
[1]