设计模式(Javaee)之---监听者模式

Posted 夏小弥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式(Javaee)之---监听者模式相关的知识,希望对你有一定的参考价值。

监听者模式

一、

监听者模式也叫观察者模式

监听器Listener

监听器-就是一个实现待定接口的普通Java程序,此程序专门用于监听别一个类的方法调用。
都是使用观察者设计模式。
什么是观察者模式:
定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新。 
示例:
GUI编程中的addXxxxListener都是观察者模式。


观察者模式的三个重要类:


观察者设计模式示例:

1、开发步骤:
 * 第一步:实现一个需要被监听的类Person.
 * 第二步:实现一个监听接口PersonListener。
 * 第三步:在Person类中,提供一个方法用于注册PersonListener类,即registerListener
 * 第四步:必须要在Person类中维护PersonListener类的实例。
 * 第五步:在调用person.eat方法是,判断PersonListener是否为null,如果不为null则调用它的eating方法。
 * 第六步:在Main类中,实例化Person,并注册一个监听。

被监听者Person

package cn.hncu.designPattern;

public class Person 
	private String name;
	private IPersonRunListener listener1;
	private IPersonRunListener listener2;
	public Person(String name) 
		this.name = name;
	

	public void run() 
		if(listener1!=null)
			listener1.fighting();
		
		System.out.println(this.name + " is running....");
		if(listener2!=null)
			listener2.fighting();
		
	
	
	public void addBefore(IPersonRunListener listener)
		this.listener1 = listener;
	
	public void addAfter(IPersonRunListener listener)
		this.listener2 = listener;
	
	


interface IPersonRunListener 
	public void fighting();
监听者

package cn.hncu.designPattern;

public class Demo 

	public static void main(String[] args) 
       Person p = new Person("Jack");
       IPersonRunListener a = new A();
       p.addAfter(a);
       p.addBefore( new IPersonRunListener() 
			@Override
			public void fighting() 
				System.out.println("注意做点准备活动....");
			
	   );
       p.run();
	


class A implements IPersonRunListener
	@Override
	public void fighting() 
		System.out.println("加油...做死的跑...");
	


2、开发步骤:
第一步:前页改Person为Cat的基础上继续添加一个CatEvent类(注意我说是类不是接口),代表事件对像。
第二步:修改ICatListener接口的climbing方法,让它接收一个 CatEvent参数。
第三步:在Cat类climbing方法中,如果判断ICatListener属性不为空,则在调用climbing方法,实例化 CatEvent并传给climbing方法。
第四步:在main方法中,通过 CatEvent的getSource方法测试是否是同一个对像。
package cn.hncu.designPattern.two;

public class Cat 
	private ICatListener listener = null;
	private String name;
	public Cat(String name) 
		
		this.name = name;
	
	
	public String getName() 
		return name;
	

	public void climb() 
		System.out.println(name+"正在爬.....");
		if (listener != null) 
			listener.help(new CatEvent(this));
		
	

	public void addCatListener(ICatListener listener) 
		this.listener = listener;
	

	@Override
	public String toString() 
		return name;
	
	


interface ICatListener 
	public void help(CatEvent e);


class CatEvent 
	private Cat cat = null;

	public CatEvent(Cat cat) 
		this.cat = cat;
	

	public Object getSource() 
		return cat;
	
	public String getActionCommand()
		return cat.getName();
	


class DefaultCatListener implements ICatListener 
	@Override
	public void help(CatEvent e) 
		System.out.println("默认动作....");
	


package cn.hncu.designPattern.two;

public class Demo2 

	public static void main(String[] args) 
		Cat cat = new Cat("白猫");
		Cat cat2 = new Cat("黑猫");
		ICatListener ic = new ICatListener() 
			@Override
			public void help(CatEvent e) 
				System.out.println(e.getSource() + "真调皮,你又爬了....");
				if(e.getActionCommand().equals("白猫"))
				    System.out.println("喂鱼...");
			    
			
		;
		cat.addCatListener(ic);
		cat2.addCatListener(ic);
		
		cat.climb();
	


二、
Servlet技术的监听器(查看API)



监听示例1-监听ServletContext的创建和销毁:

开发步骤:
第一步:实现ServletContextListener接口。
第二步:实现两个方法。
contextInitialized
contextDestroyed
第三步:在web.xml中添加<listener/>节点。
这一点与swing中的添加监听有所区别。
第四步:测试
1、发布项目启动。
2、通过Tomcat管理控制台停止此项目。


