监听器模式有三个要素——事件源、事件对象、监听器。

事件源:顾名思义,事件发生的源头,比如点击的按钮,属于被监听的对象;

事件对象:这个经常和事件源混淆,它经常被用来包装事件源,切记,它毕竟是个事件,比如点击事件,和事件源的区别自己感受,木有栗子;

监听器:这个是监听器模式的核心,定义事件发生后的动作,通常事件对象作为监听器中定义的函数入参。

下面举个简单的栗子:

故事背景是,小明是个不讲卫生的孩子,他妈妈很担心他的健康,规定必须饭前洗手。

定义一个熊孩子。熊孩子就是被监听的对象,是事件源,一切事件都是事件源发出,这似乎是句废话。

public class Child {
private String name;
private RemindListener remindListener; public Child(String name){
this.name = name;
}
public void eat() {
if(null!=remindListener){
remindListener.remind(new RemindWashingHandsEvent(this));
}
System.out.println("Child eat...");
} public void addListener(RemindListener listener){
remindListener = listener;
}
}

接下来是看看事件对象,事件对象正如上面所述,包装了事件源。我们在这里定义一个饭前洗手事件。

public class RemindWashingHandsEvent {
private Child child; public RemindWashingHandsEvent(Child child){
this.child = child;
}
}

事件对象定义了事件的属性、状态。

紧接着是定义事件发生后,监听器的动作,在这里是提醒洗手。

public class RemindListener {
public void remind(RemindWashingHandsEvent remindWashingHandsEvent){
System.out.println("listen to mom, washing hands before eating...");
}
}

注意,监听器主要封装了动作,仅此而已。

以上代码,只是为了说明监听器模式原理,代码通俗,不太优雅。

下面继承或实现java标准库,又随手写了一对代码,夜深了,有时间再解释。

public class Kid{
private String name;
private List<Listener> liteners; public Kid(String name) {
this.name = name;
this.liteners = Lists.newArrayList();
} public void eat(){ for(Listener listener:liteners){
if(listener instanceof WashingHandsListener){
WashingHandsListener washingHandsListener = (WashingHandsListener) listener;
washingHandsListener.fireAfterEventInvoked(new WashingHandsEvent(this,"洗手"));
}
}
System.out.println("吃饭...");
} public void addListener(Listener listener){
liteners.add(listener);
} }

  

public class Event extends EventObject {
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @throws IllegalArgumentException if source is null.
*/
public Event(Object source) {
super(source);
}
}

  

public class WashingHandsEvent extends Event{
private String eventName;
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @throws IllegalArgumentException if source is null.
*/
public WashingHandsEvent(Object source,String eventName) {
super(source);
this.eventName = eventName;
} public String getEventName() {
return eventName;
} public void setEventName(String eventName) {
this.eventName = eventName;
}
}

  

public interface Listener extends java.util.EventListener{
public void fireAfterEventInvoked(Event event);
}

  

public class WashingHandsListener implements Listener{
@Override
public void fireAfterEventInvoked(Event event) {
WashingHandsEvent washingHandsEvent = (WashingHandsEvent) event;
System.out.println("饭前准备"+ washingHandsEvent.getEventName());
}
}

  

public class Test {
public static void main(String[] args) {
Kid xiaoming = new Kid("xiaoming");
xiaoming.addListener(new WashingHandsListener());
xiaoming.eat();
}
}

输出结果:

Java设计模式-监听器模式的更多相关文章

  1. Java设计模式——组合模式

    JAVA 设计模式 组合模式 用途 组合模式 (Component) 将对象组合成树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有唯一性. 组合模式是一种结构型模 ...

  2. java设计模式--单列模式

    java设计模式--单列模式 单列模式定义:确保一个类只有一个实例,并提供一个全局访问点. 下面是几种实现单列模式的Demo,每个Demo都有自己的优缺点: Demo1: /** * 单列模式需要满足 ...

  3. 3.java设计模式-建造者模式

    Java设计模式-建造者模式 在<JAVA与模式>一书中开头是这样描述建造(Builder)模式的: 建造模式是对象的创建模式.建造模式可以将一个产品的内部表象(internal repr ...

  4. Java设计模式-代理模式之动态代理(附源代码分析)

    Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...

  5. Java设计模式——外观模式

    JAVA 设计模式 外观模式 用途 外观模式 (Facade) 为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 外观模式是一种结构型模式. 结构

  6. 【设计模式】Java设计模式 -工厂模式

    [设计模式]Java设计模式 -工厂模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! 目 ...

  7. 【设计模式】Java设计模式 - 原型模式

    [设计模式]Java设计模式 - 原型模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起 ...

  8. 【设计模式】Java设计模式 - 桥接模式

    [设计模式]Java设计模式 - 桥接模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起 ...

  9. 【设计模式】Java设计模式 - 组合模式

    Java设计模式 - 组合模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起记录分享自己 ...

随机推荐

  1. linux的定制和发布(一)

    如果总是仰视高山,就会挫伤我们攀登的勇气,使我们固步自封.我们需要做的就 是迈开自己的脚步,踏出第一步,let's go!       Linux的裁剪一般有三种方法: 1.以一个已经安装好的系统为基 ...

  2. jenkins-cli命令使用总结

    jenkins-cli命令使用总结 1.在jenkins中查看Jenkins CLI的相关说明 jenkins-->系统管理-->Jenkins CLI:如下图 下载:jenkins-cl ...

  3. Katalon Studio简单使用(二)

    距离上一篇更新katalon学习部分已有两个月的时间 ,我的博文的访问量为400多,(*^__^*) 嘻嘻…… 说明还是很多同学在学习这个小tools的.所以再记录下 近两个月来对katalon的体验 ...

  4. 使用Anaconda的python安装虚拟环境是出现错误:python -m venv venvdir----Error: Command '['D:\\Development\\Django\\test\\Scripts\\python.exe', '-Im', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit

    在创建python虚拟环境的时候,如果使用的是Anaconda中集成的python -m venv venvdir就会出现不能安装pip的错误,原因是Anaconda没有ensurepip, 解决办法 ...

  5. iterrows() 函数对dataframe进行遍历

    for循环遍历dataframe,返回有一个元祖类型,第一个是行的索引,第二个是series,是每一行的内容.

  6. 七、linux目录结构知识---实战

    1.企业面试题:一个100M的磁盘分区,分别写入1k文件,及写入1M的文件,分别可以写多少个? 一块磁盘被分区格式化成系统文件后,有Inode和Block:一个文件一般占用一个Inode和一个Bloc ...

  7. 【OCP题库-12c】最新CUUG OCP 071考试题库(69题)

    69.(31-1)choose the best answer: Evaluate the following query: SELECT INTERVAL '300' MONTH, INTERVAL ...

  8. [文文殿下]基本的DP技巧

    . 二进制状态压缩动态规划 对于某些情况,如果题目中所给的限制数目比较小,我们可以尝试状态压缩动态规划.例如,题目中给出数据范围\(n<=20\),这个一般情况下是一个状压DP的提示. 状态压缩 ...

  9. long int double float

    参考:https://blog.csdn.net/ideality_hunter/article/details/78432486 long是长整型,64位 int是短整型,32位 double是双精 ...

  10. robot framework-断言

    *** Test Cases *** 断言一 #01.should contain . should not contain 与should contain x times @{list1}= cre ...