“Event/Listener”是我们常用的一种设计模式,其中最常见的莫过于控件事件了。写过 Swing 程序的同学应该都非常了解,譬如,我们可以调用JButton的addActionListener方法,这样的话,当 JButton被点击时,会自动回调你的listener方法。
但正是由于控件事件被用得非常广泛,以致于很多同学把事件当成是控件的一种专有属性,而忽略了“事件” 其实是一种典型的Observer模式,它原本可以用来解决更多的架构设计问题。本文,我们来介绍 AOM 2.0中的模型事件。 请注意,此处所说的事件,并不是指 AOM 中的组件事件,确切的说,这是一种后台的“模型事件”,并且,事件的发送与接收,AOM都为用户做了非常好的封装。
如果我们把事件模型分为两部分,演讲者(即事件起源)与听众(即Listener);那么,从程序的思维来看: 事件模型的显著特点是:一个演讲者可能会有多个听众,而听众可以任意的增加或删除。 因此,事件经常用来进行解耦。譬如说某一个业务数据发生变化,这种变化可能会影响到界面或者其它数据的变化, 但事先,我们并不知道会产生多少变化,于是我们就把“业务数据发生变化”打包成一个事件,谁对此事件感兴趣, 谁就注册并侦听此事件。
但同时,我们发觉,针对常规的事件实现方式,如果你要增加一个 Listener,首先必须要获得“事件发生处”的句柄,然后再通过此句柄显式的增加Listener,写成伪码就是: speaker.addListener(myListener)。无疑,这种实现方式存在一个明显的弊端,那就是必须要事先获得“事件发生地”的句柄, 这就意味着如果你要扩展程序功能,那么,你需要对旧有代码进行更改,而且,这种更改的成本还比较大。有没有更好的实现机制呢?
AOM 2.0中,提出了“Message Bus”的概念,即“消息总线”。发送消息是向“Message Bus”中发送,并且需要注明发送的消息类型;同时,任何人都可以随时从“Message Bus”中接听消息,并且可以通过消息类型来进行筛选,只接收你感兴趣的话题。你可以把“Message Bus”想象成全国的电视网络,电视台就是消息发送者,并且,不同的电视台播放不同类型的节目; 而如果你希望收看这些节目,那么,你只需要买台电视机,选择频道,即可收看到你感兴趣的节目。
AOM 2.0的消息总线是如何使用的呢?我们假设这样一种场景:某公司的一位程序员进行费用申请,他申请的费用会经过所属项目组的项目经理的审批。 如果转换成消息模型那就是:“申请费用”是一个事件,而“项目经理“对此感兴趣。
为了让我们的视线关注于事件本身,程序代码我们尽可能的精简:
<f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
renderKitId="AJAX">
<w:page title="apply fee">
<w:form>
<layout:panelGrid columns="2">
<w:textField id="money"></w:textField>
<w:button id="apply" />
</layout:panelGrid>
</w:form>
</w:page>
</f:view>
后台的 ApplyBean 代码片断如下:
@ManagedBean(name="ApplyBean", scope=ManagedBeanScope.SESSION)
public class ApplyBean {
@Bind
private int money = 100;
@Action
public void apply(){
System.out.println("I'm a programmer, I apply " + money + " money");
}
}
基于 IoVC 原理,整个页面即可运行,效果如下:
现在,我们做一个新的托管Bean:ProjectManagerBean,代码如下:
@ManagedBean(name="ProjectManagerBean", scope=ManagedBeanScope.SESSION)
public class ProjectManagerBean {
private void applyFeeListener(int money) {
System.out.println("I'm your project manager, you apply " + money + " money.");
}
}
那么,我们如何通过事件机制,让这两个方法关联起来呢?
首先是发送事件,我们将代码修订如下:
@Action
@RaiseEvent("applyFee(this.money)")
public void apply(){
System.out.println("I'm a programmer, I apply " + money + " money");
}
请注意,我们增加了一个@RaiseEvent 的annotation,它的参数中:“applyFee”代表事件类型,“this.money”代表传递的参数。
ProjectManagerBean是怎样注册成为Listener的呢?
@EventListener("applyFee")
private void applyFeeListener(int money) {
System.out.println("I'm your project manager, you apply " + money + " money.");
}
上述代码含义就是:通过@EventListener这个annotation标明:applyFeeListener方法是个事件监听器方法,并且, 它所感兴趣的事件类型是:applyFee。
好了,我们来看一下程序运行的输出结果:
2008-03-01 14:57:30 信息 [con.out] I'm a programmer, I apply 100 money
2008-03-01 14:57:30 信息 [con.out] I'm your project manager, you apply 100 money.
两者之间已经通过事件关联起来了。
现在我们需要扩展一下:除了项目经理感兴趣,部门经理对此事也感兴趣,那么,我们根本无需更改任何代码,只是新增一个新的 DepartManagerBean:
@ManagedBean(name="DepartManagerBean", scope=ManagedBeanScope.SESSION)
public class DepartManagerBean {
@EventListener("applyFee")
private void applyFeeListener(int money) {
System.out.println("I'm your department manager, you apply " + money + " money.");
}
}
程序运行的输出结果如下:
2008-03-01 15:01:03 信息 [con.out] I'm a programmer, I apply 100 money
2008-03-01 15:01:03 信息 [con.out] I'm your department manager, you apply 100 money.
2008-03-01 15:01:03 信息 [con.out] I'm your project manager, you apply 100 money.
程序员申请费用,现在项目经理和部门经理都通过事件机制知道此事了。我们希望在同一个方法中,对事件进行分类: 如果费用小于 等于100,那么,就发送一个 applyLittleFee 的事件,如果费用大于100,则发送一个 applyMuchFee 的事件;项目经理关注 applyLittleFee 事件,而部门经理关注 applyMuchFee 的事件。ApplyBean修订如下:
public class ApplyBean {
@Bind
private int money = 100;
@Inject
private EventBroadcaster event;
@Action
public void apply(){
System.out.println("I'm a programmer, I apply " + money + " money");
if(money <=100) event.broadcast(this, "applyLittleFee", money);
else event.broadcast(this, "applyMuchFee", money);
}
}
此处的 EventBroadcaster (事件发送对象) 被注入,通过此对象,你对“发送什么事件”、“何时发送事件”都能够进行详细的控制。
ProjectManagerBean与DepartManagerBean修订如下:
@ManagedBean(name="ProjectManagerBean", scope=ManagedBeanScope.SESSION)
public class ProjectManagerBean {
@EventListener("applyLittleFee")
private void applyFeeListener(int money) {
System.out.println("I'm your project manager, you apply " + money + " money.");
}
}
@ManagedBean(name="DepartManagerBean", scope=ManagedBeanScope.SESSION)
public class DepartManagerBean {
@EventListener("applyMuchFee")
private void applyFeeListener(int money) {
System.out.println("I'm your department manager, you apply " + money + " money.");
}
}
请注意,ProjectManagerBean及DepartManagerBean所感兴趣的事件也做了相应的修订,程序运行输出如下:
2008-03-01 15:10:10 信息 [con.out] I'm a programmer, I apply 100 money
2008-03-01 15:10:11 信息 [con.out] I'm your project manager, you apply 100 money.
2008-03-01 15:10:14 信息 [con.out] I'm a programmer, I apply 1000 money
2008-03-01 15:10:14 信息 [con.out] I'm your department manager, you apply 1000 money.
有时候会有这样一种需求:程序员申请费用,根据费用的大小,要自动导航到不同的页面。但有时候, 要重定向到哪些页面我们事先并不清楚。以上述场景为例:当项目经理审批时,希望导航到 projectManager.xhtml页面, 当部门经理审批时,希望导航到 departManager.xhtml页面。在 AOM 2.0中,如何解决此需求?
我们首先完成这两个页面:
projectManager.xhtml:
<f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
renderKitId="AJAX" xmlns:h="http://java.sun.com/jsf/html">
<w:page title="project manager">
I'm your project manager, you apply <h:outputText id="money"/> money.
</w:page>
</f:view>
departManager.xhtml
<f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
renderKitId="AJAX" xmlns:h="http://java.sun.com/jsf/html">
<w:page title="project manager">
I'm your depart manager, you apply <h:outputText id="money"/> money.
</w:page>
</f:view>
再对 ProjectManagerBean及DepartManagerBean修订如下:
@ManagedBean(name="ProjectManagerBean", scope=ManagedBeanScope.SESSION)
public class ProjectManagerBean {
@Bind
private int money;
@EventListener("applyLittleFee")
private String applyFeeListener(int money) {
this.money = money;
return "view:projectManager";
}
}
@ManagedBean(name="DepartManagerBean", scope=ManagedBeanScope.SESSION)
public class DepartManagerBean {
@Bind
private int money;
@EventListener("applyMuchFee")
private String applyFeeListener(int money) {
this.money = money;
return "view:departManager";
}
}
请注意观察:return "view:projectManager"语句中,前面的 view 意即告诉AOM,这是要导航,后面的projectManager代表 view 的ID。
程序运行效果如下:
我们只是通过上述例子了解了AOM 2.0中模型事件的一些小特性,事实上,AOM 2.0中模型事件是比较完备的,还有许多其它特性我们并没有介绍,譬如,我们可以在 Action 中直接通过return 语句触发事件:
return "#applyFee(this.money)";
在 @RaiseEvent中,我们还可以引用传递给方法的参数:
@RaiseEvent("showResponse($1.name)")
public void loginSuccess(User user) {
...
}
这些特性,还请各位读者参考官方文档。
本章节,我们简单体验了 AOM 2.0 中“模型事件”的概念。笔者以为:事件是一把双刃剑,运用得好,那么,能够大大增强程序的灵活性及可扩展性; 但如果滥用事件,则只会让你的程序难以跟踪,难以理解。
相关推荐
"Operamasks UI 2.0 Demo"是一个与JavaScript相关的压缩包,包含了对Opera Masks用户界面新版本的演示。这个项目可能是一个Web应用程序框架或库,专为开发人员设计,以便在Opera浏览器或其他支持JavaScript的环境中...
IoVC是OperaMasks2.0引入的概念,旨在解决传统MVC模式中控制逻辑与展现逻辑难以完全解耦的问题。在IoVC模型中,控制逻辑不再由展现层触发,而是由后台业务逻辑控制,这样开发者可以通过绑定ID来实现展现层与业务逻辑...
内容概要:本文详细介绍了如何利用A*算法改进传统的往返式路径规划,解决扫地机器人在复杂环境中容易卡住的问题。首先构建了一个可视化的栅格地图用于模拟环境,然后引入了优先级运动规则,使机器人能够有规律地进行往返清扫。当遇到死角时,通过A*算法计算最佳逃生路径,确保机器人能够顺利脱困并继续完成清扫任务。实验结果显示,改进后的算法显著提高了清洁覆盖率,降低了路径重复率。此外,还讨论了一些潜在的优化方向,如动态调整启发函数权重、断点续传以及能耗模型等。 适合人群:对路径规划算法感兴趣的科研人员、自动化专业学生、扫地机器人开发者。 使用场景及目标:适用于需要高覆盖率和低重复率的室内清洁任务,旨在提高扫地机器人的工作效率和智能化水平。 其他说明:文中提供了详细的Matlab代码实现,并附带了仿真测试结果,有助于读者理解和复现该算法。
爬取喜马拉雅听书(1)
安卓向上传递数据学习笔记总结
1、文件说明: Centos8操作系统tigervnc-selinux-1.11.0-9.el8.rpm以及相关依赖,全打包为一个tar.gz压缩包 2、安装指令: #Step1、解压 tar -zxvf tigervnc-selinux-1.11.0-9.el8.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm
内容概要:本文详细介绍了户外储能电源双向逆变器板的技术资料及其特点。涵盖原理文件、PCB文件、源代码、电感与变压器规格参数等,适用于2KW(最大3KW)的户外储能电源。文中强调了双向软开关DC-DC设计、两颗M0+ 32位MCU的分工、SPWM调制方式、H桥IGBT的应用、详细的电气参数和技术特性。此外,还包括了SPWM信号生成代码示例、硬件设计细节、生产注意事项等。 适合人群:从事户外储能电源开发的技术人员、电子工程师、产品经理等。 使用场景及目标:帮助开发者快速掌握双向逆变器板的设计和生产要点,缩短产品研发周期,提高产品质量和可靠性。具体应用场景包括但不限于户外应急电源、便携式储能设备等。 其他说明:本文提供了丰富的技术细节和实践经验,如双向软开关DC-DC设计、SPWM调制、IGBT驱动、EMC整改记录等,有助于解决实际开发中的难题。同时,附带的实际案例展示了该方案的成功应用,进一步证明了其可行性和优越性。
电子仿真教程,从基础到精通,每个压缩包15篇教程,每篇教程5000字以上。
内容概要:美国计算机学会(ACM)是一个成立于1947年的国际性计算机专业组织,致力于推动计算机科学的发展,提供教育、资源和专业发展机会。ACM的使命是促进计算机科学和信息技术领域的进步,愿景是成为全球计算机专业人士的首选组织。其核心价值包括卓越、诚信、包容性、合作和创新。ACM定期举办学术会议,如SIGGRAPH和图灵奖颁奖典礼,出版高质量的学术期刊和会议论文集,涵盖人工智能、软件工程、网络安全等领域。此外,ACM还提供在线课程、研讨会、认证项目等教育资源,以及职业规划、网络机会和领导力培训等职业发展服务。ACM图灵奖被誉为“计算机界的诺贝尔奖”,每年颁发给对计算机科学和技术做出重大贡献的个人。; 适合人群:计算机科学领域的专业人士、教育工作者、工程师和学生。; 使用场景及目标:①了解计算机科学领域的最新研究成果和发展趋势;②获取高质量的教育资源和职业发展机会;③参与计算机科学领域的学术交流和合作。; 其他说明:ACM作为一个全球性的组织,在教育、研究和行业实践中发挥着重要作用,推动了技术创新和社会进步。
logstash-8.17.4-windows-x86_64.zip
springboot 一个基于Springboot使用Aspect实现一个切面,以记录日志为例
音箱底部折边设备sw22可编辑_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip
内容概要:本文详细介绍了如何使用Python、Django和MySQL构建一个完整的个性化图书推荐系统。系统从前端界面设计、后端逻辑实现到数据库设计,涵盖了用户管理、图书管理、评分系统等功能模块。重点讲解了基于用户和项目的协同过滤算法实现,以及在用户评分数据不足时的标签推荐备份方案。此外,还包括了系统部署、测试和优化的具体步骤,如云服务器部署、性能测试、数据库优化等。 适合人群:具备一定Python和Web开发基础的研发人员,尤其是对推荐系统感兴趣的技术爱好者。 使用场景及目标:适用于希望深入了解图书推荐系统的工作原理和实现细节的技术人员。目标是帮助读者掌握从零开始搭建一个完整的个性化推荐系统的方法,包括前后端开发、算法实现和系统部署。 其他说明:文中提供了大量代码示例和实战经验,如数据库设计、爬虫实现、权限管理等,有助于读者更好地理解和应用相关技术。
Ai和python学习资料
文本摘要
冲击试验机sw22_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip
内容概要:本文详细介绍了MyBatis Plus(MP),它是MyBatis的增强工具,旨在简化CRUD操作、提高开发效率。其主要功能包括内置分页插件、简化CRUD操作以及代码生成器。使用时只需引入相应依赖,自定义Mapper接口继承BaseMapper泛型接口,并通过实体类反射获取数据库表信息。文章还介绍了常用注解如@TableName、@TableId、@TableField、@TableLogic和@Version,配置项如全局配置、类型别名和Mapper文件路径,以及核心功能如批量插入、分页查询、条件构造器(Wrapper)等。此外,扩展功能涵盖逻辑删除、枚举处理器和JSON处理器,插件功能则包括分页插件的配置和使用。 适合人群:具备一定Java开发经验,尤其是熟悉MyBatis框架的开发者,特别是那些希望提高开发效率、减少重复代码的工作1-3年研发人员。 使用场景及目标:①简化数据库操作,提高开发效率;②快速生成代码,减少手动编写SQL语句的工作量;③实现分页查询、逻辑删除、枚举和JSON字段处理等高级功能,提升应用的灵活性和可维护性。 其他说明:本文不仅提供了MyBatis Plus的功能介绍和使用方法,还深入探讨了条件构造器(Wrapper)的使用技巧,帮助开发者更好地理解和掌握这一强大的工具。在实际开发中,合理利用这些功能可以显著提高开发效率和代码质量。建议在学习过程中结合具体项目实践,逐步掌握各个功能的应用场景和最佳实践。
电子仿真教程,从基础到精通,每个压缩包15篇教程,每篇教程5000字以上。
这个是完整源码 SpringBoot + vue 实现 【java毕业设计】Springboot+Vue高考志愿填报系统 源码+sql脚本+论文 完整版 数据库是mysql 随着高考制度的不断完善和高等教育资源的日益丰富,高考志愿填报成为考生和家长关注的焦点。本文旨在开发一个基于Spring Boot后端框架、Vue.js前端框架和实现以下功能:考生信息管理、院校信息查询、专业信息查询、志愿填报、志愿评测等。通过Spring Boot框架构建后端服务,提供 API接口与前端进行交互;Vue.js框架用于构建前端用户界面,实现数据的动态展示和交互操作;MySQL数据库用于存储考生信息、院校信息、专业信息等数据。 在系统设计过程中,我们充分考MySQL数据库的高考志愿填报系统,提高志愿填报的效率和准确性,为考生和家长提供便捷的服务。 系统主要实现以下功能:考分考MySQL数据库的高考志愿填报系统,提高志愿填报的效率和准确性,为考生和家长提供便捷的服务生信息管理、院校信息查询、专业信息查询、志愿填报、志愿评测等。通过Spring Boot框架构建后端服务,提供 API接口与前端进行交互;Vue.js框架用于构建前端用户界面,实现数据的动态展示和交互操作;MySQL数据库用于存储考生信息、院校信息、专业信息等数据。 在系统设计过程中,我们充分考虑了系统的易用性、可扩展性和安全性。通过合理的数据库设计和优化,提高了系统的查询效率。同时,采用Spring Security等安全框架对系统进行安全防护,确保数据的安全性。 本文详细阐述了系统的需求分析、设计、实现和测试过程,并对关键技术和实现难点进行了深入探讨。通过实验验证,本系统能够满足高考志愿填报的基本需求,为考生和家长提供了高效、便捷的服务。此外,本文还对系统未来的发展方向和改进空间进行了展望,以期进一步完善系统功能,提高用户体验。