概述
在对象之间定义一个被观察者和多个观察者,当被观察者的状态改变的时候,所有观察者都回自动收到通知
demo
有一个注册接口的需求,注册后,发放体验金和发送邮件,发放体验金和发送邮件为观察者由被观察者根据需要使用多线程调用,如图
对于多线程的使用基于这样的思考,希望接口的响应时间尽可能短,这样userController.register()函数就不需要等到所有的handlerMessage函数都执行完成之后才返回结果给客户端。userController.register()函数从执行3个SQL语句才返回,减少到只需要执行1个SQL语句就返回,响应时间减少为原来的1/3。如何实现呐?做法是,使用线程池执行代码
public class UserController {
private List<UserObserver> userObserves = new ArrayList<>();
public String register(String telephone,String password) throws Exception {
UserService userService = new UserService();
Long userId = userService.register(telephone,password);
userObserves.add(new PromotionServiceHandler());
userObserves.add(new SendEmailHandler());
ExecutorService exec = Executors.newFixedThreadPool(10);
Runnable run = new Runnable() {
@SneakyThrows
@Override
public void run() {
noticeObserver(userId);
}
};
exec.execute(run);
return "register完成";
}
private void noticeObserver(Long userId) throws Exception {
if (userObserves==null||userObserves.size()<=0){
throw new Exception("观察者列表不能为空");
}
for (UserObserver oneObserve:userObserves) {
oneObserve.handlerMessage(userId);
}
}
public static void main(String[] args) throws Exception {
UserController userController = new UserController();
String register = userController.register("1", "2");
System.out.println(register);
}
}
public class SendEmail {
public void sendMsg(Long userId){
System.out.println("sendMsgThread");
}
}
public class SendEmailHandler implements UserObserver {
@Override
public void handlerMessage(Long userId) {
SendEmail sendEmail = new SendEmail();
sendEmail.sendMsg(userId);
}
}
public class PromotionService {
public void issueNewUserExperienceCash(long userId) {
System.out.println("进入PromotionServiceThread");
}
}
public class PromotionServiceHandler implements UserObserver {
@Override
public void handlerMessage(Long userId) {
PromotionService promotionService = new PromotionService();
promotionService.issueNewUserExperienceCash(userId);
}
}
当然如果你不愿意使用线程池,也可以使用Thread来开启一个新的线程
但是我们知道对于第一种实现方式,尽管利用了线程池解决了第一种实现方式的问题,但线程池、异步执行逻辑都耦合载来register函数中,增加了这部分业务代码的维护成本。第二种实现方式,频繁地创建和销毁线程比较耗时,并且并发线程数无法控制,创建过多的线程回导致堆栈溢出。
Google Guava类库提供了一个利用观察者模式实现EventBus类,它无需从0编写代码,只需要通过register函数注册观察者,通过post给观察者发送消息
基于EventBus,我们不需要定义Observer接口,任意类型的对象都可以注册到EventBus中,通过@Subscribe注解来标明哪个函数可以接收被观察者发送的消息
改造代码如下:
public class UserControllerWithBus {
private List<UserObserver> userObserves = new ArrayList<>();
private EventBus eventBus;
public UserControllerWithBus(){
eventBus = new AsyncEventBus(Executors.newFixedThreadPool(20));
}
public String register(String telephone,String password) throws Exception {
UserService userService = new UserService();
Long userId = userService.register(telephone,password);
eventBus.register(new PromotionServiceHandlerBus());
eventBus.register(new SendEmailHandlerBus());
eventBus.post(userId);
return "register完成";
}
public static void main(String[] args) throws Exception {
UserControllerWithBus userController = new UserControllerWithBus();
String register = userController.register("1", "2");
System.out.println(register);
}
}
public class PromotionServiceHandlerBus implements UserObserver {
@Subscribe
public void handlerMessage(Long userId) {
PromotionService promotionService = new PromotionService();
promotionService.issueNewUserExperienceCash(userId);
}
}
public class SendEmailHandlerBus implements UserObserver {
@Subscribe
public void handlerMessage(Long userId) {
SendEmail sendEmail = new SendEmail();
sendEmail.sendMsg(userId);
}
}