您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~
除了操作集合、限流和缓存,Guava还有另一个隐秘的功能:事件总线EventBus机制——是发布-订阅模式的实现,不需要显式地注册回调——比观察者模式更灵活。
EventBus是在单体架构内实现松耦合的一种很好的手段,通过它可以实现与业务逻辑无关的事件监听和消费。Guava提供的事件总线EventBus分为两种:
1、同步事件EventBus,主要用于单线程环境;
2、异步事件AsyncEventBus,主要用于多线程环境。
可以稍稍回顾一下观察者模式。
在支付系统的设计模式中,当完成交易后,需要给用户发送通知时就使用到了观察者模式,怎么做的呢?
1、定义账户观察者接口及其子接口支付观察者和积分观察者;
2、支付抽象类实现这两个子接口,具体支付类阿里支付、微信支付和余额支付,也都分别实现这两个子接口;
3、在账户类中加入观察者接口列表,并增加注册、删除和调用观察者接口的方法;
4、在支付时将各类支付方式注册到账户的观察者列表中;
5、在交易完成后,就可以调用账户的调用观察者接口的方法,实现回调。
观察者模式的实现稍嫌麻烦。
既然用观察者模式实现比较麻烦,那不妨换个思路,用Guava EventBus来实现,而且无需继承任何接口。调用、发送回调通知同样也很简单,用EventBus把支付回调再来实现一遍。
先定义观察者:
1 /** 2 * 支付宝观察者 3 * 4 * @author 湘王 5 */ 6 public class AliPayObserver { 7 // 标记当前订阅者是线程安全的,支持并发接收消息 8 @AllowConcurrentEvents 9 @Subscribe 10 public void pay(Account account) { 11 if (account.getName().equalsIgnoreCase("ALI")) { 12 System.out.println("支付宝 >>>>>> 已付款"); 13 System.out.println(account.getMessage()); 14 } 15 } 16 }
1 /** 2 * 微信支付观察者 3 * 4 * @author 湘王 5 */ 6 public class WeixinObserver { 7 // 标记当前订阅者是线程安全的,支持并发接收消息 8 @AllowConcurrentEvents 9 @Subscribe 10 public void pay(Account account) { 11 if (account.getName().equalsIgnoreCase("WEIXIN")) { 12 System.out.println("微信 >>>>>> 已付款"); 13 System.out.println(account.getMessage()); 14 } 15 } 16 }
1 /** 2 * 余额支付观察者 3 * 4 * @author 湘王 5 */ 6 public class YuePayObserver { 7 // 标记当前订阅者是线程安全的,支持并发接收消息 8 @AllowConcurrentEvents 9 @Subscribe 10 public void pay(Account account) { 11 if (account.getName().equalsIgnoreCase("YUE")) { 12 System.out.println("余额 >>>>>> 已付款"); 13 System.out.println(account.getMessage()); 14 } 15 } 16 }
然后定义账户类:
1 /** 2 * 账户 3 * 4 * @author 湘王 5 */ 6 public class Account { 7 private String name; 8 private double amount; 9 private Date date; 10 11 public Account(String name, double amount, Date date) { 12 this.name = name; 13 this.amount = amount; 14 this.date = date; 15 } 16 17 public String getName() { 18 return name; 19 } 20 21 public String getMessage() { 22 StringBuilder sb = new StringBuilder(); 23 sb.append("账户:").append(this.name).append(", "); 24 sb.append("金额:").append(amount).append(", "); 25 sb.append("日期:").append(date); 26 return sb.toString(); 27 } 28 }
最后实现事件总线:
1 /** 2 * 事件总线 3 * 4 * @author 湘王 5 */ 6 public class EventBusTest { 7 // 回调通知 8 public static void notifyObserver() { 9 EventBus bus = new EventBus(); 10 AliPayObserver ali = new AliPayObserver(); 11 WeixinObserver weixin = new WeixinObserver(); 12 YuePayObserver yue = new YuePayObserver(); 13 bus.register(ali); 14 bus.register(weixin); 15 bus.register(yue); 16 17 Account account1 = new Account("ALI", 1.6, new Date()); 18 bus.post(account1); 19 Account account2 = new Account("WEIXIN", 2.2, new Date()); 20 bus.post(account2); 21 Account account3 = new Account("YUE", 3, new Date()); 22 bus.post(account3); 23 } 24 25 public static void main(String[] args) throws InterruptedException { 26 notifyObserver(); 27 } 28 }
运行main方法,可以看到,尽管没有显式声明观察者接口,但通过一个@Subscribe注解,就完成了方法回调。这就是EventBus比观察者模式要灵活强大的地方。
如果还不满足,那就再来一个例子。创建观察者接口和具体观察者:
1 /** 2 * 做家务的接口 3 * 4 * @author 湘王 5 */ 6 public interface HouseWork { 7 public void dry(); 8 } 9 10 11 12 /** 13 * 女主人(具体做家务的人) 14 * 15 * @author 湘王 16 */ 17 public class Woman implements HouseWork { 18 @Override 19 public void dry() { 20 System.out.println("可以晾衣服了"); 21 } 22 } 23 24 25 26 创建Subject: 27 28 /** 29 * 洗衣机(Subject类) 30 * 31 * @author 湘王 32 */ 33 public class WashingMachine { 34 private Vector<HouseWork> vector = new Vector<>(); 35 36 public void register(HouseWork work) { 37 vector.add(work); 38 } 39 40 public void unregister(HouseWork work) { 41 vector.remove(work); 42 } 43 44 public void notifyObserver() { 45 for (HouseWork work : vector) { 46 work.dry(); 47 } 48 } 49 50 public static void main(String[] args) throws InterruptedException { 51 // 洗衣机 52 WashingMachine machine = new WashingMachine(); 53 // 女主人 54 Woman woman = new Woman(); 55 // 洗衣机让女主人成为自己的观察者 56 machine.register(woman); 57 System.out.println("将衣服放到洗衣机。。。"); 58 System.out.println("买菜、遛娃中。。。"); 59 Thread.sleep(3000); 60 // 通知观察者(女主人),衣服洗完了 61 machine.notifyObserver(); 62 } 63 }
用EventBus把刚才家庭妇女做家务的例子再来做一遍(现在换成家庭妇男):
1 /** 2 * 具体观察者 3 * 4 * @author 湘王 5 */ 6 public class Man { 7 @Subscribe 8 public void dry(Sheet sheet) { 9 System.out.println("可以晾 " + sheet.getName() + " 床单了"); 10 } 11 } 12 13 14 15 /** 16 * 事件总线 17 * 18 * @author 湘王 19 */ 20 public class EventBusTest { 21 // 回调通知 22 public static void notifyObserver() { 23 EventBus bus = new EventBus(); 24 Man man = new Man(); 25 bus.register(man); 26 bus.post(new Sheet("富安娜")); 27 } 28 29 public static void main(String[] args) { 30 notifyObserver(); 31 } 32 } 33 34 35 36 /** 37 * 床单实体类 38 * 39 * @author 湘王 40 */ 41 public class Sheet { 42 private String name; 43 44 public Sheet(String name) { 45 this.name = name; 46 } 47 48 public String getName() { 49 return name; 50 } 51 52 public void setName(String name) { 53 this.name = name; 54 } 55 }
运行main方法,可以看到和之前一样的效果。事件总线的一个缺点是,回调接口必须有参数——这并不友好。
感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~
标签:湘王,Java,name,void,观察者,Commons,new,Guava,public From: https://www.cnblogs.com/xiangwang1111/p/17093851.html