java observer模式_Java观察者模式(Observer)详解及应用

Java观察者模式(Observer)详解及应用

(2011-12-15 14:03:30)

标签:

杂谈

Java观察者模式(Observer)详解及应用

由于网站带有弱sns功能,因此需要设计关注和被关注的消息或是动作通知,那么将这个需求抽象出来的时候就会发现正好符合java中

订阅者模式,我还是喜欢叫观察着模式,具体网站的实现代码就不写了,写一个简单的例子大家了解下即可

一、概述

Java的设计模式很多,观察者模式被称为是模式中的皇后,而且Java

jdk也对它做了实现,可见该设计模式的重要位置。在图形化设计的软件中,为了实现视图和事件处理的分离,大多都采用了Observer模式,比如Java的Swing,Flex的ActionScript等。在现实的应用系统中也有好多应用,比如像当当网、京东商城一类的电子商务网站,如果你对某件商品比较关注,可以放到收藏架,那么当该商品降价时,系统给您发送手机短信或邮件。这就是观察者模式的一个典型应用,商品是被观察者,有的叫主体;关注该商品的客户就是观察者。下面的一个事例将模拟这个应用。

GoF说道:Observer模式的意图是“定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”。从这段话里我们可以得到两个信息,如下:

1, 观察者(具体执行操作的对象,有多个)

2, 被观察者(顾名思义是被观察的对象,如果该对象发生某些变化则通知观察者执行对应的操)

二、jdk中观察者模式解析

在java的util包中实现了该设计模式的框架,大部分应用都可以直接用它,当然了你也可以自己实现它,实际上就是一个被观察者的抽象类和一个观察者接口。我们先看一下jdk是如何实现的。被观察者的抽象类java.util.Observable

package java.util;

public class Observable {

private boolean changed = false;

private Vector obs;

//创建被观察者时就创建一个它持有的观察者列表,注意,这个列表是需要同步的。

public Observable() {

obs = new Vector();

}

public synchronized void addObserver(Observer o) {

if (o == null)

throw new NullPointerException();

if (!obs.contains(o)) {

obs.addElement(o);

}

}

public synchronized void deleteObserver(Observer o) {

obs.removeElement(o);

}

public void notifyObservers() {

notifyObservers(null);

}

public void notifyObservers(Object arg) {

Object[] arrLocal;

synchronized (this) {

if (!changed)

return;

arrLocal = obs.toArray();

clearChanged();

}

for (int i = arrLocal.length-1; i>=0; i--)

((Observer)arrLocal[i]).update(this, arg);

}

public synchronized void deleteObservers() {

obs.removeAllElements();

}

protected synchronized void setChanged() {

changed = true;

}

protected synchronized void clearChanged() {

changed = false;

}

public synchronized boolean hasChanged() {

return changed;

}

public synchronized int countObservers() {

return obs.size();

}

}

当我们自己的被观察者继承这个Observable类是,我们就自动的获取到被观察者的一切条件了。很方便是不是,这也是为什么sun要把Observable放到java.util包中的原因,就是为了方便开发者。

下面我们再看一下观察者的接口java.util.Observer

package java.util;

public interface Observer {

void update(Observable o, Object arg);

}

接口中就只有一个方法,update,方法中有两个参数,Observable和一个object,第一个参数就是被观察的对象,而第二个参数就得看业务需求了,需要什么就传进去什么。我们自己的观察者类必须实现这个方法,这样在被观察者调用notifyObservers操作时被观察者所持有的所有观察者都会执行update操作了.

三、观察者模式应用

下面是一个book对象,它是一个被观察者,所以要继承Observable。

import java.util.Observable;

public class Book extends Observable {

private String name = "";

private double price = 0.0;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public double getPrice() {

return price;

}

public void setPrice(double price) {

this.price = price;

}

//当书的价格修改时调用该方法

public void modifyPrice(Book b) {

//调用父类的方法,改变被观察者的状态

setChanged();

//通知客户该书已降价

notifyObservers(b);

}

}

