java jdk 观察者模式_java观察者模式实现和java观察者模式演化
简单的观察者模式实现
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* 观察者模式中用到了回调:
* A. 观察者将自己注册到被观察者的监听者列表,且观察者类自身提供了一个回调函数
* B. 被观察者(Observable或Subject)维护观察者列表,并且可以注册和解注册观察者
* C. 一旦被观察者状态发生改变,它可以调用notifyObservers(),这个方法将遍历观察者列表并逐个调用
观察者提供的回调函数
* @author will
*
*/
public class SimpleObserverPattern {
public static void main(String[] args) {
SimpleObserverPattern sop = new SimpleObserverPattern();
List observers = new ArrayList ();
IObserver observerA = sop.new Observer("ObserverA");
IObserver observerB = sop.new Observer("ObserverB");
observers.add(observerA);
observers.add(observerB);
IObservable observable = sop.new Observable(observers);
observable.registerObserver(sop.new Observer("ObserverC"));
observable.changeState();
observable.close();
}
// 被观察者,有的地方叫Subject
interface IObservable {
void registerObserver(IObserver observer);
void unregisterObserver(IObserver observer);
void notifyObservers();
String getState();
void changeState();
void close();
}
class Observable implements IObservable {
private static final String NEW = "New";
private static final String CHANGED = "Changed";
private static final String CLOSED = "Closed";
private String state;
private List observers;
public Observable() {
this(null);
}
public Observable(List observers) {
if(observers == null) {
observers = new ArrayList ();
}
this.observers = Collections.synchronizedList(observers);
this.state = NEW;
}
@Override
public void registerObserver(IObserver observer) {
observers.add(observer);
}
@Override
public void unregisterObserver(IObserver observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
Iterator iter = observers.iterator();
while(iter.hasNext()) {
iter.next().update(this);
}
}
@Override
public String getState() {
return state;
}
@Override
public void changeState() {
this.state = CHANGED;
notifyObservers();
}
@Override
public void close() {
this.state = CLOSED;
notifyObservers();
}
}
interface IObserver {
void update(IObservable observalbe);
}
class Observer implements IObserver {
private String name;
public Observer(String name) {
this.name = name;
}
@Override
public void update(IObservable observalbe) {
System.out.println(
String.format("%s receive observalbe's change, current observalbe's state is %s",
name, observalbe.getState()));
}
}
}
上面的实现直接将被观察者对象作为回调函数参数,这样做很不优雅,在简单的场景可能奏效。
但事实上更多情况下,一个被观察者有很多种事件或者状态,而每个观察者可能感兴趣的事件或状态都不相同,或者为了信息隐藏的目的,不想让每个观察者都能访问到Observable内部的所有状态。
这样我继续演化代码为下面这个版本,注意我这里没有很细致地考虑并发问题。
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
public class MultiEventObserverPattern {
public static void main(String[] args) {
MultiEventObserverPattern meop = new MultiEventObserverPattern();
IObservable observable = meop.new Observable();
IObserver observerA = meop.new Observer("ObserverA");
IObserver observerB = meop.new Observer("ObserverB");
// 注册感兴趣的事件
observable.registerObserver(observable.getEventA(), observerA);
observable.registerObserver(observable.getEventB(), observerB);
// 改变被观察者状态
observable.changeStateA();
observable.changeStateB();
}
interface IEvent {
void eventChange();
String getState();
}
class EventA implements IEvent {
private static final String INITIALIZED = "Initialized";
private static final String PENDING = "Pending";
private String state;
public EventA() {
this.state = INITIALIZED;
}
@Override
public void eventChange() {
System.out.println("EventA change");
this.state = PENDING;
}
@Override
public String toString() {
return "EventA";
}
@Override
public String getState() {
return state;
}
}
class EventB implements IEvent {
private static final String NEW = "New";
private static final String IDLE = "Idle";
private String state;
public EventB() {
this.state = NEW;
}
@Override
public void eventChange() {
System.out.println("EventB change");
this.state = IDLE;
}
@Override
public String toString() {
return "EventB";
}
@Override
public String getState() {
return state;
}
}
// 被观察者(Observable),有的地方叫Subject
interface IObservable {
void registerObserver(IEvent event, IObserver observer);
void unregisterObserver(IEvent event, IObserver observer);
// 通知观察者某个事件发生了
void notifyObservers(IEvent event);
void changeStateA();
void changeStateB();
IEvent getEventA();
IEvent getEventB();
}
class Observable implements IObservable {
private IEvent eventA;
private IEvent eventB;
private Hashtable> eventObserverMapping;
public Observable() {
this(null);
}
// 这里如果evenObserverMapping传入的某些Set是未被同步修饰的,那么也没办法
public Observable(Hashtable> eventObserverMapping) {
if(eventObserverMapping == null) {
eventObserverMapping = new Hashtable> ();
}
this.eventObserverMapping = new Hashtable> ();
this.eventA = new EventA();
this.eventB = new EventB();
}
@Override
public void registerObserver(IEvent event, IObserver observer) {
Set observers = eventObserverMapping.get(event);
if(observers == null) {
observers = Collections.synchronizedSet(new HashSet ());
observers.add(observer);
eventObserverMapping.put(event, observers);
}
else {
observers.add(observer);
}
}
@Override
public void unregisterObserver(IEvent event, IObserver observer) {
Set observers = eventObserverMapping.get(event);
if(observers != null) {
observers.remove(observer);
}
}
@Override
public void notifyObservers(IEvent event) {
Set observers = eventObserverMapping.get(event);
if(observers != null && observers.size() > 0) {
Iterator iter = observers.iterator();
while(iter.hasNext()) {
iter.next().update(event);
}
}
}
@Override
public void changeStateA() {
// 改变状态A会触发事件A
eventA.eventChange();
notifyObservers(eventA);
}
@Override
public void changeStateB() {
// 改变状态B会触发事件B
eventB.eventChange();
notifyObservers(eventB);
}
@Override
public IEvent getEventA() {
return eventA;
}
@Override
public IEvent getEventB() {
return eventB;
}
}
interface IObserver {
void update(IEvent event);
}
class Observer implements IObserver {
private String name;
public Observer(String name) {
this.name = name;
}
@Override
public void update(IEvent event) {
System.out.println(
String.format("%s receive %s's change, current observalbe's state is %s",
name, event, event.getState()));
}
}
}
似乎看起来挺完美了,但还是不够完美。因为事件被硬编码为被观察者类的属性。这样事件类型在编译时期就被定死了,如果要增加新的事件类型就不得不修改IObservable接口和Observable类,这大大削减了灵活性。
相当于被观察者耦合于这些具体的事件,那么我们如何来打破这个限制呢?
答案是引入一个新的组件,让那个组件来管理事件、观察者、被观察者之间的关系,事件发生时也由那个组件来调用观察者的回调函数。这也是一种解耦吧,有点类似Spring的IOC容器。
至于具体实现,我觉得Guava EventBus做得已经蛮好了,可以参考我前面提到的链接。
PS:本帖不是为Guava EventBus做广告,只是自己的思路一步步推进,逐渐地就和Guava EventBus的设计思路吻合了。
下面继续看看JDK标准类实现观察者模式的例子,然后分析下它的源码实现,要看的只有一个Observable类和一个Observer接口。
JDK标准类实现观察者模式
import java.util.Observable;
import java.util.Observer;
/**
* 使用java.util包中的标准类实现观察者模式
* @author will
*
*/
public class JDKObserverDemo {
public static void main(String[] args) {
JDKObserverDemo jod = new JDKObserverDemo();
// 被观察者
MyObservable myObservable = jod.new MyObservable("hello");
// 观察者
Observer myObserver = jod.new MyObserver();
// 注册
myObservable.addObserver(myObserver);
// 改变被观察者状态,触发观察者回调函数
myObservable.setValue("will");
}
class MyObservable extends Observable {
private String watchedValue; // 被观察的值
public MyObservable(String watchedValue) {
this.watchedValue = watchedValue;
}
public void setValue(String newValue) {
if(!watchedValue.equals(newValue)) {
watchedValue = newValue;
setChanged();
notifyObservers(newValue);
}
}
@Override
public String toString() {
return "MyObservable";
}
}
class MyObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println(o + "'s state changed, argument is: " + arg);
}
}
}
看了下JDK标准库中的Observer和Observable实现很简单,不想多说了。
下面是Quartz中的监听器实现。
QuartzScheduler被监听者
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Quartz核心类,相当于Observable(被观察者)
* @author will
*
*/
public class QuartzScheduler {
private ArrayList internalSchedulerListeners = new ArrayList(10);
// private ArrayList interanlJobListeners = new ArrayList(); // 一个Observable可以包含多组监听器
public Date scheduleJob(Trigger trigger) {
if(trigger == null) {
return null;
}
System.out.println("Schedule job, trigger: " + trigger);
notifySchedulerListenersScheduled(trigger);
return new Date();
}
public void unScheduleJob(Trigger trigger) {
if(trigger == null) {
return;
}
System.out.println("Unschedule job, trigger: " + trigger);
notifyShedulerListenerUnScheduled(trigger);
}
// 注册SchedulerListener
public void addInternalSchedulerListener(SchedulerListener schedulerListener) {
synchronized (internalSchedulerListeners) {
internalSchedulerListeners.add(schedulerListener);
}
}
// 移除SchedulerListener
public boolean removeInternalSchedulerListener(SchedulerListener schedulerListener) {
synchronized (internalSchedulerListeners) {
return internalSchedulerListeners.remove(schedulerListener);
}
}
public List getInternalSchedulerListeners() {
synchronized (internalSchedulerListeners) {
return java.util.Collections.unmodifiableList(new ArrayList(internalSchedulerListeners));
}
}
public void notifySchedulerListenersScheduled(Trigger trigger) {
for(SchedulerListener listener: getInternalSchedulerListeners()) {
listener.jobScheduled(trigger);
}
}
public void notifyShedulerListenerUnScheduled(Trigger trigger) {
for(SchedulerListener listener: getInternalSchedulerListeners()) {
listener.jobUnScheduled(trigger);
}
}
}
SchedulerListener
// 监听接口,回调函数,Client注册监听时需要提供回调函数实现
public interface SchedulerListener {
void jobScheduled(Trigger trigger);
void jobUnScheduled(Trigger trigger);
}
Trigger
// Trigger
public class Trigger {
private String triggerKey;
private String triggerName;
public Trigger(String triggerKey, String triggerName) {
this.triggerKey = triggerKey;
this.triggerName = triggerName;
}
public String getTriggerKey() {
return triggerKey;
}
public void setTriggerKey(String triggerKey) {
this.triggerKey = triggerKey;
}
public String getTriggerName() {
return triggerName;
}
public void setTriggerName(String triggerName) {
this.triggerName = triggerName;
}
public String toString() {
return String.format("{triggerKey: %s, triggerName: %s}", triggerKey, triggerName);
}
}
Test
public class Test {
public static void main(String[] args) {
QuartzScheduler qs = new QuartzScheduler();
SchedulerListener listenerA = new SchedulerListener() {
@Override
public void jobUnScheduled(Trigger trigger) {
System.out.println("listenerA job unscheduled: " + trigger.getTriggerName());
}
@Override
public void jobScheduled(Trigger trigger) {
System.out.println("listenerA job scheduled: " + trigger.getTriggerName());
}
};
SchedulerListener listenerB = new SchedulerListener() {
@Override
public void jobUnScheduled(Trigger trigger) {
System.out.println("listenerB job unscheduled: " + trigger.getTriggerName());
}
@Override
public void jobScheduled(Trigger trigger) {
System.out.println("listenerB job scheduled: " + trigger.getTriggerName());
}
};
// 注册Scheduler Listener
qs.addInternalSchedulerListener(listenerA);
qs.addInternalSchedulerListener(listenerB);
Trigger triggerA = new Trigger("Key1", "triggerA");
Trigger triggerB = new Trigger("Key2", "triggerB");
qs.scheduleJob(triggerA);
qs.scheduleJob(triggerB);
qs.unScheduleJob(triggerA);
}
}
java jdk 观察者模式_java观察者模式实现和java观察者模式演化相关推荐
- java jdk包_Java开发工具包JDK的简介
Java开发工具包JDK的简介 Java 开发工具包是 Java 环境的核心组件,并提供编译.调试和运行一个Java 程序所需的所有工具,可执行文件和二进制文件.JDK 是一个平台特定的软件,有针对 ...
- java jdk运行_java运行机制、Jdk版本及Java环境变量
一.语言特性 计算机高级语言按程序的执行方式可分为:编译型和解释型两种.编译型的语言是指使用专门的编译器,针对特定的平台(操作系统)一次性翻译成被该平台硬件执行的机器码,并包装成该平台可执行性程序文件 ...
- java 常用类库_JAVA(三)JAVA常用类库/JAVA IO
成鹏致远 |lcw.cnblog.com|2014-02-01 JAVA常用类库 1.StringBuffer StringBuffer是使用缓冲区的,本身也是操作字符串的,但是与String类不同, ...
- macOS下查看Java/JDK的安装目录_查看Java/JDK的版本信息_配置环境变量JAVA_HOME
文章目录 查看JDK的安装目录 查看系统当前正在使用的 JDK 版本信息 配置环境变量 JAVA_HOME 查看JDK的安装目录 通常情况下,macOS安装JDK,默认是安装在 /Library/Ja ...
- java jdk安装失败_图文解答Java JDK9.0安装失败的原因,附带处理方法
对于那些第一次接触Java JDK的小伙伴们来说,在安装软件时可能会遇到一些困扰,例如安装过程中断,这是为什么呢?下文就以安装Java JDK9.0为例,详细讲解软件安装失败的解决方法. Java J ...
- 码出高效:java开发手册_Java 11手册:Java专家分享他们在Java 11方面的最佳和最差的经验
码出高效:java开发手册 Java 10标志着Java生态系统新时代的开始,但最新版本证明仍有一些里程碑可言. Java 11是Oracle新的六个月周期中的第一个LTS版本. 您可以在此处下载Ja ...
- java display.getdefault()_java基础(十一 )-----反射——Java高级开发必须懂的
本文我们通过一个实际的例子来演示反射在编程中的应用,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水.相信通过这篇教程,会让你对反射有一个更深层次的认知. 概念 ...
- java类描述_java笔记2:Java语言中的类和对象的描述
在Java 语言中,除8 个基本数据类型值之外, 一切都是对象,而对象就是面向对象程序设计的中心. 对象是人们要进行研究的任何事物,从最简单的整数到复杂的飞机等均可看作对象,它不仅能表示具体的事物,还 ...
- java回收类_Java的内存回收——Java引用的种类
1.Java引用的种类 Java是面向对象的编程语言,一个Java程序往往需要创建大量的Java类,然后对各Java类创建大量的Java对象,再调用这些Java对象的属性和方法来操作它们. 程序员需要 ...
- java当月最后一天_Java日期循环,Java获取当月的第一天和最后一天 | 学步园
1.Java日期循环 SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd"); String dateStr1 ...
最新文章
- 领先微软技术咨询公司招聘技术人员
- 对gitShell的使用
- CMOS Sensor的调试分享
- 聊聊 HTTPS 和 SSL/TLS 协议
- windows安装ruby on rails
- c++并发操作mysql_文件数据库sqlite3 C++ 线程安全和并发
- sed -i 单引号中嵌套双引号_【函数应用】IF函数的多层嵌套
- 基于ssh的多节点之间互信通信的实现
- 动态主机配置协议DHCP
- js获得URL中的参数
- GitHub又出新功能了,网友:这也太爽了吧。。。
- 智慧城市数字孪生技术方案,建设可视化系统
- 开源的轻量级JSON存储Kinto介绍
- 蓝牙耳机什么牌子好?安卓蓝牙耳机性价比推荐
- word里双横线怎么打_字体下方的双横线怎么弄 word蓝色双横线
- 如何下载Hbuilder,而不是下载Hbuilder X?
- 编译链接脚本lds文件
- html5中阴影,HTML5 Canvas 中的颜色、样式和阴影的属性和方法
- 值得收藏!国外最佳互联网安全博客TOP 30
- Unit 5: Windows Acquisition 5.1 Windows Acquisition Windows Forensic Imaging of Drives
热门文章
- hdu5437(2015长春网络赛A题)
- android 新浪微博的点赞功能实现,Android PraiseTextView实现朋友圈点赞功能
- python获取指定端口流量_利用python获取nginx服务的ip以及流量统计信息
- redhat安装wine教程_可能是最漂亮的国产Linux,U盘安装DeepinLinux 深度操作系统
- 20211201 二范数的导数小于等于导数的二范数(导数存在情况下)
- 2021-03-29 标准化函数
- Visual Studio解决freopen等函数报错函数安全问题
- mongo数据库数据迁移到muysql数据库
- 226. Invert Binary Tree
- HTML5 编辑 API 之 Range 对象(一)