监听示例2:-监听ServletContext上的属性变化:

这个比较简单就不多说了,如下图:



下面我们结合上面的监听示例1和2做一个应用实例
ContextListener应用场景:

记录一个网站的刷新量。
当服务器关闭时,必须要保存到文件中或是数据库中去。
当服务器启动时,先从文件中读取并放到ServletContext。
在Filter中记录访问量,每次访问都加1。

好处:信息不是太重要,没有必要每次用户访问都访问数据库或是操作文件。
在为不影响用户的速度感受,应该开始一个新的线程同去操作数据。
这样即使在后台使用同步技术,用户也不会感觉到速度很慢。

index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>servlet监听器HelloWorld</title>
  </head>
  
  <body>
    <h2>servlet监听器HelloWorld</h2> <br>
    <h2>示例---网站点击量的实现</h2> <br>
    点击量:$count
    
    <a href="jsps/a.jsp">演示MyServletContextAttributeListener</a>
  </body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name></display-name>	
  
  <filter>
     <filter-name>count</filter-name>
     <filter-class>cn.hncu.filter.CountFilter</filter-class>
  </filter>
  <filter-mapping>
     <filter-name>count</filter-name>
     <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  <listener>
    <listener-class>cn.hncu.listener.MyContextListener</listener-class>
  </listener>
  
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

过滤器:CountFilter

package cn.hncu.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class CountFilter implements Filter 
	@Override
	public void init(FilterConfig filterConfig) throws ServletException 
	

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException 
		ServletContext ctx = request.getServletContext();
		new MyThread(ctx).start();
		
		chain.doFilter(request, response);
	

	@Override
	public void destroy() 
	



class MyThread extends Thread
	private ServletContext ctx=null;
	private static Object obj = new Object();
	public MyThread(ServletContext ctx) 
		this.ctx = ctx;
	

	@Override
	public void run() 
		synchronized (obj) 
			Integer count = (Integer) ctx.getAttribute("count");
			count++;
			ctx.setAttribute("count", count);
		
	
	

监听器:MyContextListener

package cn.hncu.listener;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintWriter;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyContextListener implements ServletContextListener
	@Override
	public void contextInitialized(ServletContextEvent sce) 
	   System.out.println("ServletContext对象(项目)创建了....");
	   //从服务器硬盘把之前存储的点击量数据读取出来
	   ServletContext ctx = sce.getServletContext();
	   String path= ctx.getRealPath("/count.txt");
	   try
			BufferedReader br = new BufferedReader(new FileReader(path));
			String line = br.readLine();
			Integer count = Integer.valueOf(line);
			ctx.setAttribute("count", count);
		 catch (Exception e) 
			e.printStackTrace();
			ctx.setAttribute("count", new Integer(0));
		
	   
	

	@Override
	public void contextDestroyed(ServletContextEvent sce) 
		System.out.println("ServletContext对象(项目)消亡了....");
		//把当前servletContext容器中存储的点击量数据 永久化到  服务器硬盘
		ServletContext ctx = sce.getServletContext();
		String path= ctx.getRealPath("/count.txt");
		try
		   PrintWriter pw = new PrintWriter(path);
		   pw.println(""+ctx.getAttribute("count"));
		   pw.close();
		 catch (Exception e) 
				e.printStackTrace();
		
		
	


三、(一个小项目,显示在线用户)
HttpSession的监听器:

HttpSessionListener,监听HttpSession的创建和销毁。
sessionCreated
sessionDestroyed

Session的默认有效时间为30分。可以通过配置的方式修改它的值。
可以调用session.invalidate方法销毁当前Session.

主要作用是记录当前所有在线人数,无论是用户还是游客。


Session的属性设置监听事件:

HttpSessionAttributeListener
主要作用是:记录当前在登录人数。注意,登录是指注册成为合法用户并成功登录的人。



顺便提一个知识点

ServletRequestListener  经常用来记录访问量


ServletRequestAttributeListener:


下面做一个实例:

