15.观察者模式&发布/订阅模式
15.观察者模式&发布/订阅模式
1. 观察者模式
1.概念&优缺点
-
概念
观察者模式: 1. 在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。 2. 其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。 3. 抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。 抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。 具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。 具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。 4. 有一个微信公众号服务,不定时发布一些消息,关注公众号就可以收到推送消息,取消关注就收不到推送消息。
-
优点
- 低耦合
-
缺点
- 观察者与主题绑定,仍有一定耦合性
2.类图
3.代码
Observer.java
package com.desmond.codebase.designpattern.observer;
/**
* Created by presleyli on 2018/6/14.
*/
public interface Observer {
void update(String message);
}
Observerable.java
package com.desmond.codebase.designpattern.observer;
/**
* Created by presleyli on 2018/6/14.
*/
public interface Observerable {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObserver();
}
User.java:
package com.desmond.codebase.designpattern.observer;
import java.text.MessageFormat;
/**
* Created by presleyli on 2018/6/14.
*/
public class User implements Observer {
private String name;
private String message;
public User(String name) {
this.name = name;
}
@Override
public void update(String message) {
this.message = message;
read();
}
public void read() {
System.out.println(MessageFormat.format("{0} received {1}", name, message));
}
}
WechatServer:
package com.desmond.codebase.designpattern.observer;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Created by presleyli on 2018/6/14.
*/
public class WechatServer implements Observerable {
private List<Observer> list;
private String message;
public WechatServer() {
this.list = new ArrayList<>();
}
@Override
public void registerObserver(Observer o) {
list.add(o);
}
@Override
public void removeObserver(Observer o) {
if(!list.isEmpty()) {
list.remove(o);
}
}
@Override
public void notifyObserver() {
Iterator<Observer> iterable = list.iterator();
while (iterable.hasNext()) {
iterable.next().update(message);
}
}
public void setInformation(String s) {
this.message = s;
System.out.println(MessageFormat.format("wechat server is updating message: {0}", s));
notifyObserver();
}
}
Test:
package com.desmond.codebase.designpattern.observer;
/**
* Created by presleyli on 2018/6/14.
*/
public class Test {
public static void main(String[] args) {
WechatServer server = new WechatServer();
Observer userZhang = new User("ZhangSan");
Observer userLi = new User("LiSi");
Observer userWang = new User("WangWu");
server.registerObserver(userZhang);
server.registerObserver(userLi);
server.registerObserver(userWang);
server.setInformation("PHP是世界上最好用的语言!");
System.out.println("----------------------------------------------");
server.removeObserver(userZhang);
server.setInformation("JAVA是世界上最好用的语言!");
}
}
Output:
wechat server is updating message: PHP是世界上最好用的语言!
ZhangSan received PHP是世界上最好用的语言!
LiSi received PHP是世界上最好用的语言!
WangWu received PHP是世界上最好用的语言!
----------------------------------------------
wechat server is updating message: JAVA是世界上最好用的语言!
LiSi received JAVA是世界上最好用的语言!
WangWu received JAVA是世界上最好用的语言!
Process finished with exit code 0
2.发布-订阅模式
1.概念
概念与观察者很类似,但是最大的区别 发布者和订阅者彼此不知道对方的存在,它们依赖一个第三方的中介者进行串联 , 如何进行消息过滤?最流行的方式是基于***主体***以及***内容***[维基百科][https://en.wikipedia.org/wiki/Publish–subscribe_pattern#Message_filtering]
2. 两个模式最重要的区别
3. 差异总结
- 在观察者模式中,观察者是知道Subject的,Subject一直保持对观察者进行记录,然而,在发布-订阅模式中,发布者和订阅者不知道对方的存在,它们只有通过消息代理进行通信, 这样也可以做到真正解耦,发布者和订阅者可以是完全不同的服务(不同语言,不同工作模式等等),只要遵循一套数据格式即可。
- 在发布-订阅模式中,组件是松耦合的,这点与观察者模式相反
- 观察者模式大多是同步的,比如事件触发,Subject就会去调用观察者的方法。而发布-订阅模式,大多是异步的,比如消息队列。
- 观察者模式需要在单个应用传给你下地址空间实现,而发布-订阅模式更像交叉应用模式。