Java设计模式(四)——再谈观察者模式
在本系列的上一篇文章中,我们讨论了JDK对于观察者模式的一套实现。今天我们将要从另一个角度来探索Tomcat中是如何利用观察者模式加载各个组件。不过今天的任务不是解释Tomcat,所以我会单独把重点抽象出来展现如何在一个实际利用中使用Observer。
先谈一下我对观察者模式的理解。对于对象而言,观察似乎是一个主动的过程——多位观察者通过“观察”一个被观察对象状态的改变来触发一些自身的行为。是的,就设计模式来说,观察者设计的本质确实如此。可是,当引入到Java语言以后,这个“解空间”就似乎不那么“完美”了。你无法让你一个对象做到“主动”观察——轮询机制不属于今天的讨论范畴。所以,我以为称为监听器模式更加合理。
下面提出一个设计方案作为“解空间”的指导。在被观察对象(Subject)中定义一个能够注册(register)观察者(Observer)的方法和一个能够通知(notify)观察者的方法,观察者中定义一个被调用(update)的接口。
代码1.1 Subject接口:
public interface Subject {
void registerObserver(Observer ob);
void removeObserver();
void notifyObserver();
}
代码1.2 Observer接口
public interface Observer {
void update();
}
对接口定义完成以后实现业务逻辑,我们在Subject的实现中假设存在一个业务接口business,这个方法的目的是实现具体的业务逻辑并调用Observer.update。
代码2.1 Observer实现:
public class ConcerteObserver implements Observer {
@Override
public void update() {
System.out.println("update");
}
}
代码2.2 Subject实现:
public class ConcreteSubject implements Subject {
private Observer ob;
@Override
public void registerObserver(Observer ob) {
this.ob = ob;
}
@Override
public void removeObserver() {
this.ob = null;
}
@Override
public void notifyObserver() {
ob.update();
}
public void business() {
notifyObserver();
}
}
以上就是观察模式的代码逻辑,不过在实际运用的时候通常不会如此简单。下面我们来看一个相对复杂例子:利用观察者模式监听一个具有生命周期组件的各个状态。先解释一下什么是生命周期组件。在大型业务中,许多抽象的业务逻辑都具有生命周期状态。如新建、初始化、启动和停止等。不同的状态应该通知观察者触发不同的处理行为。
代码3.1 Lifecycle接口
public interface Lifecycle {
public static final int NEW_EVENT = 0;
public static final int INIT_EVENT = 1;
public static final int START_EVENT = 2;
public static final int STOP_EVENT = 3;
void addListener(LifecycleListener listener);
void removeListener(LifecycleListener listener);
void fireLifecycleEvent(LifecycleState state);
}
Lifecycle接口提供给被观察对象实现,其中定义了4种状态事件。
代码3.2 LifecycleState枚举类
public enum LifecycleState {
NEW(Lifecycle.NEW_EVENT), INIT(Lifecycle.INIT_EVENT), START(Lifecycle.START_EVENT), STOP(Lifecycle.STOP_EVENT);
private final int triggerEvent;
private LifecycleState(int triggerEvent) {
this.triggerEvent = triggerEvent;
}
public int getTriggerEvent() {
return triggerEvent;
}
}
LifecycleState是一个枚举对象,用来约束不同的生命周期状态应该对应的事件。
代码3.3 LifecycleListener接口
public interface LifecycleListener {
void lifecycleEvent(LifecycleState state);
}
观察者的触发接口,根据LifecycleState状态实现自定义业务
代码3.4 LifeCycleBean类
public class LifeCycleBean implements Lifecycle {
private List<LifecycleListener> listeners = new ArrayList<>();
private Object locked = new Object();
@Override
public void addListener(LifecycleListener listener) {
synchronized (locked) {
listeners.add(listener);
}
}
@Override
public void removeListener(LifecycleListener listener) {
synchronized (locked) {
listeners.remove(listener);
}
}
@Override
public synchronized void fireLifecycleEvent(LifecycleState state) {
for (LifecycleListener listener : listeners) {
listener.lifecycleEvent(state);
}
}
}
在LifeCycleBean中我们已经实现了多行程下的调用,好处是将业务逻辑和代码设计进一步分离。
代码3.5 StandardBusiness标准业务类
public class StandardBusiness extends LifeCycleBean {
private LifecycleState state = LifecycleState.NEW;
public void process() {
if (state.equals(LifecycleState.NEW)) {
state = LifecycleState.INIT;
fireLifecycleEvent(state);
} else if (state.equals(LifecycleState.INIT)) {
state = LifecycleState.START;
fireLifecycleEvent(state);
} else if (state.equals(LifecycleState.START)) {
state = LifecycleState.STOP;
fireLifecycleEvent(state);
} else {
System.out.println("process end");
}
}
}
在这段业务逻辑中多次调用process方法,可以模拟生命周期的不同阶段。
代码3.6.1 InitListener类
public class InitListener implements LifecycleListener {
@Override
public void lifecycleEvent(LifecycleState state) {
if(state.getTriggerEvent() == Lifecycle.INIT_EVENT) {
System.out.println("InitListener >> INIT_EVENT");
}
}
}
代码3.6.2 StartListener类
public class StartListener implements LifecycleListener {
@Override
public void lifecycleEvent(LifecycleState state) {
if (state.getTriggerEvent() == Lifecycle.START_EVENT) {
System.out.println("StartListener >> START_EVENT");
}
}
}
代码3.6.3 StopListener类
public class StopListener implements LifecycleListener {
@Override
public void lifecycleEvent(LifecycleState state) {
if (state.getTriggerEvent() == Lifecycle.STOP_EVENT) {
System.out.println("StopListener >> STOP_EVENT");
}
}
}
代码3.7 测试
public class AppTest {
@Test
public void test() {
StandardBusiness business = new StandardBusiness();
business.addListener(new InitListener());
business.addListener(new StartListener());
business.addListener(new StopListener());
business.process();
business.process();
business.process();
business.process();
}
}
总结:第二个例子逻辑相对复杂但是如果能够理清思路其实与第一个例子并无太大区别。而这个就是Tomcat中对于观察者模式的运用。
Java设计模式(四)——再谈观察者模式的更多相关文章
- Java设计模式(20)观察者模式(Observer模式)
Java深入到一定程度,就不可避免的碰到设计模式(design pattern)这一概念,了解设计模式,将使自己对java中的接口或抽象类应用有更深的理解.设计模式在java的中型系统中应用广泛,遵循 ...
- Java继承之再谈构造器
目录 Java继承之再谈构造器 初始化基类 默认构造器 带参数的构造器 子类调用父类构造器 Java继承之再谈构造器 初始化基类 前面提到,继承是子类对父类的拓展.<Thinking in Ja ...
- java设计模式解析(1) Observer观察者模式
设计模式系列文章 java设计模式解析(1) Observer观察者模式 java设计模式解析(2) Proxy代理模式 java设计模式解析(3) Factory工厂模式 java设计模式解析( ...
- 【设计模式】java设计模式总述及观察者模式
今天在准备腾讯的面试时想起来要复习一下设计模式,而刚好前几天在参加网易的在线考试的时候,也出了一道关于设计模式的选择题,主要是考察观察者模式,虽然那道题自己做对了,但觉得还是应该好好总结一下设计模式的 ...
- Java设计模式(三)——观察者模式和监听器
为了实现多个模块之间的联动,最好的方法是使用观察者模式.网上介绍的资料也比较多,今天我就从另一个方面谈谈自己对观察者模式的理解.从JDK提供的支持库里,我们能够找到四个对象:Observable.Ob ...
- java设计模式(六)--观察者模式
转载:设计模式(中文-文字版) 目录: 简单目标任务实现 观察者模式介绍 观察者模式代码实现 观察者模式是JDK中使用最多的模式之一,非常有用.我们也会一并介绍一对多关系,以及松耦合(对,没错,我们说 ...
- Java设计模式学习笔记(观察者模式)
观察者模式说起来很简单,就是一个订报纸的模式.但是实际上这部分我觉得还是很有意思的,<Head First设计模式>里还有一些还没看完,也是因为理解的不够深吧. 观察者模式会包含两个组件: ...
- Java并发编程-再谈 AbstractQueuedSynchronizer 1 :独占模式
关于AbstractQueuedSynchronizer JDK1.5之后引入了并发包java.util.concurrent,大大提高了Java程序的并发性能.关于java.util.concurr ...
- Java设计模式(二) 观察者模式
观察者模式: 定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖者都会受到通知并自动更新. 1,定义事件源接口 package com.pattern.observer; pub ...
随机推荐
- 【Alpha】——First scrum Meeting
一.今日站立式会议照片 二.每个人的工作 成员 昨天已完成的工作 今天计划完成的工作 · 李永豪 编写测试计划 学习JAVA编程及UI设计 · 郑靖涛 Alpha任务分配计划 学习JAVA编程及UI设 ...
- 201521123013 《Java程序设计》第4周学习总结
1. 本章学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 1.多态是面向对象的三大特性之一.多态的意思:相同的形态,可以实不同的行为.Java中实现多 ...
- 201521123001《Java程序设计》第3周学习总结
1. 本周学习总结 2. 书面作业 1. 代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; ...
- 201521123023《java程序设计》第三周学习总结
1. 本周学习总结 2. 书面作业 1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; p ...
- 201521123028 《Java程序设计》第2周学习总结
1. 本周学习总结 1.学习了String及部分函数用法,例如PTA上<5-2 jmu-Java-02基本语法-02-StringBuilder>一题中用到了"str.appen ...
- MUI如何调取相册的方法
第一种是HTML方法 <label> <input style="opacity: 0;" type="file" accept=" ...
- HDFS的web接口
50070端口查看NameNode状态,该端口的定义位于core-default.xml中,可以在core-site.xml中自行修改. 50075端口查看DataNode的,该地址和端口的定义位于h ...
- MySql 中文乱码解决办法
mysql存入的中文数据乱码,可能有这两个原因 原因一 : 数据源配置和mysql字符集编码不符,或数据源配置没有设置字符集 解决方案:在数据源配置添加字符集 useUnicode=true& ...
- day09<面向对象+>
面向对象(多态的概述及其代码体现) 面向对象(多态中的成员访问特点之成员变量) 面向对象(多态中的成员访问特点之成员方法) 面向对象(多态中的成员访问特点之静态成员方法) 面向对象(超人的故事) 面向 ...
- EntityFramework Core饥饿加载忽略导航属性问题
前言 .NET Core项目利用EntityFramework Core作为数据访问层一直在进行中,一直没有过多的去关注背后生成的SQL语句,然后老大捞出日志文件一看,恩,有问题了,所以本文产生了,也 ...