index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>演示HttpSessionListener---示例:在线人信息</title>
  </head>
  
  <body>
    <h3>演示HttpSessionListener---示例:在线人信息</h3>
    <a href="<c:url value='/ShowServlet'/>">查看在线人</a>
  
  <hr/>
      <form action="<c:url value='/LoginServlet'/>" method="post">
                    姓名:<input type="text" name="name" />
         <input type="submit" value="登录">
      </form>
  </body>
  
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name></display-name>	
  
  <listener>
     <listener-class>cn.hncu.listener.MyHttpSessionListener</listener-class>
  </listener>
  <listener>
     <listener-class>cn.hncu.listener.MySessionAttrListener</listener-class>
  </listener>
  
  
  <servlet>
    <servlet-name>ShowServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.ShowServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>cn.hncu.servlet.LoginServlet</servlet-class>
  </servlet>


  <servlet-mapping>
    <servlet-name>ShowServlet</servlet-name>
    <url-pattern>/ShowServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/LoginServlet</url-pattern>
  </servlet-mapping>
  
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>


监听器:
MyHttpSessionListener.java

package cn.hncu.listener;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class MyHttpSessionListener implements HttpSessionListener
	@Override
	public void sessionCreated(HttpSessionEvent se) 
		System.out.println( "有人进来了..."+ se.getSession().getId() );
		List<HttpSession> guests = (List<HttpSession>) se.getSession().getServletContext().getAttribute("guests");//在线人集合
		if(guests==null)//沙发
			guests = new ArrayList<HttpSession>();
			se.getSession().getServletContext().setAttribute("guests", guests);
		
		guests.add(se.getSession());
	
	@Override
	public void sessionDestroyed(HttpSessionEvent se) 
		System.out.println( "有人退出了..."+ se.getSession().getId() );
		List<HttpSession> guests = (List<HttpSession>) se.getSession().getServletContext().getAttribute("guests");
		if(guests.contains(se.getSession()))
			guests.remove(se.getSession());
		
	

MySessionAttrListener.java

package cn.hncu.listener;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

public class MySessionAttrListener implements HttpSessionAttributeListener

	@Override
	public void attributeAdded(HttpSessionBindingEvent se) 
		if(se.getName().equals("name"))
			System.out.println("用户"+se.getName()+"登录..."+se.getSession());
			List<HttpSession> logins = (List<HttpSession>) se.getSession().getServletContext().getAttribute("logins");
			if(logins==null)
				logins = new ArrayList<HttpSession>();
				se.getSession().getServletContext().setAttribute("logins",logins);
			
			logins.add(se.getSession());
		
	

	@Override
	public void attributeRemoved(HttpSessionBindingEvent se) 
		
	

	@Override
	public void attributeReplaced(HttpSessionBindingEvent se) 
		
	
	

Servlet

LoginServlet.java

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginServlet extends HttpServlet 

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException 

		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		
		String name = request.getParameter("name");
		if(name!=null && name.trim().length()>0)//假定该情况是登录成功
			request.getSession().setAttribute("name", name);
			request.getSession().setAttribute("ip", request.getRemoteAddr());
		
		out.println("登录成功!");
		out.flush();
		out.close();
	


ShowServlet.java

package cn.hncu.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class ShowServlet extends HttpServlet 

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException 
		doPost(request, response);
	

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException 
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		
		List<HttpSession> guests =(List<HttpSession>) getServletContext().getAttribute("guests");
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		if (guests!=null) 
			for(HttpSession s: guests)
				Date d = new Date(s.getCreationTime());
				out.println("ID:"+s.getId()+"," + sdf.format(d)+"<br/>");
			
		
		
		out.println("<hr/>");
		out.println("<h3>以下是已登录用户信息</h3>");
		List<HttpSession> logins =(List<HttpSession>) getServletContext().getAttribute("logins");
		if (logins!=null) 
			for (HttpSession s : logins) 
				out.println("ID:" + s.getId() + ", Name:"
						+ s.getAttribute("name") + ",IP:"
						+ s.getAttribute("ip") + "<br/>");
			
		
	

这一个例子因为这里只是讲知识点就并没有做得那么完善,下一篇博文将会做完善一点


以上是关于设计模式(Javaee)之---监听者模式的主要内容,如果未能解决你的问题,请参考以下文章

监听者模式(Listener)--- Observer Pattern的扩展

监听者模式

设计模式之建造者模式

Java设计模式之观察者模式

23种设计模式之四(装饰者模式)

设计模式之装饰者模式