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

来源:互联网 发布:淘宝图片轮播怎么设置 编辑:程序博客网 时间:2024/04/29 17:20

原文链接  作者:Pankaj Kumar 译者:f0tlo <1357654289@qq.com>  校对:方腾飞

观察者模式是一种行为设计模式。观察者模式的用途是,当你对一个对象的状态感兴趣,希望在它每次发生变化时获得通知。在观察者模式中,观察另外一个对象状态的对象叫做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 interfaceSubject {
04 
05    //methods to register and unregister observers
06    publicvoid register(Observer obj);
07    publicvoid unregister(Observer obj);
08 
09    //method to notify observers of change
10    publicvoid notifyObservers();
11 
12    //method to get updates from subject
13    publicObject getUpdate(Observer obj);
14 
15}

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

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

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

01package com.journaldev.design.observer;
02 
03import java.util.ArrayList;
04import java.util.List;
05 
06public classMyTopic implements Subject {
07 
08    privateList<Observer> observers;
09    privateString message;
10    privateboolean changed;
11    privatefinal Object MUTEX= newObject();
12 
13    publicMyTopic(){
14        this.observers=newArrayList<>();
15    }
16    @Override
17    publicvoid register(Observer obj) {
18        if(obj ==null) thrownew NullPointerException("Null Observer");
19        if(!observers.contains(obj)) observers.add(obj);
20    }
21 
22    @Override
23    publicvoid unregister(Observer obj) {
24        observers.remove(obj);
25    }
26 
27    @Override
28    publicvoid 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    publicObject getUpdate(Observer obj) {
45        returnthis.message;
46    }
47 
48    //method to post message to the topic
49    publicvoid 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 classMyTopicSubscriber implementsObserver {
04 
05    privateString name;
06    privateSubject topic;
07 
08    publicMyTopicSubscriber(String nm){
09        this.name=nm;
10    }
11    @Override
12    publicvoid 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    publicvoid setSubject(Subject sub) {
22        this.topic=sub;
23    }
24 
25}

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

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

01package com.journaldev.design.observer;
02 
03public classObserverPatternTest {
04 
05    publicstatic 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 newmessage
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

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

转载自并发编程网 – ifeve.com本文链接地址:JAVA中的观察者模式实例教程

0 0
原创粉丝点击