对象作为参数示例java_功能Java示例 第6部分–用作参数
對象作為參數示例java
這是稱為“ Functional Java by Example”的系列文章的第6部分。
我在本系列的每個部分中開發的示例是某種“提要處理程序”,用于處理文檔。 在前面的部分,我們試圖通過移動盡可能多的副作用,如IO,該系統的外部,以使我們的純可能的功能。
現在,我們將一些抽象替換為函數,以作為參數傳遞。
如果您是第一次來,最好是從頭開始閱讀。 它有助于了解我們從何處開始以及如何在整個系列中繼續前進。
這些都是這些部分:
- 第1部分–從命令式到聲明式
- 第2部分–講故事
- 第3部分–不要使用異常來控制流程
- 第4部分–首選不變性
- 第5部分–將I / O移到外部
- 第6部分–用作參數
- 第7部分–將失敗也視為數據
- 第8部分–更多純函數
我將在每篇文章發表時更新鏈接。 如果您通過內容聯合組織來閱讀本文,請查看我博客上的原始文章。
每次代碼也被推送到這個GitHub項目 。
OO型協作者
還記得我們以前留下的東西嗎?
class FeedHandler {Webservice webserviceList<Doc> handle(List<Doc> changes) {changes.findAll { doc -> isImportant(doc) }.collect { doc ->createResource(doc).thenApply { resource ->setToProcessed(doc, resource)}.exceptionally { e ->setToFailed(doc, e)}.get()}}private CompletableFuture<Resource> createResource(doc) {webservice.create(doc)}private static boolean isImportant(doc) {doc.type == 'important'}private static Doc setToProcessed(doc, resource) {doc.copyWith(status: 'processed',apiId: resource.id)}private static Doc setToFailed(doc, e) {doc.copyWith(status: 'failed',error: e.message)}}上面的提要處理程序需要一個“ Web服務”來完成其工作。
請看以下部分,其中使用WebService類型的協作者來創建基于文檔的資源:
class FeedHandler {Webservice webserviceList<Doc> handle(List<Doc> changes) {changes.collect { doc ->createResource(doc)...}private CompletableFuture<Resource> createResource(doc) {webservice.create(doc)}}請記住, 作為異常處理機制的一部分,我們將其包裝在CompletableFuture ,而不是直接返回資源。
如果我們想要WebService以外的其他資源來創建資源怎么辦?
好吧,這是同時變得棘手和容易的地方-OO風格可能與FP風格有些沖突。
您會看到, WebService是一個Java接口,定義如下:
interface Webservice {CompletableFuture<Resource> create(Doc doc) }這遵循了Dependency Inversion Principle(DIP) ,它是Robert C. Martin提倡的SOLID設計原則的一部分,(其中包括):
抽象不應依賴細節。 細節應取決于抽象。
WebService已經是任何類型的Webservice 實現的抽象。 因此,系統可以具有此接口的多種實現,例如REST實現和SOAP實現:
class RestWebService implements Webservice {@OverrideCompletableFuture<Resource> create(Doc doc) {// do REST communication} } class SoapWebService implements Webservice {@OverrideCompletableFuture<Resource> create(Doc doc) {// do SOAP communication} }提要處理程序不關心細節 ,它只需要遵守WebService接口定義的協定的東西:有一個create方法可以接受Doc并返回CompletableFuture 。
FeedHandler類具有一個webservice屬性,其中包含對WebService的引用。 任何OO開發人員都可以識別這種樣式,因為它非常熟悉:所有協作者都存在于屬性中,這些屬性(通常)是在構造過程中初始化的。
一旦構造了FeedHandler ,就可以通過DI框架或普通的手工方法將傳遞的WebService實例傳遞給它-盡管可以使用構造函數注入或屬性注入。
為了簡潔起見,我一直在代碼片段中省略了構造函數,但是正如您在測試用例中所看到的那樣, 我絕對使用Groovy為我生成的構造函數傳遞所有依賴關系。
協作者FP風格
好的,如果我們再次戴上Functional Hat,我們將需要重新審視將WebService傳遞到提要處理程序的方式。
該handle方法的簽名不提比其他任何東西:文件進去 ,文件出來 。
class FeedHandler {...List<Doc> handle(List<Doc> changes) {...}}我不能假定將返回相同的輸入 相同的輸出 -因為該方法暗中依賴于外的東西:對WebService 。
好吧,也許我可以控制供稿處理程序的整個創建過程,包括WebService ,但是在方法調用之間可以更改對webservice引用,每次handle使用它時都會產生其他結果。 除非我將其設為不可變的,否則將阻止引用的更新。 我告訴過你可能會很棘手
是否可以像上一期中使用isImportant , setToProcessed和setToFailed方法一樣使純正的 handle ?
在這種情況下,我們必須將WebService作為參數傳遞,就像傳遞文檔列表一樣。
我們改變
class FeedHandler {Webservice webserviceList<Doc> handle(List<Doc> changes) {...}}進入
class FeedHandler {List<Doc> handle(List<Doc> changes, Webservice webservice) {...}}在每次調用handle我們都會傳遞它需要的所有內容:需要處理的文檔和需要使用的Web服務。
由于此方法不再依賴于FeedHandler類中的任何屬性,因此我們現在可以使其變為static -將其升級為類級方法。
高階函數
實際上,我們的handle方法剛剛變成了所謂的“高階函數”,即接受一個函數或返回一個函數的函數。
因此,回到開始時我提出的一個問題: 如果我們想要WebService以外的其他東西來創建資源該怎么辦?
它甚至不應該是Web服務嗎? 也許我們完全想吃香蕉,一只猴子為我們創造資源?
class Monkey implements Webservice {@OverrideCompletableFuture<Resource> create(Doc doc) {// go bananas! But do create resources plz} }看起來很奇怪,不是嗎? 對于抽象提要處理程序的需要, WebService接口太具體了。 任何創造資源的東西都會起作用,不是嗎?
更好的名稱是“ ResourceCreator” ,因此只需重命名接口即可。
舊:
interface Webservice {CompletableFuture<Resource> create(Doc doc) }新:
interface ResourceCreator {CompletableFuture<Resource> create(Doc doc) }具有create方法的ResourceCreator接口; 多么合身! 現在任何東西都可以實現此接口,并且提要處理程序甚至不在乎它是Web服務,猴子還是霍比特人。
新方法簽名:
class FeedHandler {List<Doc> handle(List<Doc> changes, ResourceCreator creator) {...}}完美的抽象!
功能抽象
在Java中,我們將只有一種抽象方法的接口稱為功能接口 。 我們的ResourceCreator符合此描述; 它具有單個抽象方法create 。
Java的java.util.function程序包具有許多這些功能接口,并且每個功能接口都有一個已定義的用途:
- Consumer表示一個接受參數且不返回任何內容的函數
- Supplier表示不接受任何參數的函數,僅返回結果
- Function表示接受一個參數并返回結果的函數
- …和更多
這意味著,我們不需要每次都需要一個函數“接受一個參數并返回結果”時就定義一個特定的接口,例如ResourceCreator - Function已經是一個我們可以利用的接口!
這就是Java 8中的Function (簡體)的樣子:
interface Function<T,R> {R apply(T t); }這就是ResourceCreator現在的樣子:
interface ResourceCreator {CompletableFuture<Resource> create(Doc doc) }您會看到,如果滿足以下條件,我們可以用Function完全替代ResourceCreator :
- 用Doc代替R型
- 用T型替代CompletableFuture
- 替代調用create由該方法apply
我們可以完全刪除ResourceCreator界面!
新方法簽名將變為:
class FeedHandler {List<Doc> handle(List<Doc> changes,Function<Doc, CompletableFuture<Resource>> creator) {...}}我們取得了什么成就?
- 我們現在可以傳遞任何要handle 函數 ,該函數需要一個Doc并產生一個CompletableFuture —這就是feed處理程序正常工作所需的全部。
- 正如您現在可能已經注意到的,函數編程處理了很多函數 。 一個函數可以采用另一個函數,也可以返回一個函數。
- 從Java 8開始,我們已經準備好了很多功能接口。 每個開發人員都可以以標準化的方式與他們合作,因此最好查看它們是否適合您的用例和API,并盡可能重用它們。 他們每個人都有泛型類型(如T和R可以由你來表明在發生什么,什么來的函數的輸出 )。
現在,完整的代碼如下所示:
class FeedHandler {List<Doc> handle(List<Doc> changes,Function<Doc, CompletableFuture<Resource>> creator) {changes.findAll { doc -> isImportant(doc) }.collect { doc ->creator.apply(doc).thenApply { resource ->setToProcessed(doc, resource)}.exceptionally { e ->setToFailed(doc, e)}.get()}}private static boolean isImportant(doc) {doc.type == 'important'}private static Doc setToProcessed(doc, resource) {doc.copyWith(status: 'processed',apiId: resource.id)}private static Doc setToFailed(doc, e) {doc.copyWith(status: 'failed',error: e.message)}}現在就這樣! 下次,我們將處理故障數據。
如果您有任何意見或建議,我很想聽聽他們的意見!
翻譯自: https://www.javacodegeeks.com/2018/12/functional-java-functions-parameters.html
對象作為參數示例java
總結
以上是生活随笔為你收集整理的对象作为参数示例java_功能Java示例 第6部分–用作参数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: xyz域名怎么备案(xyz域名备案 腾讯
- 下一篇: 域名怎么投诉(如何投诉域名)