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

简介:

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

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


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

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

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

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

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

观察者模式例子

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

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

01 package com.journaldev.design.observer;
02  
03 public 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的变化通知。

01 package com.journaldev.design.observer;
02  
03 public 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 }

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

01 package com.journaldev.design.observer;
02  
03 import java.util.ArrayList;
04 import java.util.List;
05  
06 public 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 == nullthrow 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对象。

01 package com.journaldev.design.observer;
02  
03 public 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()方法。

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

01 package com.journaldev.design.observer;
02  
03 public 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 }

此处为上述输出内容:

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

观察者模式的UML图
observer-pattern

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

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

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

相关文章
|
9天前
|
安全 Java
Java之泛型使用教程
Java之泛型使用教程
111 10
|
21天前
|
存储 Java 关系型数据库
Java 项目实战基于面向对象思想的汽车租赁系统开发实例 汽车租赁系统 Java 面向对象项目实战
本文介绍基于Java面向对象编程的汽车租赁系统技术方案与应用实例,涵盖系统功能需求分析、类设计、数据库设计及具体代码实现,帮助开发者掌握Java在实际项目中的应用。
41 0
|
2月前
|
Java 关系型数据库 数据库
Java 项目实战教程从基础到进阶实战案例分析详解
本文介绍了多个Java项目实战案例,涵盖企业级管理系统、电商平台、在线书店及新手小项目,结合Spring Boot、Spring Cloud、MyBatis等主流技术,通过实际应用场景帮助开发者掌握Java项目开发的核心技能,适合从基础到进阶的学习与实践。
229 3
|
3月前
|
缓存 安全 Java
Java 并发新特性实战教程之核心特性详解与项目实战
本教程深入解析Java 8至Java 19并发编程新特性,涵盖CompletableFuture异步编程、StampedLock读写锁、Flow API响应式流、VarHandle内存访问及结构化并发等核心技术。结合电商订单处理、缓存系统、实时数据流、高性能计数器与用户资料聚合等实战案例,帮助开发者高效构建高并发、低延迟、易维护的Java应用。适合中高级Java开发者提升并发编程能力。
75 0
|
3月前
|
安全 Java 测试技术
Java 大学期末实操项目在线图书管理系统开发实例及关键技术解析实操项目
本项目基于Spring Boot 3.0与Java 17,实现在线图书管理系统,涵盖CRUD操作、RESTful API、安全认证及单元测试,助力学生掌握现代Java开发核心技能。
113 1
|
4月前
|
存储 算法 Java
【Java实例-智慧牌局】Java实现赌桌上的21点
游戏规则:游戏开始时,玩家和庄家各获得两张牌,玩家可以看到自己手中的两张牌以及庄家的一张明牌。玩家需要根据手中的牌面总和,选择“要牌”(Hit)以获取更多牌,或“停牌”(Stand)停止要牌。如果玩家的牌面总和超过21点,即为爆牌,玩家立即输掉游戏。若玩家选择停牌,庄家则开始行动,其策略是当牌面总和小于17点时必须继续要牌。若庄家牌面总和超过21点,则庄家爆牌,玩家获胜。若双方均未爆牌,最终比较牌面总和,更接近21点的一方获胜;若牌面总和相同,则游戏以平局结束。
64 0
|
4月前
|
Java 开发者
【Java实例-英雄对战】Java战斗之旅,既分胜负也决生死
游戏规则:在“英雄对战”中,玩家和敌人轮流选择行动,目标是在对方生命值归零前将其击败。游戏开始时,玩家和敌人都有100生命值。每回合,玩家可以选择“攻击”,“追击”,“闪避反击”这三种行动之一。
59 0
|
4月前
|
Oracle Java 关系型数据库
java 编程基础入门级超级完整版教程详解
这份文档是针对Java编程入门学习者的超级完整版教程,涵盖了从环境搭建到实际项目应用的全方位内容。首先介绍了Java的基本概念与开发环境配置方法,随后深入讲解了基础语法、控制流程、面向对象编程的核心思想,并配以具体代码示例。接着探讨了常用类库与API的应用,如字符串操作、集合框架及文件处理等。最后通过一个学生成绩管理系统的实例,帮助读者将理论知识应用于实践。此外,还提供了进阶学习建议,引导学员逐步掌握更复杂的Java技术。适合初学者系统性学习Java编程。资源地址:[点击访问](https://pan.quark.cn/s/14fcf913bae6)。
324 2
|
4月前
|
Java
【Java实例-小兵拆炸弹】Java打造数学挑战-拆炸弹
今天,我将向大家分享一款用Java开发的控制台小案例——“小兵拆炸弹”。游戏规则:玩家需要在有限的尝试次数内解开一系列数学题,以成功拆解炸弹。游戏的目标是连续答对五道数学题,每道题都由系统随机生成。如果玩家在五次机会内成功解密,游戏胜利;否则,炸弹爆炸,游戏结束。
74 0
|
4月前
|
Java 开发者
【Java实例-神秘年龄】用Java挑战你的直觉
我们一起走进这款款简单却充满趣味的Java小游戏——“神秘年龄”。这款游戏不仅适合编程初学者作为练习项目,也能为有一定基础的开发者提供一个轻松的编程小憩。
46 0
【Java实例-神秘年龄】用Java挑战你的直觉