观察者模式就是当⼀个⾏为发⽣时传递信息给另外⼀个⽤户接收做出相应的处理,两者之间没有直接的耦合关联。
观察者模式分为三大块:
事件监听、事件处理、具体业务流程
例子解析
模拟摇号:
代码结构:
开发中会把主线流程开发完成后,再使⽤通知的⽅式处理辅助流程。他们可以是异步的,在MQ以及定时任务的处理下,保证最终⼀致
性。
事件监听接口定义:
public interface EventListener {void doEvent(LotteryResult result);
}
接口定义基本的事件类
两个监听事件实现:
发送短信的事件:
public class MessageEventListener implements EventListener {private Logger logger = LoggerFactory.getLogger(MessageEventListener.class);public void doEvent(LotteryResult result) {logger.info("给{}发短信{}", result.getuId(), result.getMsg()); }
}
发送MQ的事件:
public class MQEventListener implements EventListener {private Logger logger = LoggerFactory.getLogger(MQEventListener.class);public void doEvent(LotteryResult result) {logger.info("给{}发摇号结果{}", result.getuId(), result.getMsg()); }
}
事件处理类
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}/**订阅*eventType : 事件类型*listener : 监听*/public void subscribe(Enum<EventType> eventType, EventListener listener) {List<EventListener> users = listeners.get(eventType);users.add(listener);}/**取消订阅*eventType : 事件类型*listener : 监听*/public void unsubscribe(Enum<EventType> eventType, EventListener listener) {List<EventListener> users = listeners.get(eventType);users.remove(listener);}/**通知*eventType : 事件类型*result : 结果*/public void notify(Enum<EventType> eventType, LotteryResult result) {List<EventListener> users = listeners.get(eventType);for (EventListener listener : users) {listener.doEvent(result);}}
}
实现了三个主要方法:订阅、取消订阅、通知,用于对于监听事件的添加与使用
事件有不同类型,使用枚举方式进行处理,方便外部在规定下使用事件。
业务抽象类接口:
public abstract class LotteryService {public 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);
}
只有调用draw方法才能完成事件通知
业务接口实现类
public class LotteryServiceImpl extends LotteryService {private MinibusTargetService minibusTargetService = new MinibusTargetService();protected LotteryResult doDraw(String uId) {// 摇号String lottery = minibusTargetService.lottery(uId);// 结果return new LotteryResult(uId, lottery, new Date());}
}
结论
将原有流程拆分为核心流程与辅助流程代码。
核心流程一般不会变,辅助流程可能会变。
此设计模式结构上满足开闭原则,需要新增其他监听事件或者修改监听逻辑,不需要改动事件处理类。