java 设计模式之观察者模式(高级应用)

本文是运用观察者模式,不清楚的伙伴们可以先看基础篇:https://blog.csdn.net/yk614294861/article/details/86493056

近期在做一个门禁系统,该门禁系统需要对接很多人脸开门的设备厂家,默认系统中有一个主流程是开卡,由于之前小伙伴门,每次对接一个厂家都在主流程中增加几行代码,引入需要增加的厂商服务类,这种操作代码严重耦合,经常改动原本完整的代码。因此对此进行改善,使用观察者模式进行代码解耦和,在开卡的时候进行事件统一分发,后续增加厂商仅仅需要监听具体事件即可,不用再去改动原本的代码。

 

1.定义事件总线,统一管理事件的注册、移除、分发

package com.summerSpringBoot.observer;


public interface IEventHub {
	public static final String name = "IEventHub";	

	/**   
	 * @Title: registListener   
	 * @Description: 事件注册  
	 * @param eventType 事件类型
	 * @param listener 绑定监听器   
	 * @return: void      
	 * @throws   
	 */  
	public void registListener(EventType eventType, IListener listener);
	
	/**   
	 * @Title: removeListener   
	 * @Description: 移除监听器   
	 * @param eventType 事件类型
	 * @param listener  监听器   
	 * @return: void      
	 * @throws   
	 */  
	public void removeListener(EventType eventType, IListener listener);

	/**   
	 * @Title: dispatchEvent   
	 * @Description: 事件分发   
	 * @param eventType 事件类型
	 * @param event  具体事件    
	 * @return: void      
	 * @throws   
	 */  
	public void dispatchEvent(EventType eventType, Event event);

}

2.定义统一的监听器接口

package com.summerSpringBoot.observer;

public interface IListener {
	/**   
	 * @Title: onEvent   
	 * @Description: 监听器接口  
	 * @param type 事件类型
	 * @param event 具体事件
	 * @throws Exception      
	 * @return: void      
	 * @throws   
	 */  
	public void onEvent(EventType type, Event event) throws Exception;
}

3.事件总线的实现类

package com.summerSpringBoot.observer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

@Component
public class EventHub implements IEventHub {

	private static Logger logger = Logger.getLogger(EventHub.class);

	private Map<EventType, ArrayList<IListener>> eventTable = new HashMap<>();

	@Override
	public void registListener(EventType eventType, IListener listener) {
		ArrayList<IListener> listenerList = this.eventTable.get(eventType);
		if (listenerList == null) {
			listenerList = new ArrayList<IListener>();
			this.eventTable.put(eventType, listenerList);
		}
		listenerList.add(listener);

	}
	
	@Override
	public void removeListener(EventType eventType, IListener listener) {
		ArrayList<IListener> listenerList = this.eventTable.get(eventType);
		if(listenerList!=null &&listenerList.size()>0 ){
			listenerList.remove(listener);
		}
		
	}

	@Override
	public void dispatchEvent(EventType eventType, Event event) {
		ArrayList<IListener> listenerList = this.eventTable.get(eventType);
		for (IListener iListener : listenerList) {
			try {
				iListener.onEvent(eventType, event);
			} catch (Exception e) {
				logger.error("执行监听器出错" + iListener, e);
			}
		}

	}

	
}

3.定义枚举类,表示事件类型

package com.summerSpringBoot.observer;

/**   
 * @ClassName:  EventType   
 * @Description:事件枚举类,表示事件类型,可扩展  
 * @author: summer
 * @date:   2018年12月19日 下午5:03:45   
 *   
 */
public enum EventType {
	
	/**   
	 * @Fields FLOW_TYPE_NEW : 新办卡   
	 */  
	FLOW_TYPE_NEW, 
	
	
	/**   
	 * @Fields FLOW_TYPE_ADD : 补卡   
	 */  	
	FLOW_TYPE_ADD, 
	
	/**   
	 * @Fields FLOW_TYPE_HOUSE_ADD : 新增房屋   
	 */  
	FLOW_TYPE_HOUSE_ADD,
	
	
	/**   
	 * @Fields FLOW_TYPE_HOUSE_DESTROY : 销卡 
	 */  
	FLOW_TYPE_HOUSE_DESTROY
}

