本文翻譯自: Composition in Flutter & Dart 在 Flutter & Dart 中使用組合創建模塊化應用程式。 什麼是組合? 在dictionary.com 中 composition 的定義為:將部分或者元素組合成一個整體的行為。簡單說,組合就像堆樂高積木,我們可以將積 ...
本文翻譯自: Composition in Flutter & Dart
在 Flutter & Dart 中使用組合創建模塊化應用程式。
什麼是組合?
在dictionary.com 中 composition 的定義為:將部分或者元素組合成一個整體的行為。簡單說,組合就像堆樂高積木,我們可以將積木組合成一個結構。
在 FP 中,我們定義了一個簡單的通用函數,該函數可以通過組合構成一個複雜的函數,一個函數的輸出是另外一個函數的輸入,依此類推。輸入從一個函數傳遞到另外一個函數最後返回結果。因此,組合可以認為是數據流動的管道。
組合的數字元號是 f.g。 f(g(x))它從裡向外執行。
- 首先 x 初始化。
- 將 x 作為參數傳遞給 g,g(x)被初始化。
- g(x)被計算並將結果傳遞給 f 函數,最後 f(g(x))被計算。
在 Dart 中,組合函數可以表示如下:
Compose 是個高階函數,它接收兩個函數並返回一個可接收輸入的函數。 組合的執行順序是從右到左,因此g
先執行,然後再執行f
。
如上圖創建了函數shout
,它由兩個較小的功能函數toUpper
和exclaim
組成。
第 4 行,組合這兩個函數創建shout
函數.
第 8 行使用了包Dartz
中提供的函數composeF
。
Flutter 中如何使用組合?
Flutter 框架是展示組合功能的最佳示例之一,我們組合控制項來進行UI設計。比如你想設置 padding,可以用Padding
來組合,你想設置一些裝飾,可以用DecoratedBox
來進行組合等等。
Flutter 大量使用了組合。控制項樹就是我們用組合處理 UI 的結果.控制項就像樂高積木,小的通用控制項可以被組合成複雜的控制項或者用戶界面。比如,Container
就包含了幾個控制項,如Padding
, DecoratedBox
, Align
, LimitedBox
等。
這裡偏重介紹組合在實踐中應用讓讀者更深刻理解組合概念,本質上來說Flutter中的控制項組合與函數式編程中的組合還是有點區別,兩則編程範式不一樣,Flutter 控制項間組合偏重於面向對象編程,對象是基本單元,控制項都是對象;而函數的組合偏重於函數式編程,無狀態函數是基本單元。
組合與管道
與 compose 類似,這裡介紹另外一個概念:管道。兩者區別在於組合執行順序是從右到左,而管道執行順序是從左至右。
這個區別尤為重要,不要忽視,它間接影響到代碼可讀性。中國人的閱讀習慣是從左到右的,如果你是阿拉伯人可以忽略我說的,哈哈!
在第 14 行,使用了 compose,它的執行順序是從右至左,函數 g 首先執行,結果傳遞給 f 。
在第 17 行,使用了管道,它的執行順序是從左至右,函數 f 先執行,結果傳遞給 g 。
如果使用 compose,輸入 10 先執行increment
增加到 11 然後乘以 2,因此執行結果是 22.
如果使用管道,輸入 10 先執行doubler
乘以 2 變成 20,然後執行increment
遞增到 21 並返回。
Example 示例
結合所學的概念,我們可以創建幾個函數,實現字元串的變換。
我們需要可以將上述用例相互轉換的函數。
就像樂高游戲一樣,首先需要樂高積木,在這個例子中我們需要具有一些基礎功能的函數。
之前定義的 Compose 函數只接收兩個函數作為參數,現在定義一個可以接收 n 個參數的函數。
我們創建瞭如上代碼,接下來可以用它來實現更有意思的函數,這些函數將被使用,通過Github 倉庫查找更多信息。
Snake case to Pascal case
接下來將從 Snake case 轉換成 camel,pascal 和 kebab cases。
const _pascalCase = 'LoremIpsumDolorSitAmet';
const _snakeCase = 'lorem_ipsum_dolor_sit_amet';
在第 5 行中,定義了_snakeToPascal
函數,它接收一個參數並返回結果。_snakeToPascal
由三個小函數組合而成:splitWithUnderscore
, capitalizeWords
和 joinWithoutSpace
。將“lorem_ipsum_dolor_sit_amet”作為參數傳入函數中,compose 是從右至左的執行順序。因此:
-
首先輸入字元串先傳給
splitWithUnderscore
,該函數將輸入拆分成 [“lorem”, “ipsum”, “dolor”, “sit”, “amet”]。 -
splitWithUnderscore
的返回值是一個數組,它將被傳遞給第二個函數,即capitalizeWords
將每個元素的首字母轉換成大寫並返回列表 [“Lorem”, “Ipsum”, “Dolor”, “Sit”, “Amet”]。 -
capitalizeWords
的返回結果將被傳遞給joinWithoutSpace
,該函數將元素連接在一起並返回結果 “LoremIpsumDolorSitAmet”
還記得我們之前講的麽? 我們通過組合為數據定義一個管道,像上面這樣。數據流通過這些管道並返回結果,花些時間來構建一些基礎功能函數,組合他們生成更有意義的函數就變得很容易了。
Snake case to Camel case
const _snakeCase = 'lorem_ipsum_dolor_sit_amet';
const _camelCase = 'loremIpsumDolorSitAmet';
第 15 行_snakeToCamel
非常簡單,第一個與最後一個函數都是與上面轉換都是相同的:splitWithUnderscore
和 joinWithoutSpace
,將中間函數從capitalizeWords
修改為 capitalizeTail
,我們的功能就實現了。原因是 camelCase 的情況下不需要將第一個單詞大寫。capitalizeTail
與capitalizeWords
類似,但是它忽略了第一個單詞處理,匹配了我們的用例。
Snake case to Kebab case
Snake case 轉換成 kebab case 更簡單.只需要組合兩個函數 (splitWithUnderscore
& joinWithHyphen
),就可以完成任務。
Camel case to other cases
Kebab case to other cases
Pascal case to other cases
想法
我喜歡將組合視為一種分治技術。組合的主要優點是得到高復用和可定製功能。
文中源碼地址 GitHub
太棒了!鼓勵自己堅持到底。我希望我為你投入的時間增加了一些價值。
如果覺得文章對你有幫助,點贊、收藏、關註、評論,一鍵四連支持,你的支持就是我創作最大的動力。
❤️ 本文原創聽蟬 公眾號:碼里特別有禪 歡迎關註原創技術文章第一時間推送 ❤️