观察者模式
观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
观察者模式四大角色
Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供新增、删除、通知观察者的方法。
ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新
使用场景
商品变更的时候,需要更新商品缓存、发布商品详情页、更新搜索索引,传统做法,在商品update方法处,分别调用更新商品缓存接口、发布商品接口、更新搜索索引接口。代码耦合度很高,如果增加一个新的逻辑,需要修改update方法,如果商品修改不需要更新缓存了,同样需要修改update方法。通过引入观察者模式,通过消息中间件的方式可以进行解耦,当商品发生修改的时候,发送一个消息,商品缓存应用可以订阅此消息,进行缓存的更新。商品发布系统,订阅此消息,重新发布商品。搜索应用,订阅此消息,增量更新索引。
如果商品更改有其他的业务逻辑,可以通过消息订阅和消费,增加相应的逻辑。如果要去掉某个逻辑,只要取消消息订阅,不再消费此消息即可。观察者模式通过发布和订阅的方式,实现业务的解耦。
代码实现
public interface Subject{
//添加观察者
void addObserver(Observer obj);
//移除观察者
void deleteObserver(Observer obj);
//当主题方法改变时,这个方法被调用,通知所有的观察者
void notifyObserver();
}
public class StudentObserver implements Observer{
//保存一个Subject的引用,以后如果可以想取消订阅,有了这个引用会比较方便
private Subject subject;
//学生的姓名,用来标识不同的学生对象
private String name;
//构造器用来注册观察者
public Student Observer(String name,TeacherSubject teacherSubject) {
this.name=name;
this.subject = teacherSubject;
//每新建一个学生对象,默认添加到观察者的行列
teacherSubject.addObserver(this);
}
public void update(Stringinfo) {
System.out.println(name+"得到作业:"+info);
}
}
public interface Subject{
//添加观察者
void addObserver(Observer obj);
//移除观察者
void removeObserver(Observer obj);
//当主题方法改变时,这个方法被调用,通知所有的观察者
void notifyObserver();
}
public class StudentObserver implements Observer{
//保存一个Subject的引用,以后如果可以想取消订阅,有了这个引用会比较方便
private Subject subject;
//学生的姓名,用来标识不同的学生对象
private String name;
//构造器用来注册观察者
public StudentObserver(String name,TeacherSubject teacherSubject) {
this.name=name;
this.subject = teacherSubject;
//每新建一个学生对象,默认添加到观察者的行列
teacherSubject.addObserver(this);
}
public void update(Stringinfo) {
System.out.println(name+"得到作业:"+info);
}
}
public classTestObserver{
public static void main(String[] args) {
TeacherSubject teacher =newTeacherSubject();
StudentObserver zhangSan =newStudentObserver("张三", teacher);
StudentObserver LiSi =newStudentObserver("李四", teacher);
StudentObserver WangWu =newStudentObserver("王五", teacher);
teacher.setHomework("第二页第六题");
System.out.println("----------------");
teacher.setHomework("第三页第七题");
System.out.println("----------------");
teacher.setHomework("第五页第八题");
}
}
运行结果:
代码不是特别的严谨,没有考虑多线程问题,不是线程安全的,用于生产环境,需要做同步或者增加锁控制。java中jdk提供了相关的工具类,java.uitl包下的Observer和Observable,这个是同步的,支持多线程。java自带jdk实现方法如下:
public class Message {
private String title;
private String content;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Message(String title,String content) {
this.title = title;
this.content = content;
}
@Override
public String toString() {
return"Message{"+
"title='"+ title +'\''+
", content='"+ content +'\''+
'}';
}
}
//订阅者
public class MessageObserver implementsObserver{
private String title;
public String getTitle(){
return title;
}
public void setTitle(String title){
this.title = title;
}
public MessageObserver(String title){
this.title = title;
}
public void update(Observable o, Object arg){
System.out.println("observer :"+ title +",receive a message"+ arg.toString());
}
}
//发布者
public class MessagePublishObservable extends Observable{
private Message message;
public MessagePublishObservable(Message message){
this.message = message;
}
public void pushMessage(){
setChanged();
notifyObservers(message);
}
public Message getMessage(){
return message;
}
public void setMessage(Message message){
this.message = message;
}
@Override
public synchronized void addObserver(Observer o){
super.addObserver(o);
}
@Override
public synchronized void deleteObserver(Observer o){
super.deleteObserver(o);
}
@Override
public void notifyObservers(){
super.notifyObservers();
}
@Override
public void notifyObservers(Object arg){
super.notifyObservers(arg);
}
@Override
protected synchronized void setChanged(){
super.setChanged();
}
}
public classTest{
public static void main(String[] args){
MessageObserver messageObserverTopicA =new MessageObserver("A");
MessageObserver messageObserverTopicB =new MessageObserver("B");
MessageObserver messageObserverTopicC =new MessageObserver("C");
MessagePublishObservable messagePublishObservable =new MessagePublishObservable(newMessage("关注","欢迎关注享知行"));
//a关注了享知行
messagePublishObservable.addObserver(messageObserverTopicA);
//b关注了享知行
messagePublishObservable.addObserver(messageObserverTopicB);
//c关注了享知行
messagePublishObservable.addObserver(messageObserverTopicC);
messagePublishObservable.pushMessage();
messagePublishObservable.setMessage(newMessage("文章更新","公众号享知行更新啦"));
messagePublishObservable.pushMessage();
}
}
运行结果:
优缺点
优点:发布者和订阅者是松耦合的,发布者和订阅者之间互不影响,满足开闭原则,当有变化的时候,实时,高效的通知订阅者。
缺点:如果一个发布者对象有很多直接和间接的订阅者的话,将所有的订阅者都通知到会花费很多时间。如果在发布者之间有循环依赖的话,发布者会触发它们之间进行循环调用,导致系统崩溃。
生活中的观察者模式
老师布置作业,采用的就是观察者模式,老师是信息的发布者,学生是订阅者,老师布置作业只需要布置一遍即可,所有的学生,都能收到这个任务。
邮件组也是观察者模式,可以动态的增加和删除组成员,技术部的所有成员创建一个邮件组,如果需要发送邮件通知所有技术部的人,只要发送一封邮件给技术部邮件组即可,既方便又不会遗漏。如果有员工入职加入邮件组,有员工离职则从邮件组删除。
群社区也是观察者模式的一种形式,有相同爱好兴趣的人加入到同一个群,每一个人既是消息的发布者,也是订阅者,让大家的沟通更实时高效。
专栏的订阅,公众号的关注也是属于观察者模式,内容生产者,有新的内容更新,会通知所有的订阅者,你如果喜欢“享知行”,并关注了公众号“享知行”,只要享知行有内容更新,会通知所有的粉丝。
直播和视频,同样也是观察者模式,内容生产者,直播或者把录好的视频上传,如果你感兴趣,点开观看,所有人看到的都是同样的内容。
app消息订阅、报纸订阅、新闻订阅等等都是观察者模式,观察者模式无处不在,我们既是内容生产者也是内容的消费者。
我的启发
我们既是内容的生产者,不断的创造内容。作为内容的生产者,请保持内容的质量。我们也是内容的消费者,不断的消费内容,作为内容的消费者,请保持批判的精神。
网友评论