4.自定义注解,用在类上,这样可以方便地注册事件

package com.summerSpringBoot.observer;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**   
 * @ClassName:  EventListener   
 * @Description:自定义注解标注注册是事件类型
 * @author: summer
 * @date:   2019年1月15日 下午3:42:46   
 *   
 */  
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventListener {
	EventType[] eventType();
}

5.Spring 初始化地时候一起注册事件,大概流程是,当InitRegistListeners类初始化完成后会执行@PostConstruct标注地registListener() 方法,可以从Spring中获取所有IListener接口地实现类,然后获取类上地注解,并注册到事件总线

package com.summerSpringBoot.observer;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class InitRegistListeners {
	@Autowired
	private EventHub eventHub;
	@Autowired
	private SpringContextHolder springContextHolder;

	private static Logger logger = Logger.getLogger(InitRegistListeners.class);

	@PostConstruct
	public void registListener() {
		logger.info("##############开始注册监听器###############");
		Map<String, IListener> map = springContextHolder.getMap();
		for (Map.Entry<String, IListener> obj : map.entrySet()) {
			IListener listener = obj.getValue();
			Class<? extends IListener> class1 = listener.getClass();			
			Annotation annotation = class1.getAnnotation(EventListener.class);			
			if (null != annotation) {
				try {
					Method method = annotation.annotationType().getDeclaredMethod("eventType");
					EventType[] types = (EventType[]) method.invoke(annotation, null);
					for (EventType type : types) {
						eventHub.registListener(type, listener);
						logger.info("监听器" + obj.getKey() + "注册成功,监听事件:" + type + "---" + listener);
					}
				} catch (Exception e) {
					logger.error(listener + "监听器注册失败", e);
				}
			}
		}
	}

}

6.自定义SpringContextHolder  implements ApplicationContextAware 使用getBeansOfType方法,根据接口类型返回相应的所有bean,也就是获取所有实现IListener接口的类,key为bean的id.value 为实现类对象

package com.summerSpringBoot.observer;

import java.util.Map;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringContextHolder implements ApplicationContextAware {
	private static ApplicationContext applicationContext = null;

	private Map<String, IListener> map;

	/**
	 * 获取静态变量中的ApplicationContext.
	 */
	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	/**
	 * 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型.
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getBean(String name) {
		return (T) applicationContext.getBean(name);
	}

	/**
	 * 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型.
	 */
	public static <T> T getBean(Class<T> requiredType) {
		return applicationContext.getBean(requiredType);
	}

	/**
	 * 清除SpringContextHolder中的ApplicationContext为Null.
	 */
	public static void clearHolder() {
		applicationContext = null;
	}

	/**
	 * 实现ApplicationContextAware接口, 注入Context到静态变量中.
	 */
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) {
		SpringContextHolder.applicationContext = applicationContext;
		//根据接口类型返回相应的所有bean,也就是获取所有实现IListener接口的类,key为bean的id.value 为实现类对象
		map = applicationContext.getBeansOfType(IListener.class);
	}
	
	public Map<String, IListener> getMap(){
		return 	map;
	}

}

7.定义监听器实现类处理具体地逻辑,例如旷视地人脸注册

package com.summerSpringBoot.demo.listener;

import org.springframework.stereotype.Service;

import com.summerSpringBoot.observer.Event;
import com.summerSpringBoot.observer.EventListener;
import com.summerSpringBoot.observer.EventType;
import com.summerSpringBoot.observer.IListener;

@EventListener(eventType=EventType.FLOW_TYPE_NEW)
@Service
public class UserCreateListener implements IListener {

	@Override
	public void onEvent(EventType type, Event event) throws Exception {
		System.out.println("UserCreateListener执行了,旷视注册人脸");
	}

}

8.事件分发使用 UserEvent 是继承Event类地一个子类,使用该类来携带必须地参数。经过dispatchEvent后,指定地事件类型监听器就会执行

执行后地

具体demo代码如附件:https://download.csdn.net/download/yk614294861/10918876

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值