下面是观察者对象,表示顾客的电子邮件,它实现了Observer接口。

import java.util.Observable;

import java.util.Observer;

public class BuyerEmail implements Observer {

private String buyerId = "";

private String email = "";

public String getBuyerId() {

return buyerId;

}

public void setBuyerId(String buyerId) {

this.buyerId = buyerId;

}

public String getEmail() {

return email;

}

public void setEmail(String email) {

this.email = email;

}

//该方法会被“被观察者的父类”既Observable调用

public void update(Observable o, Object arg) {

//这里做具体发电子邮件的操作

Book b = (Book)arg;

System.out.println("给顾客的发电子邮件:"+b.getName()+"降价了,目前价格为:"+b.getPrice());

}

}

下面是另一个观察者对象,表示顾客的手机,同样需要继承Observer接口

import java.util.Observable;

import java.util.Observer;

public class BuyerMobileMessage implements Observer {

private String buyerId = "";

private String mobileNo = "";

public String getBuyerId() {

return buyerId;

}

public void setBuyerId(String buyerId) {

this.buyerId = buyerId;

}

public String getMobileNo() {

return mobileNo;

}

public void setMobileNo(String mobileNo) {

this.mobileNo = mobileNo;

}

public void update(Observable o, Object arg) {

// TODO Auto-generated method stub

Book b = (Book)arg;

System.out.println("给顾客的发手机短信:"+b.getName()+"降价了,目前价格为:"+b.getPrice());

}

}

下面是调用类:

public class MainApp {

public static void main(String args[])

{

Book b1 = new Book();

b1.setName("<>");

b1.setPrice(45.00);//假设原价是60,现在是降价促销

//下面的观察者在实际的应用中可以从数据库或文件中读取

BuyerMobileMessage bm = new BuyerMobileMessage();

bm.setBuyerId("001");

bm.setMobileNo("13810500085");

BuyerEmail be = new BuyerEmail();

be.setBuyerId("001");

be.setEmail("dobodo@163.com");

//增加观察者,在实际应用中就是那些人对该书做了关注

b1.addObserver(bm);

b1.addObserver(be);

b1.modifyPrice(b1);

}

}

输出:

给顾客的发电子邮件:<>降价了,目前价格为:45.0

给顾客的发手机短信:<>降价了,目前价格为:45.0

不知道上面的例子你看懂了没有,观察者模式实际上没什么高深的东西,就是运用了java的继承和接口,在被观察者的抽象类里设置一个状态标志,通过该标志判断是否通知观察者对象。在学习该模式的同时,我们更应该学习java的继承和接口的灵活应用,其实所有的设计模式都是继承、接口、多态的灵活应用

分享:

a4c26d1e5885305701be709a3d33442f.png喜欢

0

a4c26d1e5885305701be709a3d33442f.png赠金笔

加载中,请稍候......

评论加载中,请稍候...

发评论

登录名: 密码: 找回密码 注册记住登录状态

昵   称:

评论并转载此博文

a4c26d1e5885305701be709a3d33442f.png

发评论

以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/551012.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java bundle管理_java.util.ResourceBundle使用详解

一、认识国际化资源文件这个类提供软件国际化的捷径。通过此类&#xff0c;可以使您所编写的程序可以&#xff1a;轻松地本地化或翻译成不同的语言一次处理多个语言环境以后可以轻松地进行修改&#xff0c;支持更多的语言环境说的简单点&#xff0c;这个类的作用就是读取资源属…

java源代码实例倒计时_Java倒计时三种实现方式代码实例

写完js倒计时&#xff0c;突然想用java实现倒计时&#xff0c;写了三种实现方式一&#xff1a;设置时长的倒计时&#xff1b;二&#xff1a;设置时间戳的倒计时&#xff1b;三&#xff1a;使用java.util.Timer类实现的时间戳倒计时代码如下&#xff1a;package timer;import ja…

python二维表转一维表_二维表格转换成一维表格

