基于IOC的Java事件框架的设计与实现 Ⅲ

SingletonActionListener.java

作用:用于返回ActionListener的唯一实例,自身实现了ActionListener接口。抽象方法通过Java反射机制,执行事件处理函数(目标函数)。

package com.csufox.listener;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Method;
import java.util.HashMap;
import org.w3c.dom.Element;

 

public class SingletonActionListener implements ActionListener{
    private static HashMap<Object,Element> eventMap = new HashMap<Object,Element>();;
    private static HashMap<String,Object> classMap = new HashMap<String,Object>();;
    private static SingletonActionListener singletonActionListener = new SingletonActionListener();    //单态模式的ActionListener,只有一个实例在内存

    public static SingletonActionListener getInstance(Object bean,Object component,Element eventNode){
        String classPath = eventNode.getAttribute("class");
        if(classPath==""){  //若event节点中class属性缺省,则默认事件执行方法在原容器中
            String className = bean.getClass().getName();
            eventNode.setAttribute("class", className);
            classMap.put(className, bean);  //classMap用于保证执行器的单态,节省内存
        }
        eventMap.put(component, eventNode);
        return singletonActionListener;
    }

    public void actionPerformed(ActionEvent event) {
        Object key = event.getSource();
        Object execute = null;
        if(eventMap.containsKey(key)){
            Element eventNode = eventMap.get(key);
            String classPath = eventNode.getAttribute("class");
            try {
                if(classMap.containsKey(classPath)){
                    execute = classMap.get(classPath);  //返回事件执行器
                }
                else{
                    execute = Class.forName(classPath).newInstance(); //实例化事件执行器
                    classMap.put(classPath, execute);    //置入classMap,保证单态
                }
                String targetMethod = eventNode.getAttribute("method"); //反射
                Class<?> cla = execute.getClass();
                Method m = cla.getMethod(targetMethod,new Class[]{});
                m.invoke(execute, new Object[]{});  } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

 

Session.java

作用:模拟B/S模式Web容器中的Session,用于传递数据,使事件触发和事件执行分离成为可能。

package com.csufox.util; 

import java.util.HashMap;

public class Session {
    private static HashMap<String,Object> hm = new HashMap<String,Object>();
    public static void setAttribute(String name,Object obj){ //静态方法,添加属性
        hm.put(name, obj);
    }
    public static Object getAttribute(String name){ //静态方法,得到属性
        Object obj = hm.get(name);
        return obj;
    }
}

 

至此,框架的代码初步完成。

测试

采用该框架,继续实现输入数字计算平方的简单图形界面,看看会发生什么奇迹?

新代码如下(注意代码中仅有组件(成员变量)的set、get方法,没有任何注册监听器,实现抽象方法等操作。全部在框架底层实现):

package demo;

import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.TextField;
import com.csufox.util.Session;
import com.csufox.util.XMLReader;

public class FrameDemo2 extends Frame{
    private TextField input = new TextField(10);
    private Button calculate = new Button("求平方");
    private TextField show = new TextField(10);

    public TextField getInput() {
        return input;
    }

    public void setInput(TextField input) {
        this.input = input;
    }

    public Button getCalculate() {
        return calculate;
    }

    public void setCalculate(Button calculate) {
        this.calculate = calculate;
    }

    public TextField getShow() {
        return show;
    }

    public void setShow(TextField show) {
        this.show = show;
    }

    public FrameDemo2(){
        show.setEditable(false);
        this.setLayout(new FlowLayout());
        this.add(input);
        this.add(calculate);
        this.add(show);
        this.setSize(300,80);
        this.setTitle("FrameDemo2");
        this.setVisible(true);
    }

    public static void main(String args[]){
        XMLReader xr = new XMLReader("event-config.xml");
        FrameDemo2 frame = (FrameDemo2)xr.getBean("frame");
        Session.setAttribute("frame", frame);
    }
}

在 event-config.xml 配置文件中配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="frame" class="demo.FrameDemo2">
        <component name="calculate">
            <event type="ActionListener" class="event.OnClick" method="onClick"></event>
        </component>
    </bean>
</beans>

在event包的OnClick类中定义onClick方法(实现了事件执行器的远程调用):

package event;

import java.awt.TextField;
import com.csufox.util.Session;
import demo.FrameDemo2;

public class OnClick {
    public void onClick(){
        FrameDemo2 frame = (FrameDemo2)Session.getAttribute("frame");
        TextField input = frame.getInput();
        TextField show = frame.getShow();
        String numStr = input.getText();
        double num = Double.parseDouble(numStr);
        String result = String.valueOf(num * num);
        show.setText(result);
    }
}

 

运行后的结果如下:

 image

事件得到监听,说明框架能够正常工作,测试成功!

另:

如果在event-config.xml文件中event节点的class属性空缺,则默认执行器的类路径在原容器FrameDemo2内。

在FrameDemo2中定义方法onClick(), 经过测试,程序同样正常运行。

 

从运行结果来看,该框架相比传统的Java事件机制有如下的优点:

1. 代码中仅需要写get,set方法,可由IDE(如MyEclipse)自动生成,没有注册监听器,实现接口等代码,减少了代码编写量

2. 事件监听器和事件执行器均在底层实现了单态模式,仅有一个实例运行,节省内存消耗(如同Struts中的Action)。

3. 实现了真正意义上的事件触发和事件执行的分离,通过Session来传递相关组件/容器的引用,进而改变状态。

通过这种解耦,提高了维护性。

4. event-config.xml来配置事件信息,实现了组件的热可插拔,比如将来需要更换事件执行器或事件监听器类型,只需在配置文件中重新配置即可,无须修改源代码。配置文件呈树结构,结构清晰,易于维护。

注:

框架XMLEventHandler只实现了ActionListener(SingletonActionListener.java),没有其它监听器接口的实现类,并不完善。但是整个实现的结构已经形成。

框架XMLEventHandler本可以省略get,set方法,而采用Java反射机制,用Field来得到组件(如Button),减少代码量。但是由于Field得到组件需将组件定义为公有变量,考虑到一般成员变量均定义为私有的习惯,放弃了这种实现方法。

–EOF–

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值