可重用函數(shù)塊基本是你一開始使用 Reactor 就需要的核心功能。[1] 那么函數(shù)式編程酷在哪里呢? 其核心理念之一將可執(zhí)行代碼當作另一種數(shù)據(jù)來處理。[2]業(yè)務邏輯由原始調用者決定,這與閉包和匿名函數(shù)的理念不謀而合。函數(shù)式編程還避免了 IF/SWITCH 語句塊的包袱,并清晰地分離了功能:每個代碼塊只負責一個獨立功能,而不共享內容。
- 除非你只想用核心處理功能,而這些功能在這一階段是基本獨立的。我們打算逐步將調度器與核心調整到一致。
- 有人也許要說這觀點過于簡化了,不過我們這里先講求實用 :)
規(guī)劃函數(shù)塊
每個函數(shù)組件有明確的功能:
? 我們將發(fā)布者和訂閱者接口也作為函數(shù)塊處理,我們稱之為響應式函數(shù)塊。它們是基本的組件,在 Reactor 和 Beyond 中到處都有用到。通??梢灾苯诱{用數(shù)據(jù)流 API 來創(chuàng)建恰當?shù)挠嗛喺?,你只需要?API 傳入 reactor.fn 參數(shù)。
好消息是:封裝在函數(shù)功能中的可執(zhí)行指令,可以像樂高積木一樣重用。
Consumer<String> consumer = new Consumer<String>(){
@Override
void accept(String value){
System.out.println(value);
}
};
// 為了簡約,現(xiàn)在用 Java 8 風格
Function<Integer, String> transformation = integer -> ""+integer;
Supplier<Integer> supplier = () -> 123;
BiConsumer<Consumer<String>, String> biConsumer = (callback, value) -> {
for(int i = 0; i < 10; i++){
// 對要運行的最后邏輯運行做惰性求值
callback.accept(value);
}
};
// 注意生產(chǎn)者到雙向消費者執(zhí)行過程
biConsumer.accept(
consumer,
transformation.apply(
supplier.get()
)
);
乍一看,你可能會覺得這個革新并不特別,但是這種編程理念的變化,對后續(xù)我們構建分層可組合代碼卻尤其重要。調度者通過消費者處理類型化的數(shù)據(jù)和錯誤的回調。Reactor Stream 模塊也基于該理念實現(xiàn)優(yōu)雅編碼。
? 使用 Spring 這樣的 IoC 容器的良好實踐是利用 Java 配置特性返回無狀態(tài)函數(shù)式 Beans。然后就可以從容地將代碼塊注入數(shù)據(jù)流管道,或者指派代碼塊的執(zhí)行。
元組
或許你已經(jīng)注意到:Reactor 提供的接口都是強類型、帶有泛型支持和少量確定數(shù)目的參數(shù)。那如果形參個數(shù)大于1或者2呢,又該怎么辦呢?此時,需要使用一個類:元組。元組像是單對象實例中的帶類型 CSV 行,在函數(shù)式編程中,就是通過元組保證類型安全呢和可變參數(shù)。
讓我們用雙參數(shù)雙向消費者代替單參數(shù)消費者實現(xiàn)上例的過程:
Consumer<Tuple2<Consumer<String>, String>> biConsumer = tuple -> {
for(int i = 0; i < 10; i++){
// 類型正確,開啟編譯器
tuple.getT1().accept(tuple.getT2());
}
};
biConsumer.accept(
Tuple.of(
consumer,
transformation.apply(supplier.get())
)
);
? 元組涉及到更多的資源分配,因此,通常鍵值對比較和鍵值信號量更傾向使用 Bi **類型接口。