# 加载数据import pandas as pddf_old1 pd.read_excel(r"D:\Jupyter\data\Python.xlsx",sheet_name "变一维")df_old1# 数据清洗&#xff0c;把第一列设为索引列df_old2 pd.read_excel(r"D:\Jupyter\data\Python.xlsx",sheet_name "变一…

java web后台_java web 后台那些事

java web 后台运行原理当Web服务器接收到一个HTTP请求时&#xff0c;它会先判断请求内容——如果是静态网页数据&#xff0c;Web服务器将会自行处理&#xff0c;然后产生响应信息&#xff1b;如果牵涉到动态数据&#xff0c;Web服务器会将请求转交给Servlet容器。此时Servlet容…

java 反射机制 视频_JAVA反射机制及其原理实现

9.1 概念JAVA反射机制是在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够知道这个类的所有属性和方法&#xff1b;对于任意一个对象&#xff0c;都能够调用它的任意方法和属性&#xff1b;public、protected、private。OO(面向对象)&#xff0c;private私有的&#x…

java 安卓下载文件_GitHub - Charay/downloadfile: 使用Retrofit2+Rxjava+Rxandroid+okhttp的方式下载文件并存储到sd卡指定目录...

downloadfile使用Retrofit2RxjavaRxandroidokhttp的方式下载文件并存储到sd卡指定目录使用&#xff1a;gradleStep 1.在工程build.gradle文件中加入maven地址repositories:allprojects {repositories {...maven { url https://jitpack.io }}}Step 2. 在module的build.gradle中添…

java基础 最重要的部分_Java基础(1)最基础的部分

本文章均为自己在自学期间整理的笔记&#xff0c;2020年四月份开始学习Java&#xff0c;如有不足&#xff0c;请补充。希望对各位小伙伴都能有帮助。1.Java中public class和class区别&#xff1a;1)在一个Java文件中可以定义多个class 2)public的class不是必须的 3)public修…

php解析bt,PHP基于闭包思想实现的BT(torrent)文件解析工具实例详解

本文实例讲述了PHP基于闭包思想实现的torrent文件解析工具。分享给大家供大家参考&#xff0c;具体如下&#xff1a;PHP对静态词法域的支持有点奇怪&#xff0c;内部匿名函数必须在参数列表后面加上use关键字&#xff0c;显式的说明想要使用哪些外层函数的局部变量。function c…

java怎么让1的数据2可以拥有,【如何让代码变“高级”(二)】-这样操作值得一波666(Java Stream)(这么有趣)...

“致"高级"工程师(BUG工程师)一颗折腾的心原创不易&#xff0c;点个赞&#x1f497;&#xff0c;支持支持开发中的代码在开发中的代码是不是很常见这样的代码&#xff1a;这样的?for循环取元素取值List szUserList new ArrayList<>();for (User user : userL…

php+页面加载进度,基于jQuery实现模拟页面加载进度条_jquery

因为我们无法通过任何方法获取整个页面的大小和当前加载了多少&#xff0c;所以想制作一个加载进度条的唯一办法就是模拟。那要怎么模拟呢&#xff1f;我们知道&#xff0c;页面是从上往下执行的&#xff0c;也就是说我们可以大致估算出在页面的某个位置加载了多少&#xff0c;…

nifi将hive同步到oracle,NiFi使用总结 一 hive到hive的PutHiveStreaming processor和SelectHiveQL...

我说实话&#xff0c;NiFi的坑真的挺多的。。。1、PutHiveStreaming processor的使用该控制器配置需要hive启用事物&#xff1b;且目前只支持orc格式&#xff0c;且建表需要分桶&#xff0c;开启事务等&#xff0c;建表示例如下&#xff1a;create tabletest_trancaction(user_…

rds oracle,Amazon RDS Oracle数据库托管

您可通过两种不同的许可模式运行 Amazon RDS for Oracle&#xff0c;即“附带许可”和“使用自有许可 (BYOL)”。在“附带许可”服务模型中&#xff0c;您无需单独购买 Oracle 许可&#xff1b;Oracle 数据库软件软件由 AWS 提供授权许可。“附带许可”的起价为 0.04 USD/小时&…

