业务场景
登陆注册应该是最常见的业务场景了。就拿注册来说事,我们经常会遇到类似的场景,就是用户注册成功后,我们给用户发一条消息,又或者发个邮件等等,因此经常有如下的代码:
void register(User user){
insertRegisterUser(user);
sendIMMessage();
sendEmail();
}
这块代码会有什么问题呢?如果产品又加需求:现在注册成功的用户,再给用户发一条短信通知。于是你又得改register方法的代码了。。。这是不是违反了开闭原则啦。
void register(User user){
insertRegisterUser(user);
sendIMMessage();
sendMobileMessage();
sendEmail();
}
并且,如果调发短信的接口失败了,是不是又影响到用户注册了?!这时候,是不是得加个异步方法给通知消息才好。。。
实际上,我们可以使用观察者模式优化。
观察者模式定义
观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被完成业务的更新。
观察者模式属于行为模式,一个对象(被观察者)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。它的主要成员就是观察者和被观察者。
- 被观察者(Observerable):目标对象,状态发生变化时,将通知所有的观察者。
- 观察者(observer):接受被观察者的状态变化通知,执行预先定义的业务。
使用场景: 完成某件事情后,异步通知场景。如,登陆成功,发个IM消息等等。
###观察者模式使用
观察者模式实现的话,还是比较简单的。
- 一个被观察者的类Observerable ;
- 多个观察者Observer ;
- 观察者的差异化实现
- 经典观察者模式封装:EventBus实战
一个被观察者的类Observerable 和 多个观察者Observer
public class Observerable {
private List<Observer> observers
= new ArrayList<Observer>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
notifyAllObservers();
}
//添加观察者
public void addServer(Observer observer){
observers.add(observer);
}
//移除观察者
public void removeServer(Observer observer){
observers.remove(observer);
}
//通知
public void notifyAllObservers(int state){
if(state!=1){
System.out.println(“不是通知的状态”);
return ;
}
for (Observer observer : observers) {
observer.doEvent();
}
}
}
观察者的差异化实现
//观察者
interface Observer {
void doEvent();
}
//Im消息
IMMessageObserver implements Observer{
void doEvent(){
System.out.println("发送IM消息");
}
}
//手机短信
MobileNoObserver implements Observer{
void doEvent(){
System.out.println("发送短信消息");
}
}
//EmailNo
EmailObserver implements Observer{
void doEvent(){
System.out.println("发送email消息");
}
}
EventBus实战
自己搞一套观察者模式的代码,还是有点小麻烦。实际上,Guava EventBus就封装好了,它 提供一套基于注解的事件总线,api可以灵活的使用,爽歪歪。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
我们来看下EventBus的实战代码哈,首先可以声明一个EventBusCenter类,它类似于以上被观察者那种角色Observerable。
public class EventBusCenter {
private static EventBus eventBus = new EventBus();
private EventBusCenter() {
}
public static EventBus getInstance() {
return eventBus;
}
//添加观察者
public static void register(Object obj) {
eventBus.register(obj);
}
//移除观察者
public static void unregister(Object obj) {
eventBus.unregister(obj);
}
//把消息推给观察者
public static void post(Object obj) {
eventBus.post(obj);
}
}
然后再声明观察者EventListener
public class EventListener {
@Subscribe //加了订阅,这里标记这个方法是事件处理方法
public void handle(NotifyEvent notifyEvent) {
System.out.println("发送IM消息" + notifyEvent.getImNo());
System.out.println("发送短信消息" + notifyEvent.getMobileNo());
System.out.println("发送Email消息" + notifyEvent.getEmailNo());
}
}
//通知事件类
public class NotifyEvent {
private String mobileNo;
private String emailNo;
private String imNo;
public NotifyEvent(String mobileNo, String emailNo, String imNo) {
this.mobileNo = mobileNo;
this.emailNo = emailNo;
this.imNo = imNo;
}
}
使用demo测试:
public class EventBusDemoTest {
public static void main(String[] args) {
EventListener eventListener = new EventListener();
EventBusCenter.register(eventListener);
EventBusCenter.post(new NotifyEvent("13372817283", "123@qq.com", "666"));
}
}
运行结果:
发送IM消息666
发送短信消息13372817283
发送Email消息123@qq.com