案例来自《重学Java设计模式》
本案例是模拟每次小客车摇号通知的场景,如下图(截自《重学Java设计模式》)


这个接口定义了监听事件要执行的方法,后面创建的监听器都会实现这个接口并重写该方法
- public interface EventListener < T > {
- /**
- * observed do
- * @param type
- */
- void doEvent ( T type ) ;
- }
消息监听器,用于监听摇号结果并给用户发送通知结果的消息(此处用日志模拟发送短信)
- public class MessageEventListener implements EventListener < LotteryResult > {
- public static Logger logger = LoggerFactory.getLogger( MessageEventListener.class ) ;
-
- @Override
- public void doEvent ( LotteryResult lotteryResult ) {
- logger.info ( "给用户 {} 发送通知:{}",lotteryResult.getUid () ,lotteryResult.getMessage ()) ;
- }
- }
消息队列监听器,用于监听摇号结果并记录结果(此处用日志模拟发送短信)
- public class MQEventListener implements EventListener < LotteryResult > {
- public static Logger logger = LoggerFactory.getLogger( MQEventListener.class ) ;
-
- @Override
- public void doEvent ( LotteryResult lotteryResult ) {
- logger.info ( "记录用户 {} 摇号结果:{}",lotteryResult.getUid () ,lotteryResult.getMessage ()) ;
-
- }
- }
这里定义了一个存储监听器的集合listeners以及监听类型的枚举类EventType,并封装了操作监听器的方法:
subscribe()unsubscribe()notify()
- public class EventManager {
- Map < Enum < EventType > , List < EventListener >> listeners = new HashMap <>() ;
-
- public EventManager ( Enum < EventType > ... operations ) {
- for ( Enum < EventType > operation : operations ) {
- this.listeners.put ( operation, new ArrayList <>()) ;
- }
- }
-
- /**
- * 事件类型枚举类
- */
- public enum EventType {
- MQ, Message
- }
-
- /**
- * 订阅
- *
- * @param eventType 事件类型
- * @param listener 监听
- */
- public void subscribe ( Enum < EventType > eventType, EventListener listener ) {
- /**
- * 将新订阅的监听器添加进存储不同监听器的map中
- */
- List < EventListener > users = listeners.get ( eventType ) ;
- users.add ( listener ) ;
- }
-
- /**
- * 取消订阅
- *
- * @param eventType 事件类型
- * @param listener 监听
- */
- public void unsubscribe ( Enum < EventType > eventType, EventListener listener ) {
- List < EventListener > users = listeners.get ( eventType ) ;
- users.remove ( listener ) ;
- }
-
- /**
- * 通知
- *
- * @param eventType 事件类型
- * @param lotteryResult 通知结果
- */
- public void notify ( Enum < EventType > eventType, LotteryResult lotteryResult ) {
- List < EventListener > users = listeners.get ( eventType ) ;
- for ( EventListener user : users ) {
- user.doEvent ( lotteryResult ) ;
- }
- }
-
-
- }
这个对象封装了返回所需要的信息
- @Data
- public class LotteryResult {
- String uid;
- String message;
- Date time;
-
- public LotteryResult ( String uid, String message, Date time ) {
- this.uid = uid;
- this.message = message;
- this.time = time;
- }
- }
这里依赖了EventManager这个操作监听器的方法类
draw()方法中执行了监听器的通知操作(针对此示例可以理解为监听器的监听对象执行事件draw()时,会通知监听器(MessageEventListener和MQEventListener),此时监听器会遍历执行监听器中定义的doEvent()方法)doDraw()方法交由子类去实现
- public abstract class LotteryService {
- private EventManager eventManager;
-
- public LotteryService () {
- eventManager = new EventManager ( EventManager.EventType.MQ, EventManager.EventType.Message) ;
- eventManager.subscribe ( EventManager.EventType.MQ, new MQEventListener ()) ;
- eventManager.subscribe ( EventManager.EventType.Message, new MessageEventListener ()) ;
- }
-
- public LotteryResult draw ( String uid ) {
- LotteryResult lotteryResult = doDraw ( uid ) ;
- eventManager.notify ( EventManager.EventType.MQ, lotteryResult ) ;
- eventManager.notify ( EventManager.EventType.Message, lotteryResult ) ;
- return lotteryResult;
- }
-
- protected abstract LotteryResult doDraw ( String uid ) ;
- }
调用当前案例的主线业务逻辑:小客车摇号
- public class LotteryServiceImpl extends LotteryService {
- MinibusTargetService minibusTargetService = new MinibusTargetService () ;
-
- @Override
- protected LotteryResult doDraw ( String uid ) {
- String lottery = minibusTargetService.lottery ( uid ) ;
- return new LotteryResult ( uid, lottery, new Date ()) ;
- }
- }
封装了小客车的相关操作
- public class MinibusTargetService {
- /**
- * mock lottery
- *
- * @param uid
- * @return
- */
- public String lottery ( String uid ) {
- return Math.abs( uid.hashCode () % 2 ) == 0 ? "中签" : "未中签";
- }
- }
这个示例项目需要添加下依赖
- xml version="1.0" encoding="UTF-8" ?>
- < project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
- < modelVersion > 4.0.0 modelVersion >
-
- < groupId > org.example groupId >
- < artifactId > Desigins artifactId >
- < version > 1.0-SNAPSHOT version >
-
- < properties >
- < maven.compiler.source > 8 maven.compiler.source >
- < maven.compiler.target > 8 maven.compiler.target >
- properties >
-
- < dependencies >
- < dependency >
- < groupId > org.projectlombok groupId >
- < artifactId > lombok artifactId >
- < version > 1.18.0 version >
- dependency >
-
- < dependency >
- < groupId > org.slf4j groupId >
- < artifactId > slf4j-api artifactId >
- < version > 1.7.25 version >
- dependency >
-
- < dependency >
- < groupId > ch.qos.logback groupId >
- < artifactId > logback-classic artifactId >
- < version > 1.2.3 version >
- dependency >
-
- < dependency >
- < groupId > org.junit.jupiter groupId >
- < artifactId > junit-jupiter-api artifactId >
- < version > 5.2.0 version >
- < scope > test scope >
- dependency >
- dependencies >
-
- project >
- @Slf4j
- public class Test {
-
- @org.junit.jupiter.api.Test
- public void test_draw () {
- LotteryService lotteryService = new LotteryServiceImpl () ;
- LotteryResult result = lotteryService.draw ( "233444449484441" ) ;
- System.out.println ( result ) ;
- }
- }