linux目录下有斜杠,Windows和Linux路径中斜杠/和反斜杠\ 的区别

Unix使用斜杆/ 作为路径分隔符&#xff0c;而web应用最新使用在Unix系统上面&#xff0c;所以目前所有的网络地址都采用 斜杆/ 作为分隔符。Windows由于使用 斜杆/ 作为DOS命令提示符的参数标志了&#xff0c;为了不混淆&#xff0c;所以采用 反斜杠\ 作为路径分隔符。所以目前…

telnet服务下载 Linux,linux telnet服务安装包

这是linux telnet服务安装包下载&#xff0c; telnet-client 客户端安装包、telnet-server服务端安装包和xinetd依赖包&#xff0c;本人在linux retHat 32位系统上亲自安装过&#xff0c;若您依旧安装不成功&#xff0c;没关系&#xff0c;在附赠.txt中&#xff0c;打开这个链接…

linux挂载硬盘的分区创建,Linux 新增硬盘、新建分区、格式化硬盘、挂载硬盘的操作...

今天学校有一台机器发现有块硬盘没有挂载&#xff0c;然后叫我挂载一下&#xff0c;这里记录一下 Linux 下新增硬盘分区、格式化硬盘、挂载硬盘的操作。查看当前硬盘首先我们查看一下当前的硬盘配置。使用命令sudo fdisk -l就可以看到目前的硬盘了。可以看到有块空的 sda(这里忘…

Win10 Linux GPT分区方案,win10+Ubuntu 20.04 LTS双系统安装(UEFI + GPT)(图文,多图预警)

win10 安装(已安装的略过)制作启动u盘插入U盘&#xff0c; 运行 rufus-3.10.exe&#xff0c;按照下面选择&#xff0c;然后点击开始&#xff0c;等待完成即可为Ubuntu安装空出分区此电脑->管理->磁盘管理&#xff0c;选择一个磁盘右键选择压缩卷&#xff0c;压缩出50G以上…

linux关闭4750 端口,【ubuntu分享帖】acer 4750G ubuntu安装后的一些设置

本帖最后由 love雨阳 于 2011-11-7 13:27 编辑本帖前提&#xff1a;已经成功安装ubuntu11.10 网卡驱动默认成功1.安装完之后&#xff0c;开机&#xff0c;进入ubunt 第一件事当然是联网,首先&#xff0c;确定你的网络链接方式&#xff0c;如果是路由器自动分配ip的那种应该不用…

linux软件中心替代,Ubuntu 16.04 LTS 将替换 Ubuntu 软件中心

Ubuntu 软件中心在 Ubuntu 16.04 LTS 被移除了。Xenial Xerus 桌面用户会发现非常熟悉的 Ubuntu Software Center 找不到了。GNOME 的软件应用 将会 – 根据当前的计划 – 作为基于 Unity 7 桌面的默认的包管理应用。GNOME 软件应用Ubuntu 将创建新插件来支持新 Software Cente…

linux脚本算术函数,Linux基础之bash脚本编程初级-变量与算术运算

什么是变量&#xff1f;变量最初来源于数学&#xff0c;指的是非固定的值可变化的数通常用拉丁字母表示。在计算机中变量它依旧指的是可变化的数&#xff0c;只不过表现形式有些变化。它指的是变量名所指向的内存空间。以下实验环境均在CentOS7.2进行变量的特点变量分强类型变量…

存储管理实验linux,07-存储管理器实验

S3C2440的存储控制器提供了访问外设所需要的信号&#xff0c;它有如下特性&#xff1a;支持大/小端字节(通过软件选择)&#xff1b;每个BANK的地址空间为128MB&#xff0c;总共1GB(8个BANK)&#xff1b;可编程控制的总线宽度(8/16&#xff0f;32bit)&#xff0c;BANK0只有两种位…