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();