登录注册是非常典型的业务需求,以用户注册为场景,用户注册成功后,会给用户发送一条消息,又或者发一个email等,如
public static void register(User user) {
int insert = insert(user);
sendImMessage();
sendMobileMessage();
sendEmailMessage();
}
这样写是正常的逻辑,那会有什么问题呢?
如果需求变了或增加了,如用户注册成功,需要再发送一条短信,于是有得改register方法了,是不是违反了开闭原则了。并且若是发送短信的方法失败了,是不是影响用用户注册了?
这时候若是有个异步方法给通知一下就好了,实际上,可以通过使用观察者模式进行优化,使代码变得更优雅。
观察者模式
观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并完成处理。
观察者模式属于行为模式,一个对象(被观察者)的状态发生改变,所有的依赖对象(观察者)都将得到通知,进行广播通知。
被观察者:目标对象,状态发生变化时,将通知所有的观察者;
观察者:接受被观察者的状态变化通知,执行预先定义的业务;
使用场景:完成某件事情后,异步通知的场景,如登录成功,发送消息等;
观察者模式的实现:
一个被观察者的类Observerable;
一个观察者接口Observer;
多个观察者的实现;
public class Observerable {
private List<Observer> observers = new ArrayList<>();
private int state;
/**
* 添加观察者
*/
public void addObserver(Observer observer) {
observers.add(observer);
}
/**
* 移除观察者
*/
public void removeObserver(Observer observer) {
observers.remove(observer);
}
/**
* 通知
* @return
*/
public void notifyAllObserver(int state) {
if (state != 1) {
System.out.println("非通知状态");
return;
}
for (Observer observer : observers) {
observer.doEvent();
}
}
public int getState() {
return state;
}
public void setState(int state) {
notifyAllObserver(state);
}
}
public interface Observer {
/**
* 观察者事件
*/
void doEvent();
}
public class EmailObserver implements Observer {
@Override
public void doEvent() {
System.out.println("发送email消息");
}
}
public class IMMessageObserver implements Observer {
@Override
public void doEvent() {
System.out.println("发送IM消息");
}
}
public class MobileNoObserver implements Observer {
@Override
public void doEvent() {
System.out.println("发送短信消息");
}
}
测试
public static void main(String[] args) {
User user = new User(1, "caocao", 0);
register(user);
}
public static void register(User user) {
// int insert = insert(user);
// sendImMessage();
// sendMobileMessage();
// sendEmailMessage();
int insert = insert(user);
Observerable observerable = new Observerable();
observerable.addObserver(new IMMessageObserver());
observerable.addObserver(new EmailObserver());
observerable.addObserver(new MobileNoObserver());
observerable.setState(insert);
}
private static void sendEmailMessage() {
}
private static void sendMobileMessage() {
}
private static void sendImMessage() {
}
private static int insert(User user) {
System.out.println("insert success");
return 1;
}
Guava EventBus封装好了一套观察者模式,提供基于注解的事件总线,实例如下
public class EventBusCenter {
private static EventBus eventBus = new EventBus();
private EventBusCenter() {
}
//添加观察者
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);
}
public static EventBus getInstance() {
return eventBus;
}
}
public class EmailEventListener {
@Subscribe //加了订阅,这里标记这个方法是事件处理方法
public void handle(NotifyEvent notifyEvent) {
System.out.println("发送Email消息" + notifyEvent.getEmailNo());
}
}
public class ImEventListener {
@Subscribe //加了订阅,这里标记这个方法是事件处理方法
public void handle(NotifyEvent notifyEvent) {
System.out.println("发送IM消息" + notifyEvent.getImNo());
}
}
public class MobileEventListener {
@Subscribe //加了订阅,这里标记这个方法是事件处理方法
public void handle(NotifyEvent notifyEvent) {
System.out.println("发送短信消息" + notifyEvent.getMobileNo());
}
}
通知对象
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;
}
public String getMobileNo() {
return mobileNo;
}
public void setMobileNo(String mobileNo) {
this.mobileNo = mobileNo;
}
public String getEmailNo() {
return emailNo;
}
public void setEmailNo(String emailNo) {
this.emailNo = emailNo;
}
public String getImNo() {
return imNo;
}
public void setImNo(String imNo) {
this.imNo = imNo;
}
}
测试
public static void main(String[] args) {
// EventListener eventListener = new EventListener();
// EventBusCenter.register(eventListener);
// EventBusCenter.post(new NotifyEvent("13372817283", "123@qq.com", "666"));
ImEventListener imEventListener = new ImEventListener();
MobileEventListener mobileEventListener = new MobileEventListener();
EmailEventListener emailEventListener = new EmailEventListener();
EventBusCenter.register(imEventListener);
EventBusCenter.register(mobileEventListener);
EventBusCenter.register(emailEventListener);
EventBusCenter.unregister(imEventListener);
EventBusCenter.post(new NotifyEvent("12345678901","123456","999"));
}
不同的观察者实现可借助spring容器进行统一注入。