EventBus事件驅動模型java
在軟件開發過程當中, 不免有信息的共享或者對象間的協做。 如何讓對象間信息共享高效, 而且耦合性低, 這是一個難題。 而耦合性高將帶來編碼修改牽一髮而動全身的連鎖效應, Spring的風靡正是由於解決了高耦合問題。 本篇介紹的EventBus中也用到了Spring中的依賴注入, 來進行對象和對象間的解耦(如@Subscribe)。數組
Guava解決高耦合採用的是事件驅動模型的思路, 對象能夠訂閱(subscribe)特定的事件或者發佈(publish)特定的事件去被消費。 從下面的代碼能夠看出, EventBus對生產者和消費者是透明的, 它無需知道他們的類型, 從而實現瞭解耦。app
TradeAccountEvent: 基本對象兼測試類 ide
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:根據不一樣生產者訂閱不一樣內容:post
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:ui
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)發佈事件this
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: 最簡單的事件消費者(或者說訂閱者)google
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個