Java中的观察者模式实例讲解

所属分类: 软件编程 / java 阅读数: 46
收藏 0 赞 0 分享

观察者模式是一种行为设计模式。观察者模式的用途是,当你对一个对象的状态感兴趣,希望在它每次发生变化时获得通知。在观察者模式中,观察另外一个对象状态的对象叫做Observer观察者,被观察的对象叫着Subject被观察者。根据GoF规则,观察者模式的意图是:

复制代码 代码如下:

定义对象之间一对多的依赖关系,一个对象状态改变,其他相关联的对象就会得到通知并被自动更新。

Subject(被观察者)包含了一些需要在其状态改变时通知的观察者。因此,他应该提供给观察者可以register(注册)自己和unregister(注销)自己的方法。当Subject(被观察者)发生变化的时候,也需要包含一个方法来通知所有观察者。当通知观察者的时候,可以推送更新内容,或者提供另外一个方法来获得更新内容。

观察者应该有一种方法,这种方法能够设置观察者对象并且可以由被观察者使用来通知其更新。

JAVA提供了内置的方式来实现观察者模式,java.util.Observable和java.util.Observer接口。然而他们用的不是很广泛。因为此实现过于简单,大多数时候我们都不想最后扩展的类仅仅是实现了观察者模式,因为JAVA类不能多继承。

Java Messages Service(JMS)消息服务使用观察者模式与命令模式来实现不同的程序之间的数据的发布和订阅。

MVC模型-视图-控制框架也使用观察者模式,把模型当做被观察者,视图视为观察者。视图能够注册自己到模型上来获得模型的改变。

观察者模式例子

在此例中,我们将完成一个简单的主题讨论,观察者能够注册此主题。任何在此主题上的内容提交导致的变化都会通知所有在注册的观察者。

基于Subject被观察者的需求,这个是实现一个基本的Subject接口,此接口定了一系列具体的方法需要在随后实现接口的具体类中被实现。

复制代码 代码如下:

package com.journaldev.design.observer;

public interface Subject {

 //methods to register and unregister observers
 public void register(Observer obj);
 public void unregister(Observer obj);

 //method to notify observers of change
 public void notifyObservers();

 //method to get updates from subject
 public Object getUpdate(Observer obj);

}

现在创建一个相关联的观察者。它需要有一个方法能使Subject附属于一个观察者。另外的方法能够接受Subject的变化通知。

复制代码 代码如下:

package com.journaldev.design.observer;

public interface Observer {

 //method to update the observer, used by subject
 public void update();

 //attach with subject to observe
 public void setSubject(Subject sub);
}

这种关联已经建立。现在实现具体的主题。

复制代码 代码如下:

package com.journaldev.design.observer;

import java.util.ArrayList;
import java.util.List;

public class MyTopic implements Subject {

 private List<Observer> observers;
 private String message;
 private boolean changed;
 private final Object MUTEX= new Object();

 public MyTopic(){
  this.observers=new ArrayList<>();
 }
 @Override
 public void register(Observer obj) {
  if(obj == null) throw new NullPointerException("Null Observer");
  if(!observers.contains(obj)) observers.add(obj);
 }

 @Override
 public void unregister(Observer obj) {
  observers.remove(obj);
 }

 @Override
 public void notifyObservers() {
  List<Observer> observersLocal = null;
  //synchronization is used to make sure any observer registered after message is received is not notified
  synchronized (MUTEX) {
   if (!changed)
    return;
   observersLocal = new ArrayList<>(this.observers);
   this.changed=false;
  }
  for (Observer obj : observersLocal) {
   obj.update();
  }

 }

 @Override
 public Object getUpdate(Observer obj) {
  return this.message;
 }

 //method to post message to the topic
 public void postMessage(String msg){
  System.out.println("Message Posted to Topic:"+msg);
  this.message=msg;
  this.changed=true;
  notifyObservers();
 }

}

注册与注销观察者方法的实现非常简单,额外的方法postMessage()将被客户端应用来提交一个字符串消息给此主题。注意,布尔变量用于追踪主题状态的变化并且通知观察者此种变化。这个变量是必须的,因为如果没有更新,但是有人调用notifyObservers()方法,他就不能发送错误的通知信息给观察者。

此外需要注意的是,notifyObservers()中使用synchronization同步的方式来确保在消息被发布给主题之前,通知只能被发送到注册的观察者处。

