JAVA中的观察者模式实例教程

本文详细介绍了观察者模式,包括其定义、用途、Java中的实现方式,并给出了一段简单的示例代码。通过示例解释了如何创建Subject和Observer,以及如何在Subject中通知Observer。文章还提到了JMS和MVC框架中观察者模式的应用,并展示了观察者模式的UML图,最后列举了Java中观察者模式的实际应用。
摘要由CSDN通过智能技术生成

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

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


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

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

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

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

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

观察者模式例子

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

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

01package com.journaldev.design.observer;
02 
03public interface Subject {
04 
05    //methods to register and unregister observers
06    public void register(Observer obj);
07    public void unregister(Observer obj);
08 
09    //method to notify observers of change
10    public void notifyObservers();
11 
12    //method to get updates from subject
13    public Object getUpdate(Observer obj);
14 
15}

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

01package com.journaldev.design.observer;
02 
03public interface Observer {
04 
05    //method to update the observer, used by subject
06    public void update();
07 
08    //attach with subject to observe
09    public void setSubject(Subject sub);
10}

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

01package com.journaldev.design.observer;
02 
03import java.util.ArrayList;
04import java.util.List;
05 
06public class MyTopic implements Subject {
07 
08    private List<Observer> observers;
09    private String message;
10    private boolean changed;
11    private final Object MUTEX= new Object();
12 
13    public MyTopic(){
14        this.observers=new ArrayList<>();
15    }
16    @Override
17    public void register(Observer obj) {
18        if(obj == null) throw new NullPointerException("Null Observer");
19        if(!observers.contains(obj)) observers.add(obj);
20    }
21 
22    @Override
23    public void unregister(Observer obj) {
24        observers.remove(obj);
25    }
26 
27    @Override
28    public void notifyObservers() {
29        List<Observer> observersLocal = null;
30        //synchronization is used to make sure any observer registered after message is received is not notified
31        synchronized (MUTEX) {
32            if (!changed)
33                return;
34            observersLocal = new ArrayList<>(this.observers);
35            this.changed=false;
36        }
37        for (Observer obj : observersLocal) {
38            obj.update();
39        }
40 
41    }
42 
43    @Override
44    public Object getUpdate(Observer obj) {
45        return this.message;
46    }
47 
48    //method to post message to the topic
49    public void postMessage(String msg){
50        System.out.println("Message Posted to Topic:"+msg);
51        this.message=msg;
52        this.changed=true;
53        notifyObservers();
54    }
55 
56}

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

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

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

01package com.journaldev.design.observer;
02 
03public class MyTopicSubscriber implements Observer {
04 
05    private String name;
06    private Subject topic;
07 
08    public MyTopicSubscriber(String nm){
09        this.name=nm;
10    }
11    @Override
12    public void update() {
13        String msg = (String) topic.getUpdate(this);
14        if(msg == null){
15            System.out.println(name+":: No new message");
16        }else
17        System.out.println(name+":: Consuming message::"+msg);
18    }
19 
20    @Override
21    public void setSubject(Subject sub) {
22        this.topic=sub;
23    }
24 
25}

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

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

01package com.journaldev.design.observer;
02 
03public class ObserverPatternTest {
04 
05    public static void main(String[] args) {
06        //create subject
07        MyTopic topic = new MyTopic();
08 
09        //create observers
10        Observer obj1 = new MyTopicSubscriber("Obj1");
11        Observer obj2 = new MyTopicSubscriber("Obj2");
12        Observer obj3 = new MyTopicSubscriber("Obj3");
13 
14        //register observers to the subject
15        topic.register(obj1);
16        topic.register(obj2);
17        topic.register(obj3);
18 
19        //attach observer to subject
20        obj1.setSubject(topic);
21        obj2.setSubject(topic);
22        obj3.setSubject(topic);
23 
24        //check if any update is available
25        obj1.update();
26 
27        //now send message to subject
28        topic.postMessage("New Message");
29    }
30 
31}

此处为上述输出内容:

1Obj1:: No new message
2Message Posted to Topic:New Message
3Obj1:: Consuming message::New Message
4Obj2:: Consuming message::New Message
5Obj3:: Consuming message::New Message</pre>

观察者模式的UML图
observer-pattern

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

  • Swing 中的 java.util.EventListener
  • javax.servlet.http.HttpSessionBindingListener
  • javax.servlet.http.HttpSessionAttributeListener

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

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值