观察者模式(发布-订阅模式、模型-视图模式)
观察者模式(Observer Pattern)指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。
优点:
- 观察者和被观察者是抽象耦合的。
- 建立一套触发机制。
缺点:
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
- 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
- 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
何时使用:
一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
如何解决:
使用面向对象技术,可以将这种依赖关系弱化。
注意事项:
- 在 Java 中,通过 java.util.Observable 类和 java.util.Observer 接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实例。
- Observable.addObserver(Observer o)
- Observable.notifyObservers(Object arg)
- Observable.setChange()
- Observer.update(Observable o,Object arg)
- 避免循环引用。
- 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。
案例实现:
1.1 Java内置观察者实现
import java.util.Observable;
import java.util.Observer;
/**
* Author:YANKAI
* Date:2019/4/21
* Time:11:26
* Desc:观察者1
*/
class Client1 implements Observer {
@Override
public void update(Observable o, Object data) {
System.out.println("Client1: " + data);
}
}
/**
* Author:YANKAI
* Date:2019/4/21
* Time:11:26
* Desc:观察者2
*/
class Client2 implements Observer {
@Override
public void update(Observable o, Object data) {
System.out.println("Client2: " + data);
}
}
/**
* Author:YANKAI
* Date:2019/4/21
* Time:11:26
* Desc:监听者
*/
class Service extends Observable {
private Object data;
public void setData(Object data) {
this.data = data;
//设置内部标志位,注明数据发生变化
setChanged();
//通知观察者价格改变了
notifyObservers(data);
}
}
/**
* Author:YANKAI
* Date:2019/4/21
* Time:11:26
* Desc:观察者模式:使用Java内置观察者
*/
public class JavaObserver {
public static void main(String[] args) {
// 创建客户端
Client1 c1 = new Client1();
Client2 c2 = new Client2();
// 实例化服务器
Service s=new Service();
// 注册服务器
s.addObserver(c1);
s.addObserver(c2);
System.out.println("----------------------");
// 数据改变
s.setData("123");
System.out.println("----------------------");
// 删除c2
s.deleteObserver(c2);
s.setData("456");
}
}
1.2 运行结果
2.1 案例说明
- 服务器:负责通知客户端更新数据;注册客户端;注销客户端。
- 客户端:服务器更新数据后,所有客户端同步服务器中的数据。
2. 2 案例实现
/**
* Author:YANKAI
* Date:2019/4/20
* Time:22:39
* Desc:观察者
*/
interface Observer {
/**
* 更新数据
*
* @param data
*/
void update(String data);
}
/**
* Author:YANKAI
* Date:2019/4/20
* Time:22:44
* Desc:观察者1,用来显示服务器数据
*/
class MyClient1 implements Observer {
/* 客户端数据*/
private String data;
@Override
public void update(String data) {
this.data = data;
display();
}
/**
* 显示客户端1的数据
*/
public void display() {
System.out.println("MyClient1:data " + data);
}
}
/**
* Author:YANKAI
* Date:2019/4/20
* Time:22:44
* Desc:观察者2,用来显示服务器数据
*/
class MyClient2 implements Observer {
/* 客户端数据*/
private String data;
@Override
public void update(String data) {
this.data = data;
display();
}
/**
* 显示客户端2的数据
*/
public void display() {
System.out.println("MyClient2:data " + data);
}
}
/**
* Author:YANKAI
* Date:2019/4/20
* Time:22:38
* Desc:
*/
interface Subject {
/**
* 注册观察者
*
* @param observer
*/
void regiesterObserver(Observer observer);
/**
* 移除观察者
*
* @param observer
*/
void removeObserver(Observer observer);
/**
* 通知所有观察者更新数据
*/
void notifyObserver();
}
import java.util.HashSet;
import java.util.Set;
/**
* Author:YANKAI
* Date:2019/4/20
* Time:22:44
* Desc:服务器,用来注册、移除、更新 客户端数据
*/
class MyServer implements Subject {
/* 服务器中的数据*/
private String data;
/* 客户端的集合*/
private Set<Observer> observers;
public MyServer() {
observers = new HashSet<>();
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
// 更新数据时,调用dataChange()
dataChange();
}
public void dataChange() {
// 通知所有客户端,服务器数据改变了
notifyObserver();
}
@Override
public void regiesterObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
if (observers.contains(observer)) {
observers.remove(observer);
}
}
@Override
public void notifyObserver() {
for (Observer observer : observers) {
observer.update(getData());
}
}
}
/**
* Author:YANKAI
* Date:2019/4/20
* Time:22:21
* Desc:观察者模式测试
*/
public class ObserverPattern {
public static void main(String[] args) {
//实例化观察者
MyClient1 client1 = new MyClient1();
MyClient2 client2 = new MyClient2();
//实例化服务器
MyServer server = new MyServer();
//注册观察者
server.regiesterObserver(client1);
server.regiesterObserver(client2);
System.out.println("-------------服务器更新数据-------------");
server.setData("this is change service data1");
System.out.println("-------------服务器更新数据-------------");
server.removeObserver(client2);
server.setData("this is change service data2");
}
}