觀察者模式就是當?個?為發?時傳遞信息給另外?個?戶接收做出相應的處理,兩者之間沒有直接的耦合關聯。
觀察者模式分為三大塊:
事件監聽、事件處理、具體業務流程
例子解析
模擬搖號:
代碼結構:
開發中會把主線流程開發完成后,再使?通知的?式處理輔助流程。他們可以是異步的,在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());}
}
結論
將原有流程拆分為核心流程與輔助流程代碼。
核心流程一般不會變,輔助流程可能會變。
此設計模式結構上滿足開閉原則,需要新增其他監聽事件或者修改監聽邏輯,不需要改動事件處理類。