觀察者模式就是當⼀個⾏為發⽣時傳遞資訊給另外⼀個⽤戶接收做出相應的處理,兩者之間沒有直接的耦合關聯。
觀察者模式分為三大塊:
事件監聽、事件處理、具體業務流程
例子解析
模拟搖号:
代碼結構:
開發中會把主線流程開發完成後,再使⽤通知的⽅式處理輔助流程。他們可以是異步的,在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);
}
業務接口實作類
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());
}
}