`
lixiongzhi_m
  • 浏览: 60945 次
  • 性别: Icon_minigender_1
  • 来自: 福建
社区版块
存档分类
最新评论

监听器设计模式总结

阅读更多
         监听器模式设计总结

为何需要用到监听器设计模式?


        假设现在有这样一个情景:我们要在一个文本区域中显示一些我们指定的信息。这个信息假设是在一个线程中每隔三秒发布一个信息并显示在该文本区域,我们一般的做法会在,窗体界面类中实例化这样一个文本区域对象,然后再实例化一个信息产生对象(即前面所说的线程),在实例化这个信息产生对象的时候将该文本区域对象作为一个参数传到信息产生的类内部,并在信息产生代码语句后添加该文本区域对信息的处理。(此处为将信息添加到文本区域中)。说的可能有点模糊。请看以下代码,相信很好理解。

          先定义一个信心产生类(利用线程),和一个信息类,代码如下:


package 监听器设计模式;

import java.util.ArrayList;

import javax.swing.JTextArea;;

public class NetConnector extends Thread{
	private JTextArea textarea;

	public NetConnector(JTextArea textArea){
		this.textarea=textArea;
	}
	public void run(){
		//线程运行时模拟产生信息
		int t=0;
		while(true){
			try {
				sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
				}
			t++;
			Msg msg=new Msg();
			msg.setId(t);
			msg.setContent("第"+t+"条信息\n");
			textarea.append(msg.getContent());
		}
		
	
	}
		
}

class Msg{
	private int id; //消息id
	private String content;//消息内容
	public String toString(){//重写的toString方法
		return content;
	}	
	public int getId(){
		return id;
	}
	public void setId(int id){
		this.id=id;
	}
	public String getContent(){
		return content;
	}
	public void setContent(String content){
		this.content=content;
	}
}


在主界面的代码:
package 监听器设计模式;

import java.awt.FlowLayout;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class UI extends JFrame{
	public static void main(String[] args){
		UI ui=new UI();
		ui.show_Ui();
	}
	
	public void show_Ui(){
		this.setTitle("测试界面");
		this.setDefaultCloseOperation(3);
		this.setLayout(new FlowLayout());
		this.setLocationRelativeTo(null);
		this.setSize(400,300);
		JTextArea textarea=new JTextArea(10,20);
		JScrollPane jscollpane=new JScrollPane(textarea);
		NetConnector connector=new NetConnector(textarea);
		connector.start();
		
		this.add(jscollpane);
		this.setVisible(true);
	}
}


   那么这样在主界面的文本区域内就能3秒产生一条信息。

这样的设计有什么弊端呢?

          假设我们要在另外一个组件中也对这些信息做相应的处理,按照这种做法就必须在在实例化信息产生对象的时候在传入相应组件的参数,然后再信息产生代码后再添加相应组件对信息的处理,要是后面有更多的组件要处理这些相同的信息,那么我们就每次都要去修改信息产生的构造方法。并要去添加信息产生后相应组件处理信息的代码,这些都必须要去修改源代码,显然这样会使代码代码质量下降。那么我们该怎么去处理这样一个问题呢?下面的监听器模式能帮你解决。

            回想我们以前用过的监听器,比如鼠标监听器、键盘监听器等。拿鼠标监听器来讲。我们用一个自定义类去实现鼠标监听器,实现里面的方法,如鼠标按下的方法。这个过程它是怎么来处理的?当我们按下鼠标,这个就相当于一条信息的发送。那么这条信息要怎么处理呢?这个只要在鼠标Press的方法中实现即可。然后将这个实现了鼠标监听器的类对象添加给某个处理该信息的组件,如一个面板。要是你想在其他组件如一个窗体上,那么同样只要实现这个鼠标监听器的接口,在相应的处理方法中实现我们对信息的处理,在将实现了该鼠标监听器接口的对象添加给窗体。想想这个模式和我们上面涉及到的对同一些信息要多种组件来处理的是不是一样的?答案是是的,完全一样。这样的做法并不用像上面举到的例子一样要去修改来原来的代码,只要做相应的添加就行了。要是还不是很理解,请看如下监听器设计模式的步骤。(该处还是以上面多种组件来处理同一信息的情况)


           既然是对同一信息的处理。我们先定义这个一个接口,该接口中有一个信息处理的方法。

接口如下:

package 监听器设计模式;

public interface IMsgReciverListener {
	public void reciveMsg(Msg m);//监听器中必须实现的处理消息的方法
}





某一个组件要去处理这类信息那么它就必须去实现这个接口。并实现相应的信息的处理的方法。如上面所说的文本区域。



           那么实现了接口,就要实现了相应的方法。最后的工作只要去调用这个方法了。这个方法要在什么地方调用呢?最佳答案是在信息产生的类内部。这边就要考虑到这样一个问题,这个信息是要在多种组件下同时做处理的。那么该如何将这些能处理信息对像(即实现了接口的类的实例化对象)放置在一起呢?有这样一个想法,当我们实例化一个这样的对象时我们就动态地将这个对象添加到信息产生的类内部,并用一个队列保存,那么要去调用全部的这些对象的方法就迎刃而解了。只要遍历队列,取出所有的对象,并调用相应的信息处理方法即可。


           以下代码是对消息产生类的修改(实现监听器设计模式):


package 监听器设计模式;

import java.util.ArrayList;

import javax.swing.JTextArea;

public class NetConnector extends Thread{
	//内部保存消息监听器对象的队列
	private ArrayList<IMsgReciverListener> listeners=new ArrayList();
		public void run(){
		//线程运行时模拟产生信息
		int t=0;
		while(true){
			try {
				sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
				}
			t++;
			Msg msg=new Msg();
			msg.setId(t);
			msg.setContent("第"+t+"条信息\n");
                          //遍历队列调用相应信息处理方法
                          fireMsgRecive(msg);
						}
		
	
	}
	
	//给NetConnector对象中增加一个监听器的方法调用
	public void addListener(IMsgReciverListener listener){
		listeners.add(listener);
	}
	//将接收到的消息通知到队列中的所有监听器对象去处理
	private void fireMsgRecive(Msg m){
		for(int i=0;i<listeners.size();i++){
			listeners.get(i).reciveMsg(m);
		}
	}
	
}



还要定义实现了接口的文本区域类:
package 监听器设计模式;

import javax.swing.JTextArea;

public class MyTextArea extends JTextArea implements IMsgReciverListener{

	@Override
	public void reciveMsg(Msg m) {
		this.append(m.getContent());
	}

}


在主界面中代码修改如下:

package 监听器设计模式;

import java.awt.FlowLayout;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class UI extends JFrame{
	public static void main(String[] args){
		UI ui=new UI();
		ui.show_Ui();
	}
	
	public void show_Ui(){
		this.setTitle("测试界面");
		this.setDefaultCloseOperation(3);
		this.setLayout(new FlowLayout());
		this.setLocationRelativeTo(null);
		this.setSize(400,300);
		MyTextArea textarealistener=new MyTextArea(200,150);
		JScrollPane jscollpane=new JScrollPane(textarealistener);
		NetConnector connector=new NetConnector();
		connector.addListener(textarealistener);
		connector.start();
		
		this.add(jscollpane);
		this.setVisible(true);
	}
}



想看效果,可以运行下啊。

这样,要是我们想在另外一个组件比如一个按钮上让他显示最新产生的消息,我们只要自定义一个继承JButton的类并实现上述接口,在信息处理方法中做我们想要的信息处理方法就可以。代码如下:
package 监听器设计模式;

import javax.swing.JButton;

public class MyButton extends JButton implements IMsgReciverListener{

	@Override
	public void reciveMsg(Msg m) {
		this.setText(m.getContent());
	}

}


然后再主界面类中实例化我们实现了接口的按钮,这时这个按钮也是一个监听器对象(由于实现了接口),别忘了将该监听器添加给消息产生类中的队列。最后在把按钮添加到界面上即可。这个自己动手尝试下。


以下是我的一些看法:
            1.很多书上可能较多用监听术语来描述,类似事件源、事件处理着。上述对应于事件源的就是消息产生的类,要处理的信息就是这里产生的。那么我们实现了的事件处理方法就要在这里调用,(将消息传入)。事件处理者就是上述实现了事件处理接口的那些自定义类(当然继承了系统提供的组件类)。可以看出,用这样的方式,事件源和事件处理者是独立的。这样可以减少代码的耦合性。

            2.将所有要处理事件的类都实现了事件处理接口,这本身就是理所当然,由于它要对事件进行处理,必须实现,而后在调用的时候,不同组件却可以被当成同一类型的对象存在队列中,并遍历调用。也正是由于实现了同一接口,(可以理解为他们都是这个接口类的一个对象),不同组件对象可以当成同一类型对象也就显得顺理成章。

             3.大家可按自己的理解去理解监听器设计模式,而不用刻意按监听器术语去理解他,我昨天刚看hu总给的文档时,看前面写的那些也是一头晕,当然自己看了一遍后按自己的理解整理了一下思路,然后再去类比那些术语,这样感觉那些知识一下子浅显了了很多。
分享到:
评论

相关推荐

    常用开发模式讲解.zip

    下面介绍几种常用的设计模式,包括单例模式、工厂模式、观察者模式、建造者模式、原型模式、适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式和策略模式。 单例模式(Singleton Pattern) 单例模式...

    Android中的事件处理总结

    当该事件源发生指定的事件时,就通知所委托的事件监听器,由事件监听器来处理事件。例如:消防所(事件监听器)监听所有的火灾事件并处理火灾,所有的企事业单位(事件源)当发生火灾时本身自己无法灭火,都委托给消防...

    全方位深入解析最新版SpringBoot源码.txt

    系统初始化器概览3-2 授人以渔:系统初始化器实战3-3 打破砂锅:工厂加载机制解析3-4 庖丁解牛:系统初始化器解析3-5 英雄所见:系统初始化器总结第4章 ***解析【眼观六路,耳听八方】本章先讲解下***设计模式,通过...

    吴天雄--JavaWeb完整笔记.doc

    模块八:过滤器和监听器(三大组件、八大监听器、session的绑定、解绑、钝化、活化);模块九:文件上传和下载(限制上传(文件的大小和类型)、详细代码、解决下载时文件名乱码问题) --author

    一本糊涂账-基于Swing和JDBC开发的图形界面桌面应用

    本项目是基于Swing和JDBC开发的图形界面...单例模式,面板类与监听器类松耦合,Entity层设计,DAO层设计,Service层设计 业务常见处理手法: CRUD操作,配置信息,配置信息初始化,报表生成,一对多关系,多对一关系

    基于JAVA的在线考试系统(毕业论文)

    3.5.4 监听器类设计 19 3.6系统的用例图 20 3.6.1 总体用例分析 20 3.6.2 用户管理用例分析 21 3.6.3 考试管理用例分析 21 3.6.4 考试题目管理用例分析 22 3.6.5 成绩管理用例分析 22 小结 22 第四章 系统的详细设计...

    Java语言基础下载

    Servlet监听器 576 内容总结 579 独立实践 580 第二十九章: Jsp 技术 583 学习目标 583 JSP介绍 584 JSP语法 584 模板元素 588 指令元素 588 页面指令 588 标签库指令 593 脚本元素 593 动作元素 597 &lt;jsp:include&gt;...

    黑客反汇编揭秘(第二版).part2.rar

    5.4.7 反监听器 79 5.4.8 反转储器 79 5.4.9 弥补保护机制 80 5.5 容易导致严重后果的小错误 80 第6章 热身 83 6.1 创建保护机制,并尝试破解 83 6.2 走近反汇编器 85 6.2.1 批反汇编器与交互式反汇编器 86 ...

    黑客反汇编揭秘(第二版).part1.rar

    5.4.7 反监听器 79 5.4.8 反转储器 79 5.4.9 弥补保护机制 80 5.5 容易导致严重后果的小错误 80 第6章 热身 83 6.1 创建保护机制,并尝试破解 83 6.2 走近反汇编器 85 6.2.1 批反汇编器与交互式反汇编器 86 ...

    Oracle 10g应用指导

    针对应用中经常出现问题,如保护与设置监听器,监听器远程管理,端口号,客户机与服务器的连接,外部过程调用,不能解析服务名以及没有监听器等都给出了详细的解决方法。第10章 数据库管理,包括导出数据库模式的DDL...

    java版飞机大战源码-Rockira.github.io:Rockira.github.io

    :microscope:监听器和过滤器 :ring:数据库 MySQL 索引、锁机制 事务特性、隔离级别 MySQL调优与最佳实践 :t-shirt:JDBC :ribbon:AJAX :cooked_rice:JavaWeb小项目 :hamburger:Hibernate :page_facing_up:Struts2 :...

    Oracle+10g应用指导与案例精讲

    针对应用中经常出现问题,如保护与设置监听器,监听器远程管理,端口号,客户机与服务器的连接,外部过程调用,不能解析服务名以及没有监听器等都给出了详细的解决方法。第10章 数据库管理,包括导出数据库模式的DDL...

    HugeGraph_SourceCode_ReadShare:HugeGraph源码阅读分享

    (小标题为自己总结的内容且不分先后) HugeGraph源码阅读一HugeGraph官方介绍HugeGraph架构和图策略HugeGraph是如何启动的HugeGraph的插件机制HugeGraph原始码阅读二HugeGraph的多后端存储HugeGraph的...

    python入门到高级全栈工程师培训 第3期 附课件代码

    08 select监听多连接 09 select与epoll的实现区别 第36章 01 异步IO 02 selectors模块介绍 03 selectors模块应用 04 作业介绍 第37章 01 selctors实现文件上传与下载 02 html的介绍 03 html文档树的概念 04 meta...

    vc++ 开发实例源码包

    CCAMS系统是一种用于局域网下的CS模式的软件管理和监测系统源码 它包括客户端和服务端,客户端软件主要作用是监测本主机的活动,并将监测到的信息定时发送给服务器。服务器可以将收集到的信息以柱状图和文件列表以及...

    21天学通Java-由浅入深

    277 14.5.2 创建按钮 277 14.5.3 按钮动作事件 278 14.6 Swing中的事件 280 14.6.1 事件简介 280 14.6.2 同一个事件源注册多个监听器 280 14.6.3 同一个监听器注册给多个事件源 282 14.6.4 窗体获取和失去焦点事件 ...

    vc++ 应用源码包_1

    任务管理器应该大家都很熟悉,论坛里也有好多的任务管理器的源码,解决CListCtr刷新时滚动条跳到开始处。 VC++实现网络连接查看器源码 非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++...

    vc++ 应用源码包_2

    任务管理器应该大家都很熟悉,论坛里也有好多的任务管理器的源码,解决CListCtr刷新时滚动条跳到开始处。 VC++实现网络连接查看器源码 非常好的一个实例,把网络连接的UDP/TCP都插入到CList控件中显示出来。 VC++...

Global site tag (gtag.js) - Google Analytics