考虑到一个现实需求,实现微信的订阅通知功能,即某某公众号发布了一个消息,那么所有订阅了该公众号消息订阅的使用者都会得到这个消息的通知。如何实现?下意识脑中想到了轮询,订阅者并不知道什么时候公众号会发布新消息,那么我们可以让订阅的人每隔一段时间去检查一下公众号的状态,看看有没有发布新的消息。但是现实中真的是这样实现的吗?这样做会有以下的缺陷:
1、消耗资源去主动检查公众号状态。
2、无法及时的得到消息订阅提醒。看似只要轮询的间隔足够小,订阅者就能够及时的得到订阅消息。轮询时间间隔越小,单位时间消耗资源去检查公众号状态的次数就会变多;轮询时间间隔越大,我们就无法及时的得到新消息提醒。
3、采取这种方式,每次有新的客户订阅消息,我们都需要往发布者代码中增加该客户(想一下,这种模式下公众号必须保存所有的订阅者可能是以List或者其他形式存储),每次增加订阅者都需要改一下发布者的代码。
基于类似以上的需求,观察者模式(也叫发布订阅模式)被提出,它是对多个对象之间定义了一对多的依赖,即一个对象发生了变化,依赖它的对象都会得到响应的提醒并采取相应的操作。即发布者发布信息,订阅者获取信息,订阅了相关消息的就能收到相应的消息,没有订阅就不能收到。
1、抽象的被观察者:抽象的行为有,添加、删除观察者和在状态发生改变时通知观察者
2、抽象的观察者:抽象的行为主要是收到被观察者通知后执行相应的操作,比如订阅消息后,收到公众号通知有新消息,则展示新消息。
3、具体的被观察者:
4、具体的观察者:
就拿概述中的需求而言,做个简单的Demo,有一个公众号实例,若干个订阅者实例,现在要实现的功能就是公众号能够发布新的消息,同时对于每一个订阅者,能够订阅和取消订阅公众号,同时在公众号发布新消息时能够及时展示新消息。
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
public interface Observer {
public void update(String newmessage);
}
import java.util.ArrayList;
public class Subscription implements Subject{
private ArrayList observers;//公众号保存订阅者
private String newMessage;//公众号发布的新消息,现实中应该是用集合类或者其他技术实现,毕竟还需要保存历史消息,此处就采用字符串测试功能
public Subscription(){
this.observers = new ArrayList();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
observers.remove(i);
}
@Override
public void notifyObservers() {
for(int i =0;i
public class Subscriber implements Observer{
private String name;
private String newMessage;
public Subscriber(String name,Subject subscription){
this.name = name;
subscription.registerObserver(this);
}
@Override
public void update(String newmessage) {
this.newMessage = newmessage;
show();
}
private void show() {
System.out.println(name+"收到新消息:"+newMessage);
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
Subscription subscription_1 =
new Subscription();
Subscriber subscriber_1 = new Subscriber("张三",subscription_1);
Subscriber subscriber_2 = new Subscriber("李四",subscription_1);
Subscriber subscriber_3 = new Subscriber("王五",subscription_1);
subscription_1.updateNewMessage("小米拟投资77.6亿在深圳设立国际总部");
System.out.println("------------------------------------------------");
Thread.sleep(1000);
subscription_1.updateNewMessage("麦当劳中国将停用塑料吸管");
}
}
执行结果如下: