java 观察者模式_java设计模式之观察者模式

494c2ae6a0459fec219f9781d6d1e6f2.png

观察者模式

观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

观察者模式四大角色

Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供新增、删除、通知观察者的方法。

ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。

Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。

ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新

使用场景

商品变更的时候,需要更新商品缓存、发布商品详情页、更新搜索索引,传统做法,在商品update方法处,分别调用更新商品缓存接口、发布商品接口、更新搜索索引接口。代码耦合度很高,如果增加一个新的逻辑,需要修改update方法,如果商品修改不需要更新缓存了,同样需要修改update方法。通过引入观察者模式,通过消息中间件的方式可以进行解耦,当商品发生修改的时候,发送一个消息,商品缓存应用可以订阅此消息,进行缓存的更新。商品发布系统,订阅此消息,重新发布商品。搜索应用,订阅此消息,增量更新索引。

如果商品更改有其他的业务逻辑,可以通过消息订阅和消费,增加相应的逻辑。如果要去掉某个逻辑,只要取消消息订阅,不再消费此消息即可。观察者模式通过发布和订阅的方式,实现业务的解耦。

49d3fad2a95f6e45c67642ac4c725db6.png

代码实现

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 StudentObserver(String name,TeacherSubject teacherSubject) {
 this.name=name;
 this.subject = teacherSubject;
 //每新建一个学生对象,默认添加到观察者的行列
 teacherSubject.addObserver(this);
 }
 public void update(String info) {
 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(String info) {
 System.out.println(name+"得到作业:"+info);
 }
}
public class TestObserver {
 public static void main(String[] args) {
 TeacherSubject teacher = new TeacherSubject();
 StudentObserver zhangSan = new StudentObserver("张三", teacher);
 StudentObserver LiSi = new StudentObserver("李四", teacher);
 StudentObserver WangWu = new StudentObserver("王五", teacher);
 teacher.setHomework("第二页第六题");
 System.out.println("----------------");
 teacher.setHomework("第三页第七题");
 System.out.println("----------------");
 teacher.setHomework("第五页第八题");
 }
}

运行结果:

e4db34340b6093b7c2ef5eab8a465166.png

代码不是特别的严谨,没有考虑多线程问题,不是线程安全的,用于生产环境,需要做同步或者增加锁控制。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 implements Observer {
 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 class Test {
 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(new Message("关注","欢迎关注享知行"));
 //a关注了享知行
 messagePublishObservable.addObserver(messageObserverTopicA);
 //b关注了享知行
 messagePublishObservable.addObserver(messageObserverTopicB);
 //c关注了享知行
 messagePublishObservable.addObserver(messageObserverTopicC);
 messagePublishObservable.pushMessage();
 messagePublishObservable.setMessage(new Message("文章更新","公众号享知行更新啦"));
 messagePublishObservable.pushMessage();
 }
}

运行结果:

bbd97468ff594f28ee06c1df7b5ad8d6.png

优缺点

优点:发布者和订阅者是松耦合的,发布者和订阅者之间互不影响,满足开闭原则,当有变化的时候,实时,高效的通知订阅者。

缺点:如果一个发布者对象有很多直接和间接的订阅者的话,将所有的订阅者都通知到会花费很多时间。如果在发布者之间有循环依赖的话,发布者会触发它们之间进行循环调用,导致系统崩溃。

c8c37b8d5c7f76bf26b603ec301985d6.png

生活中的观察者模式

老师布置作业,采用的就是观察者模式,老师是信息的发布者,学生是订阅者,老师布置作业只需要布置一遍即可,所有的学生,都能收到这个任务。

邮件组也是观察者模式,可以动态的增加和删除组成员,技术部的所有成员创建一个邮件组,如果需要发送邮件通知所有技术部的人,只要发送一封邮件给技术部邮件组即可,既方便又不会遗漏。如果有员工入职加入邮件组,有员工离职则从邮件组删除。

群社区也是观察者模式的一种形式,有相同爱好兴趣的人加入到同一个群,每一个人既是消息的发布者,也是订阅者,让大家的沟通更实时高效。

专栏的订阅,公众号的关注也是属于观察者模式,内容生产者,有新的内容更新,会通知所有的订阅者,你如果喜欢“享知行”,并关注了公众号“享知行”,只要享知行有内容更新,会通知所有的粉丝。

直播和视频,同样也是观察者模式,内容生产者,直播或者把录好的视频上传,如果你感兴趣,点开观看,所有人看到的都是同样的内容。

app消息订阅、报纸订阅、新闻订阅等等都是观察者模式,观察者模式无处不在,我们既是内容生产者也是内容的消费者。

我的启发

我们既是内容的生产者,不断的创造内容。作为内容的生产者,请保持内容的质量。我们也是内容的消费者,不断的消费内容,作为内容的消费者,请保持批判的精神。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值