观察者模式 一
2020-03-21 本文已影响0人
zjxchase
简单实例
首先看一个警察蹲点抓小偷的简单实例:警察蹲点观察到小偷偷东西就立即抓捕
Policemen.Java (警察)
public class Policemen implements Observer {
/**
* 警察姓名
*/
private String name;
public Policemen(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
Pickpocket pickpocket = (Pickpocket) o;
System.out.printf("警察 %s 发现(实际是被通知)扒手 %s 盗取了 %s,立即抓捕 \n", this.name, pickpocket.getName(), arg);
}
}
Pickpocket.java (扒手)
public class Pickpocket extends Observable {
/**
* 小偷姓名
*/
private String name;
/**
* 赃物
*/
private List<String> booties = new ArrayList<>();
public Pickpocket(String name) {
this.name = name;
}
public String getName() {
return name;
}
/**
* 偷窃
* @param booty
*/
public void steal(String booty) {
booties.add(booty);
setChanged();
notifyObservers(booties);
}
}
ObserverEx1Test.java (测试类)
public class ObserverEx1Test {
public static void main(String[] args) {
Policemen p1 = new Policemen("警察A");
Policemen p2 = new Policemen("警察B");
Pickpocket pp1 = new Pickpocket("郭某");
pp1.addObserver(p1);
pp1.addObserver(p2);
pp1.steal("cellphone");
}
}
运行ObserverEx1Test类输出结果:
警察 警察B 发现(实际是被通知)郭某 盗取了 [cellphone] ,立即抓捕
警察 警察A 发现(实际是被通知)郭某 盗取了 [cellphone] ,立即抓捕
上边这种例子观察者模式叫:发布-订阅模式
观察者模式介绍
定义
观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
解决的问题
一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
优点
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
- 目标与观察者之间建立了一套触发机制。
缺点
- 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
- 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
使用场景
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
简单实例 二
由于java.util.Observable 和 java.util.Observer 类在java9 之后过期了,该实例主要是不再继承java.util.Observable 和 java.util.Observer 实现观察者模式
IObserver.java 接口
public interface IObserver {
/**
* 观察者获得消息
* @param msg
*/
void update(String msg);
}
ISubject.java 接口
public interface ISubject {
/**
* 注册观察者
* @param observer
*/
void registerObserver(IObserver observer);
/**
* 取消观察者
* @param observer
*/
void removeObserver(IObserver observer);
/**
* 通知观察者
*/
void notifyObserver();
/**
* 获取主体标示名称
* @return
*/
String getName();
}
Pickpocket.java
public class Pickpocket implements ISubject {
/**
* 小偷姓名
*/
private String name;
/**
* 赃物
*/
private String booty;
/**
* 观察者集合
*/
private List<IObserver> observers = new ArrayList<>();
public Pickpocket(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public void registerObserver(IObserver observer) {
observers.add(observer);
}
@Override
public void removeObserver(IObserver observer) {
if (observers.contains(observer)) {
observers.remove(observer);
}
}
@Override
public void notifyObserver() {
for (IObserver observer : observers) {
observer.update(booty);
}
}
/**
* 盗取赃物后给观察者(警察)发送消息
* @param booty
*/
public void steal(String booty) {
this.booty = booty;
// 通知观察者
notifyObserver();
}
}
Policemen.java
public class Policemen implements IObserver {
/**
* 警察姓名
*/
private String name;
/**
* 增具体的观察者订阅的主体
*/
private ISubject subject;
public Policemen(String name, ISubject subject) {
this.name = name;
this.subject = subject;
subject.registerObserver(this);
}
@Override
public void update(String booty) {
System.out.printf("警察 %s 发现(实际是被通知)%s 盗取了 %s ,立即抓捕\n", this.name, subject.getName(), booty);
}
}
ObserverEx1Test.java
public class ObserverEx1Test {
public static void main(String[] args) {
Pickpocket pp = new Pickpocket("Pickpocket-A");
Policemen p1 = new Policemen("Policemen-A", pp);
Policemen p2 = new Policemen("Policemen-B", pp);
pp.steal("手机");
System.out.println("------------------------");
pp.removeObserver(p2);
pp.steal("PAD");
}
}
执行结果:
警察 Policemen-A 发现(实际是被通知)Pickpocket-A 盗取了 手机 ,立即抓捕
警察 Policemen-B 发现(实际是被通知)Pickpocket-A 盗取了 手机 ,立即抓捕
------------------------
警察 Policemen-A 发现(实际是被通知)Pickpocket-A 盗取了 PAD ,立即抓捕