概念
什么是观察者模式
对象之间一对多的关系,当一个对象状态发生变化,其他的依赖对象都会收到通知。变化的对象为被观察者,收到消息的对象就是观察者。
类图
观察者观察被观察者,被观察者通知观察者。
- 被观察者实现Subject接口,观察者实现Observer接口
- 调用被观察者ConcreteSubject的registerObserver()方法注册观察者
- 当被观察者ConcreteSubject状态改变,调用notifyObserver()方法通知所有注册了的观察者ConcreteObserver,类似群发短信。
基于观察者模式的一个简单的聊天工具示例的Java实现
程序设计
-
两位聊天者,一位发送消息,另外一位接收消息,发送消息者chater1就是被观察者,接收消息者chater2就是观察者;
-
观察者chater2收到消息后,又会变成被观察者向chater1发送消息;
发送推送消息应用观察者模式,notifyObserver()方法实现消息的推送;
每一个聊天者即是观察者也是被观察者,所以需要即实现Subject接口,也需要实现Observer接口。
代码实现
- 定义Subject和Observer接口
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers(String msg);
}
public interface Observer {
void update(String revMsg);
}
- 实现Observer和Subject接口,聊天者chater即是观察者也是被观察者。这里实现聊天功能为了展示观察者模式,功能简单化,将所有好友放入一个friends队列中,相当于群发,无法指定具体某个好友。
public class Chater implements Subject, Observer {
//记录收到的消息
private String revMsg = "init msg";
//可以发消息的好友列表
private List<Observer> friends = new LinkedList<>();
//发送消息
public void sendMsg(String msg){
notifyObservers(msg);
}
//成为好友,注册为观察者,接收消息
public void registerObserver(Observer o){
friends.add(o);
}
public void removeObserver(Observer o){
//pass
}
//通知观察者
public void notifyObservers(String msg){
for (Observer o : friends){
o.update(msg);
}
}
//作为观察者接收到消息,存储在revMsg
public void update(String revMsg){
this.revMsg = revMsg;
}
//输出收到的消息
public String getRevMsg() {
return revMsg;
}
}
- 测试用例展示聊天功能,假设只有两个聊天者,互相成为好友。
public class ChatRoom {
public static void main(String[] args){
//初始化两个聊天者
Chater chater1 = new Chater();
Chater chater2 = new Chater();
System.out.println(chater1.getRevMsg());
System.out.println(chater2.getRevMsg());
System.out.println("-------------init-------------");
//互相加为好友
chater1.registerObserver(chater2);
chater2.registerObserver(chater1);
//互相发送消息
chater1.sendMsg("chater1: Hello, chater2");
//chater2收到的消息
System.out.println(chater2.getRevMsg());
chater2.sendMsg("chater2: Hello, chater1");
//chater1收到的消息
System.out.println(chater1.getRevMsg());
chater1.sendMsg("chater1: I am chater1");
//chater2收到的消息
System.out.println(chater2.getRevMsg());
chater2.sendMsg("chater2: I am chater2");
//chater1收到的消息
System.out.println(chater1.getRevMsg());
}
}
执行结果:
init msg
init msg
-------------init-------------
chater1: Hello, chater2
chater2: Hello, chater1
chater1: I am chater1
chater2: I am chater2
总结
Java API有内置的观察者模式,java.util包内包含最基本的Observer接口和Observable类。可以使用推(push)或拉(pull)的方式传送数据。在Java中的Swing大量使用到观察者模式,GUI框架,JavaBeans,RMI同样有应用。观察者模式是十分简单和容易理解的,生产环境中遇到监听通知相关的模型,优先考虑使用观察者模式,解耦多个相互交互的对象。
补充
有一个与观察者模式比较相似的设计模式——发布订阅模式。从名字上感觉两种设计模式应用的是相同的场景,都是一个模块发送通知,另一个模块接收通知,一些说法发布订阅模式就是观察者模式衍生。如果非要进行区分,应该就是发布订阅模式具有中间件模块,是一个消息范式,发布者不是直接将消息发给订阅者,而是通过中间件传递消息,订阅者在中间件中获取消息,最经典的应用就是消息队列。观察者模式被观察者直接通知到观察者。