此处是观察者的实现。他们将一直关注subject对象。

复制代码 代码如下:

package com.journaldev.design.observer;

public class MyTopicSubscriber implements Observer {

 private String name;
 private Subject topic;

 public MyTopicSubscriber(String nm){
  this.name=nm;
 }
 @Override
 public void update() {
  String msg = (String) topic.getUpdate(this);
  if(msg == null){
   System.out.println(name+":: No new message");
  }else
  System.out.println(name+":: Consuming message::"+msg);
 }

 @Override
 public void setSubject(Subject sub) {
  this.topic=sub;
 }

}

注意,update()方法的实现使用了被观察者的getUpdate()来处理更新的消息。此处应该避免把消息作为参数传递给update()方法。

一下为简单地测试程序来验证话题类的实现。

复制代码 代码如下:

package com.journaldev.design.observer;

public class ObserverPatternTest {

 public static void main(String[] args) {
  //create subject
  MyTopic topic = new MyTopic();

  //create observers
  Observer obj1 = new MyTopicSubscriber("Obj1");
  Observer obj2 = new MyTopicSubscriber("Obj2");
  Observer obj3 = new MyTopicSubscriber("Obj3");

  //register observers to the subject
  topic.register(obj1);
  topic.register(obj2);
  topic.register(obj3);

  //attach observer to subject
  obj1.setSubject(topic);
  obj2.setSubject(topic);
  obj3.setSubject(topic);

  //check if any update is available
  obj1.update();

  //now send message to subject
  topic.postMessage("New Message");
 }

}

此处为上述输出内容:

复制代码 代码如下:

Obj1:: No new message
Message Posted to Topic:New Message
Obj1:: Consuming message::New Message
Obj2:: Consuming message::New Message
Obj3:: Consuming message::New Message</pre>

观察者模式的UML图

观察者模式也被叫做发布订阅模式。JAVA中的一些具体应用如下:

1.Swing 中的 java.util.EventListener
2.javax.servlet.http.HttpSessionBindingListener
3.javax.servlet.http.HttpSessionAttributeListener

以上为全部的观察者模式。希望你已经喜欢上它了。在评论中分享你的感受或者请分享给其他人。

更多精彩内容其他人还在看

SpringBoot中使用Ehcache的详细教程

EhCache 是一个纯 Java 的进程内缓存框架,具有快速、精干等特点,是 Hibernate 中默认的 CacheProvider。这篇文章主要介绍了SpringBoot中使用Ehcache的相关知识,需要的朋友可以参考下
收藏 0 赞 0 分享

在idea 中添加和删除模块Module操作

这篇文章主要介绍了在idea 中添加和删除模块Module操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
收藏 0 赞 0 分享

java spring整合junit操作(有详细的分析过程)

这篇文章主要介绍了java spring整合junit操作(有详细的分析过程),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
收藏 0 赞 0 分享

详解JAVA 弱引用

这篇文章主要介绍了 JAVA 弱引用的相关资料,帮助大家更好的理解和学习java引用对象,感兴趣的朋友可以了解下
收藏 0 赞 0 分享

深入了解JAVA 虚引用

这篇文章主要介绍了JAVA 虚引用的相关资料,帮助大家更好的理解和学习JAVA,感兴趣的朋友可以了解下
收藏 0 赞 0 分享

详解JAVA 强引用

这篇文章主要介绍了JAVA 强引用的相关资料,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
收藏 0 赞 0 分享

java中的按位与(&)用法说明

这篇文章主要介绍了java中的按位与(&)用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
收藏 0 赞 0 分享

深入了解JAVA 软引用

这篇文章主要介绍了JAVA 软引用的相关资料,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
收藏 0 赞 0 分享

利用MyBatis实现条件查询的方法汇总

这篇文章主要给大家介绍了关于利用MyBatis实现条件查询的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用MyBatis具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
收藏 0 赞 0 分享

Intellij IDEA 与maven 版本不符 Unable to import maven project See logs for details: No implementation for org.apache.maven.model.path.PathTranslator was bound

这篇文章主要介绍了Intellij IDEA 与maven 版本不符 Unable to import maven project See logs for details: No implementation for org.apache.maven.model.path.Pa
收藏 0 赞 0 分享
查看更多