什么是观察者模式?
定义了 一种一对多的关系,让多个观察对象(公司员工)同时监听一个主题对象(秘书),主题对象状态发生变化时,会通知全部的观察者,使它们可以更新本身。
解决什么问题?
将一个系统分割成一个一些类相互协做的类有一个很差的反作用,那就是须要维护相关对象间的一致性。咱们不但愿为了维持一致性而使各种紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。
各个角色
抽象主题(Subject):它把全部观察者对象的引用保存到一个汇集里,每一个主题均可以有任何数量的观察者。抽象主题提供一个接口,能够增长和删除观察者对象。
具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给全部登记过的观察者发出通知。
抽象观察者(Observer):为全部的具体观察者定义一个接口,在获得主题通知时更新本身。
具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使自己的状态与主题状态协调。
经过实例说明:
//抽象观察者角色
public interface Watcher
{
public void update(String str);
}<strong>
</strong>
//定义抽象的主题角色,即抽象的被观察者
//抽象主题角色,watched:被观察
public interface Watched
{
public void addWatcher(Watcher watcher);
public void removeWatcher(Watcher watcher);
public void notifyWatchers(String str);
}
public class ConcreteWatcher implements Watcher
{
@Override
public void update(String str)
{
System.out.println(str);
}
}<strong>
</strong>
//主题角色
import java.util.ArrayList;
import java.util.List;
public class ConcreteWatched implements Watched
{
// 存放观察者
private List<Watcher> list = new ArrayList<Watcher>();
@Override
public void addWatcher(Watcher watcher)
{
list.add(watcher);
}
@Override
public void removeWatcher(Watcher watcher)
{
list.remove(watcher);
}
@Override
public void notifyWatchers(String str)
{
// 自动调用其实是主题进行调用的
for (Watcher watcher : list)
{
watcher.update(str);
}
}
}<strong>
</strong>
//test
public class Test
{
public static void main(String[] args)
{
Watched girl = new ConcreteWatched();
Watcher watcher1 = new ConcreteWatcher();
Watcher watcher2 = new ConcreteWatcher();
Watcher watcher3 = new ConcreteWatcher();
girl.addWatcher(watcher1);
girl.addWatcher(watcher2);
girl.addWatcher(watcher3);
girl.notifyWatchers("开心");
}
}<strong>
</strong>
实际应用场景 (内容来自:http://blog.csdn.net/swengineer/article/details/6268244)
/**
* 观察者模式应用场景实例
*
* 免责声明:本文只是以哈票网举例,示例中并未涉及哈票网任何业务代码,所有原创,若有雷同,纯属巧合。
*
* 场景描述:
* 哈票以购票为核心业务(此模式不限于该业务),但围绕购票会产生不一样的其余逻辑,如:
* 1、购票后记录文本日志
* 2、购票后记录数据库日志
* 3、购票后发送短信
* 4、购票送抵扣卷、兑换卷、积分
* 5、其余各种活动等
*
* 传统解决方案:
* 在购票逻辑等类内部增长相关代码,完成各类逻辑。
*
* 存在问题:
* 1、一旦某个业务逻辑发生改变,如购票业务中增长其余业务逻辑,须要修改购票核心文件、甚至购票流程。
* 2、日积月累后,文件冗长,致使后续维护困难。
*
* 存在问题缘由主要是程序的"紧密耦合",使用观察模式将目前的业务逻辑优化成"松耦合",达到易维护、易修改的目的,
* 同时也符合面向接口编程的思想。
*
* 观察者模式典型实现方式:
* 1、定义2个接口:观察者(通知)接口、被观察者(主题)接口
* 2、定义2个类,观察者对象实现观察者接口、主题类实现被观者接口
* 3、主题类注册本身须要通知的观察者
* 4、主题类某个业务逻辑发生时通知观察者对象,每一个观察者执行本身的业务逻辑。
*
* 示例:如如下代码
*
*/
#===================定义观察者、被观察者接口============
/**
*
* 观察者接口(通知接口)
*
*/
interface ITicketObserver //观察者接口
{
function onBuyTicketOver($sender, $args); //获得通知后调用的方法
}
/**
*
* 主题接口
*
*/
interface ITicketObservable //被观察对象接口
{
function addObserver($observer); //提供注册观察者方法
}
#====================主题类实现========================
/**
*
* 主题类(购票)
*
*/
class HipiaoBuy implements ITicketObservable { //实现主题接口(被观察者)
private $_observers = array (); //通知数组(观察者)
public function buyTicket($ticket) //购票核心类,处理购票流程
{
// TODO 购票逻辑
//循环通知,调用其onBuyTicketOver实现不一样业务逻辑
foreach ( $this->_observers as $obs )
$obs->onBuyTicketOver ( $this, $ticket ); //$this 可用来获取主题类句柄,在通知中使用
}
//添加通知
public function addObserver($observer) //添加N个通知
{
$this->_observers [] = $observer;
}
}
#=========================定义多个通知====================
//短信日志通知
class HipiaoMSM implements ITicketObserver {
public function onBuyTicketOver($sender, $ticket) {
echo (date ( 'Y-m-d H:i:s' ) . " 短信日志记录:购票成功:$ticket<br>");
}
}
//文本日志通知
class HipiaoTxt implements ITicketObserver {
public function onBuyTicketOver($sender, $ticket) {
echo (date ( 'Y-m-d H:i:s' ) . " 文本日志记录:购票成功:$ticket<br>");
}
}
//抵扣卷赠送通知
class HipiaoDiKou implements ITicketObserver {
public function onBuyTicketOver($sender, $ticket) {
echo (date ( 'Y-m-d H:i:s' ) . " 赠送抵扣卷:购票成功:$ticket 赠送10元抵扣卷1张。<br>");
}
}
#============================用户购票====================
$buy = new HipiaoBuy ();
$buy->addObserver ( new HipiaoMSM () ); //根据不一样业务逻辑加入各类通知
$buy->addObserver ( new HipiaoTxt () );
$buy->addObserver ( new HipiaoDiKou () );
//购票
$buy->buyTicket ( "一排一号" );
其余设计模式: