EventBus事件驱动模型
在软件开发过程中, 难免有信息的共享或者对象间的协作。 如何让对象间信息共享高效, 并且耦合性低, 这是一个难题。 而耦合性高将带来编码修改牵一发而动全身的连锁效应, Spring的风靡正是因为解决了高耦合问题。 本篇介绍的EventBus中也用到了Spring中的依赖注入, 来进行对象和对象间的解耦(如@Subscribe)。
Guava解决高耦合采用的是事件驱动模型的思路, 对象可以订阅(subscribe)特定的事件或者发布(publish)特定的事件去被消费。 从下面的代码可以看出, EventBus对生产者和消费者是透明的, 它无需知道他们的类型, 从而实现了解耦。
TradeAccountEvent: 基本对象兼测试类
package com.wenniuwuren.eventbus;
import com.google.common.eventbus.EventBus;
import java.util.Date;
/**
* 不管什么时候买卖交易执行, 都会产生一个TradeAccountEvent实例
*/
public class TradeAccountEvent {
private double amount;
private Date tradeExecutionTime;
private String tradeType;
private String tradeAccount;
public TradeAccountEvent(String account, double amount,
Date tradeExecutionTime, String tradeType) {
this.amount = amount;
this.tradeExecutionTime =tradeExecutionTime;
this.tradeAccount = account;
this.tradeType = tradeType;
}
public static void main(String[] args) {
// 消费者和生产者根据EventBus对象来一一对应
EventBus eventBus1 = new EventBus();
SimpleTradeAuditor simpleTradeAuditor = new SimpleTradeAuditor(eventBus1);
SimpleTradeExecutor simpleTradeExecutor = new SimpleTradeExecutor(eventBus1);
simpleTradeExecutor.executeTrade("zhangsan", 10, "Money");
System.out.println("----This is devil dividing line------");
EventBus eventBus2 = new EventBus();
BuySellTradeExecutor buySellTradeExecutor = new BuySellTradeExecutor(eventBus2);
AllTradesAuditor allTradesAuditor = new AllTradesAuditor(eventBus2);
buySellTradeExecutor.executeTrade("lisi", 100, "SELL");
System.out.println("---------------------");
buySellTradeExecutor.executeTrade("wangwu", 1000, "BUY");
}
}
AllTradesAuditor:根据不同生产者订阅不同内容:
package com.wenniuwuren.eventbus;
import java.util.List;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
public class AllTradesAuditor {
private List<BuyEvent> buyEvents = Lists.newArrayList();
private List<SellEvent> sellEvents = Lists.newArrayList();
public AllTradesAuditor(EventBus eventBus) {
eventBus.register(this);
}
@Subscribe
public void auditSell(SellEvent sellEvent) {
sellEvents.add(sellEvent);
System.out.println("Received TradeSellEvent " + sellEvent);
}
@Subscribe
public void auditBuy(BuyEvent buyEvent) {
buyEvents.add(buyEvent);
System.out.println("Received TradeBuyEvent " + buyEvent);
}
}
BuyEvent:
package com.wenniuwuren.eventbus;
import java.util.Date;
/**
* 购买事件
* @author wenniuwuren
*
*/
public class BuyEvent extends TradeAccountEvent {
public BuyEvent(String tradeAccount, double amount,
Date tradExecutionTime) {
super(tradeAccount, amount, tradExecutionTime, "BUY");
}
}
SellEvent:
package com.wenniuwuren.eventbus;
import java.util.Date;
/**
* 销售事件
* @author wenniuwuren
*
*/
public class SellEvent extends TradeAccountEvent {
public SellEvent(String tradeAccount, double amount, Date tradExecutionTime) {
super(tradeAccount, amount, tradExecutionTime, "SELL");
}
}
BuySellTradeExecutor: 分类型(BUY、SELL)发布事件
package com.wenniuwuren.eventbus;
import java.util.Date;
import com.google.common.eventbus.EventBus;
/**
* 分类型(SELL BUY)执行器
* @author wenniuwuren
*
*/
public class BuySellTradeExecutor {
private EventBus eventBus;
public BuySellTradeExecutor(EventBus eventBus) {
this.eventBus = eventBus;
}
private TradeAccountEvent processTrade(String tradeAccount, double amount,
String tradeType) {
Date executionTime = new Date();
String message = String.format("Processed trade for" + tradeAccount
+ "of amount" + amount + "type" + tradeType + "@"
+ executionTime);
TradeAccountEvent tradeAccountEvent;
if (tradeType.equals("BUY")) {
tradeAccountEvent = new BuyEvent(tradeAccount, amount,
executionTime);
} else {
tradeAccountEvent = new SellEvent(tradeAccount, amount,
executionTime);
}
System.out.println(message);
return tradeAccountEvent;
}
public void executeTrade(String tradeAccount, double amount, String tradeType) {
TradeAccountEvent tradeAccountEvent = processTrade(tradeAccount, amount, tradeType);
// 发布, 通知订阅者
eventBus.post(tradeAccountEvent);
}
}
SimpleTradeAuditor: 最简单的事件消费者(或者说订阅者)
package com.wenniuwuren.eventbus;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import java.util.List;
/**
* 审核交易
*/
public class SimpleTradeAuditor {
private List<TradeAccountEvent> tradeEvents = Lists.newArrayList();
public SimpleTradeAuditor(EventBus eventBus) {
// 注册, 以便获取TradeAccountEvent的通知
eventBus.register(this);
}
/**
* 事件处理(用@Subscribe注解表示)
* @param tradeAccountEvent
*/
@Subscribe
public void auditTrade(TradeAccountEvent tradeAccountEvent) {
tradeEvents.add(tradeAccountEvent);
System.out.println("Received trade " + tradeAccountEvent);
}
}
TradeBuyAuditor:分类型事件消费:
package com.wenniuwuren.eventbus;
import java.util.List;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
/**
* 购买审查
* @author wenniuwuren
*
*/
public class TradeBuyAuditor {
private List<BuyEvent> buyEvents = Lists.newArrayList();
public TradeBuyAuditor(EventBus eventBus) {
eventBus.register(this);
}
@Subscribe
public void auditBuy(BuyEvent buyEvent) {
buyEvents.add(buyEvent);
System.out.println("Received TradeBuyEvent " + buyEvent);
}
public List<BuyEvent> getBuyEvents() {
return buyEvents;
}
}
TradeSellAuditor:
package com.wenniuwuren.eventbus;
import java.util.List;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
/**
* 销售审查
* @author wenniuwuren
*
*/
public class TradeSellAuditor {
private List<SellEvent> sellEvents = Lists.newArrayList();
public TradeSellAuditor(EventBus eventBus) {
eventBus.register(this);
}
@Subscribe
public void auditSell(SellEvent sellEvent) {
sellEvents.add(sellEvent);
System.out.println("Received SellEvent " + sellEvent);
}
public List<SellEvent> getSellEvents() {
return sellEvents;
}
}
输出结果:
Processed trade forzhangsanof amount10.0typeMoney@Fri Jun 12 02:29:03 CST 2015
Received trade com.wenniuwuren.eventbus.TradeAccountEvent@7c53a9eb
----This is devil dividing line------
Processed trade forlisiof amount100.0typeSELL@Fri Jun 12 02:29:03 CST 2015
Received TradeSellEvent com.wenniuwuren.eventbus.SellEvent@14899482
---------------------
Processed trade forwangwuof amount1000.0typeBUY@Fri Jun 12 02:29:03 CST 2015
Received TradeBuyEvent com.wenniuwuren.eventbus.BuyEvent@21588809
FluentIterable类:
使用FluentIterable.filter过滤, 即利用Predicate实现:
Iterable<Person> adults = FluentIterable.from(ps).filter(
new Predicate<Person>() {
@Override
public boolean apply(Person p) {
return p.getAge() >= 18; // 年龄>18
}
});
使用FluentIterable.transform()转换,即利用Function实现
FluentIterable.from(ps).transform(new Function<Person, String>() {
@Override
public String apply(Person p) {
return Joiner.on('#').join(p.getName(), p.getAge());
}
});
Lists类
使用Lists.newArrayList创建列表:
ps = Lists.newArrayList(
new Person("person1", 22),
new Person("person2", 23),
new Person("person3", 17)
);
使用Lists.partition()方法分割列表:
//[a, b, c, d, e] --> [[a, b], [c, d, e]] -
List<List<Person>> subList = Lists.partition(ps, 2);
Sets类:
Sets.difference()求S1-S2
Set<String> s1 = Sets.newHashSet("1", "2", "3");
Set<String> s2 = Sets.newHashSet("2", "3", "4");
Sets.difference(s1, s2); //[1]
Sets.intersection()求S1,S2交集
Set<String> s1 = Sets.newHashSet("1", "2", "3");
Set<String> s2 = Sets.newHashSet("3", "2", "4");
Sets.SetView<String> sv = Sets.intersection(s1, s2); // [2, 3]
Sets.union()求合集
Set<String> s1 = Sets.newHashSet("1", "2", "3");
Set<String> s2 = Sets.newHashSet("3", "2", "4");
Sets.SetView<String> sv = Sets.union(s1, s2); // [3, 2, 1 ,4]
Maps类:
Maps.uniqueIndex()将列表转换为map:
//iterator各个元素作为Map.values, key为Function.apply返回值
Maps.uniqueIndex(ps.iterator(), new Function<Person, String>() {
@Override
public String apply(Person p) {
return p.getName();
}
});
Maps.asMap(),<K, V>和Maps.uniqueIndex()相反
Maps.asMap(ps, new Function<Person, String>() {
@Override
public String apply(Person p) {
return p.getName();
}
});
Maps Transform API:
将Map<String, Boolean> --> Map<String, String>, 其他的还有Maps.transformValues转换值
Maps.transformEntries(map, new Maps.EntryTransformer<String, Boolean, String>() {
@Override
public String transformEntry(String key, Boolean value) {
return value ? "yes" : "no";
}
});
Multimaps:
一个key对应多个value。
ArrayListMultiMap:
ArrayListMultimap<String, String> multiMap = ArrayListMultimap.create();
multiMap.put("Foo", "1");
multiMap.put("Foo", "2");
multiMap.put("Foo", "3");
System.out.println(multiMap); // {Foo=[1,2,3]}
当出现重复值时,依然会被添加,因为ArrayListMultiMap的value时一个ArrayList:
ArrayListMultimap<String, String> multiMap = ArrayListMultimap.create();
multiMap.put("Bar", "1");
multiMap.put("Bar", "2");
multiMap.put("Bar", "3");
multiMap.put("Bar", "3");
multiMap.put("Bar", "3");
System.out.println(multiMap); //{Bar=[1, 2, 3, 3, 3]},相同的value会重复,value内部是一个List
HashMultiMap:
HashMultimap<String, String> multiMap = HashMultimap.create();
multiMap.put("Bar", "1");
multiMap.put("Bar", "2");
multiMap.put("Bar", "3");
multiMap.put("Bar", "3");
multiMap.put("Bar", "3");
System.out.println(multiMap); //{Bar=[3, 2, 1]}, 相同的value不会重复,value内部是一个Set
其他一些MultiMap:
LinkedHashMultimap //顺序的HashMultimap, 形如LinkedHashMap
TreeMultimap //可排序的MultiMap, 形如TreeMap
//一些不可变的map
ImmutableListMultimap
ImmutableMultimap
ImmutableSetMultimap
BiMap:
其限制value是唯一的,且通过value可以找到key
BiMap<String,String> biMap = HashBiMap.create();
biMap.put("1","Tom");
biMap.put("2","Tom"); //抛出异常
BiMap.forcePut()强制放入value相等的entry:
BiMap<String, String> biMap = HashBiMap.create();
biMap.put("1", "Tom");
biMap.forcePut("2", "Tom");
System.out.println(biMap); //{2=Tom}
BiMap.inverse()反转key-value
BiMap<String, String> biMap = HashBiMap.create();
biMap.put("1", "Tom");
biMap.put("2", "Harry");
BiMap<String, String> inverseMap = biMap.inverse();
System.out.println(biMap); //{2=Harry, 1=Tom}
System.out.println(inverseMap); //{Harry=2, Tom=1
Table:
它具有2个key[行, 列],对应一个值。
HashBasedTable:
通用操作:
HashBasedTable<Integer, Integer, String> table = HashBasedTable.create();
table.put(1, 1, "Rook");
table.put(1, 2, "Knight");
table.put(1, 3, "Bishop");
System.out.println(table.contains(1, 1)); //true
System.out.println(table.containsColumn(2)); //true
System.out.println(table.containsRow(1)); //true
System.out.println(table.containsValue("Rook")); //true
System.out.println(table.remove(1, 3)); //Bishop
System.out.println(table.get(3, 4)); //null
Table views,表行列视图:
Map<Integer,String> columnMap = table.column(1);
Map<Integer,String> rowMap = table.row(2);
其他table:
ArrayTable //二维数组实现
ImmutableTable //不可变table,创建后不能改变
TreeBasedTable //对行列排序的table
Range代表一种范围的类。:
Range<Integer> numberRange = Range.closed(1, 10); //包括首尾
System.out.println(numberRange.contains(10)); //true
System.out.println(numberRange.contains(1)); //true
Range<Integer> numberRange1 = Range.open(1,10); //除去首尾
System.out.println(numberRange1.contains(10)); //false
System.out.println(numberRange1.contains(1)); //false
Range和Function组合成Predicate的过滤条件:
Range<Integer> ageRange = Range.closed(35, 50);
//Person到age转换的function
Function<Person, Integer> ageFunction = new Function<Person, Integer>() {
@Override
public Integer apply(Person person) {
return person.getAge();
}
};
//这样得到年龄再[35, 50]之间的人
Predicate<Person> predicate = Predicates.compose(ageRange,ageFunction);
创建不可变的集合:
ultiMap<Integer,String> map = new ImmutableListMultimap.Builder<Integer,String>()
.put(1,"Foo").putAll(2,"Foo","Bar","Baz")
.putAll(4,"Huey","Duey","Luey")
.put(3,"Single").build();
Ordering:Ordering提供了一些简单强大的排序功能。:
/**
* 城市人口比较器
*/
public class CityByPopluation implements Comparator<City> {
@Override
public int compare(City city1, City city2) {
return Ints.compare(city1.getPopulation(), city2.getPopulation());
}
}
反序:
Ordering.from(cityByPopluation).reverse();
处理Null:
Ordering.from(comparator).nullsFirst();//null值最小放在前面
二次排序:
/**
* 雨量比较器
*/
public class CityByRainfall implements Comparator<City> {
@Override
public int compare(City city1, City city2) {
return Doubles.compare(city1.getAverageRainfall(),
city2.getAverageRainfall());
}
}
Ordering<City> secondaryOrdering = Ordering.from(cityByPopulation).compound(cityByRainfall);//组合比较器
Collections.sort(cities,secondaryOrdering); //排序
获取最大最小:
Ordering<City> ordering = Ordering.from(cityByPopluation);
List<City> topFive = ordering.greatestOf(cityList,5); //前5个
List<City> bottomThree = ordering.leastOf(cityList,3); //最后3个