最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Android官方架構中UseCase

 更新時間:2023年05月08日 11:53:15   作者:fundroid  
這篇文章主要為大家介紹了Android?官方架構中的?UseCase?該怎么寫示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

1. UseCase 的用途

Android 最新的架構規(guī)范中,引入了 Domain Layer(譯為領域層or網域層),建議大家使用 UseCase 來封裝一些復雜的業(yè)務邏輯。

傳統(tǒng)的 MVVM 架構中,我們習慣用 ViewModel 來承載業(yè)務邏輯,隨著業(yè)務規(guī)模的擴大,ViewModel 變得越來越肥大,職責不清。

Clean Architecture 提出的關注點分離和單一職責(SRP)的設計原則被廣泛認可,因此 Android 在最新架構中引入了 Clean Architecture 中 UseCase 的概念。ViewModel 歸屬 UI Layer,更加聚焦 UiState 的管理,UI 無關的業(yè)務邏輯下沉 UseCase,UseCase 與 ViewModel 解耦后,也可以跨 ViewModel 提供公共邏輯。

Android 架構早期的示例代碼 todo-app 中曾經引入過 UseCase 的概念,最新架構中只不過是將 UseCase 的思想更明確了,最新的 UseCase 示例可以從官方的 NIA 中學習。

NIA: github.com/android/now…

2. UseCase 的特點

官方文檔認為 UseCase 應該具有以下幾個特點:

2.1 不持有狀態(tài)

可以定義自己的數(shù)據(jù)結構類型,但是不能持有狀態(tài)實例,像一個純函數(shù)一樣工作。甚至直接推薦大家將邏輯重寫到 invoke 方法中,像調用函數(shù)一樣調用實例。

下面是 NIA 中的一個示例:GetRecentSearchQueriesUseCase

2.2 單一職責

嚴格遵守單一職責,一個 UseCase 只做一件事情,甚至其命名就是一個具體行為。掃一眼 UseCase 的文件目錄大概就知道 App 的大概功能了。

下面 NIA 中所有 UseCases:

2.3 可有可無

官方文檔中將 UseCase 定義為可選的角色,按需定義。簡單的業(yè)務場景中允許 UI 直接訪問 Repository。如果我們將 UseCase 作為 UI 與 Data 隔離的角色,那么工程中會出現(xiàn)很多沒有太大價值的 UseCase ,可能就只有一行調用 Repoitory 的代碼。

3. 如何定義 UseCase

如上所述,官方文檔雖然對 UseCase 給出了一些基本定義,但是畢竟是一個新新生概念,很多人在真正去寫代碼的時候仍然會感覺不清晰,缺少有效指引。在究竟如何定義 UseCase 這個問題上,還有待大家更廣泛的討論,形成可參考的共識。本文也是帶著這個目的而生,算是拋磚引玉吧。

3.1 Optional or Mandatory?

首先,官方文檔認為 UseCase 是可選的,雖然其初衷是好的,大家都不希望出現(xiàn)太多 One-Liner 的 UseCase,但是作為一個架構規(guī)范切忌模棱兩可,這種“可有可無”的規(guī)則其結局往往就是“無”。

業(yè)務剛起步時由于比較簡單往往定義在 Repository 中,隨著業(yè)務規(guī)模的擴大,應該適當?shù)迷黾?UseCase 封裝一些復雜的業(yè)務邏輯,但是實際項目中此時的重構成本會讓開發(fā)者變得“懶惰”,UseCase 最終難產。

那放棄 UseCase 呢?這可能會造成 Repository 的職責不清和無限膨脹,而且 Repository 往往不止有一個方法, ViewModel 直接依賴 Repository 也違反了 SOLID 中的另一個重要原則 ISP ,ViewModel 會因為不相關的 Repository 改動導致重新編譯。

ISP(Interface Segregation Principle,接口隔離原則) 要求將接口分離成更小的和更具體的接口,以便調用方只需知道其需要使用的方法。這可以提高代碼的靈活性和可重用性,并減少代碼的依賴性和耦合性。

為了降低前期判斷成本和后續(xù)重構成本,如果我們有業(yè)務持續(xù)壯大的預期,那不妨考慮將 UseCase 作為強制選項。當然,最好這需要研究如何降低 UseCase 帶來的模板代碼。

3.2 Class or Object?

官方建議使用 Class 定義 UseCase,每次使用都實例化一個新對象,這會做成一些重復開銷,那么可否用 object 定義 UseCase 呢?

UseCase 理論上可以作為單例存在,但 Class 相對于 Object 有以下兩個優(yōu)勢:

  • UseCase 希望像純函數(shù)一樣工作,普通 Class 可以確保每次使用時都會創(chuàng)建一個新的實例,從而避免狀態(tài)共享和副作用等問題。
  • 普通類可以通過構造參數(shù)注入不同的 Repository,UseCase 更利于復用和單元測試

如果我們強烈希望 UseCase 有更長的生命周期,那借助 DI 框架,普通類也可以簡單的支持。例如 Dagger 中只要添加 @Singleton 注解即可

@Singleton
class GetRecentSearchQueriesUseCase @Inject constructor(
    private val recentSearchRepository: RecentSearchRepository,
) {
    operator fun invoke(limit: Int = 10): Flow<List<RecentSearchQuery>> =
        recentSearchRepository.getRecentSearchQueries(limit)
}

3.3 Class or Function?

既然我們想像函數(shù)一樣使用 UseCase ,那為什么不直接定義成 Function 呢?比如像下面這樣

fun GetRecentSearchQueriesUseCase : Flow<List<RecentSearchQuery>> 

這確實遵循了 FP 的原則,但又喪失了 OOP 封裝性的優(yōu)勢:

  • UseCase 往往需要依賴 Repository 對象,一個 UseCase Class 可以將 Repository 封裝為成員存儲。而一個 UseCase Function 則需要調用方通過參數(shù)傳入,使用成本高不說,如果 UseCase 依賴的 Repository 的類型或者數(shù)量發(fā)生變化了,調用方需要跟著修改
  • 函數(shù)起不到隔離 UI 和 Data 的作用,ViewModel 仍然需要直接依賴 Repository,為 UseCase 傳參
  • UseCase Class 可以定義一些 private 的方法,相對于 Function 更能勝任一些復雜邏輯的實現(xiàn)

可見,在 UseCase 的定義上 Function 沒法取代 Class。當然 Class 也帶來一些弊端:

  • 暴露多個方法,破壞 SRP 原則。所以官方推薦用 verb in present tense + noun/what (optional) + UseCase 動詞命名,也是想讓職責更清晰。
  • 攜帶可變狀態(tài),這是大家寫 OOP 的慣性思維
  • 樣板代碼多

3.4 Function interface ?

通過前面的分析我們知道:UseCase 的定義需要兼具 FP 和 OOP 的優(yōu)勢。這讓我想到了 Function(SAM) Interface 。Function Interface 是一個單方法的接口,可以低成本創(chuàng)建一個匿名類對象,確保對象只能有一個方法,同時具有一定封裝性,可以通過“閉包”依賴 Repository。此外,Kotlin 對 SAM 提供了簡化寫法,一定程度也減少了樣板代碼。

Functional (SAM) interfaces: kotlinlang.org/docs/fun-in…

改用 Function interface 定義 GetRecentSearchQueriesUseCase 的代碼如下:

fun interface GetRecentSearchQueriesUseCase : () -> Flow<List<RecentSearchQuery>>

用它創(chuàng)建 UseCase 實例的同時,實現(xiàn)函數(shù)中的邏輯

val recentSearchQueriesUseCase = GetRecentSearchQueriesUseCase {
    //...
}

我在函數(shù)實現(xiàn)中如何 Repository 呢?這要靠 DI 容器獲取。官方示例代碼中都使用 Hilt 來解耦 ViewModel 與 UseCase 的,ViewModel 不關心 UseCase 的創(chuàng)建細節(jié)。下面是 NIA 的代碼, GetRecentSearchQueriesUseCase 被自動注入到 SearchViewModel 中。

@HiltViewModel
class SearchViewModel @Inject constructor(
    recentSearchQueriesUseCase: GetRecentSearchQueriesUseCase // UseCase 注入 VM
    //...
) : ViewModel() { 
    //...
}

Function interface 的 GetRecentSearchQueriesUseCase 沒有構造函數(shù),需要通過 Dagger 的 @Module 安裝到 DI 容器中,provideGetRecentSearchQueriesUseCase 參數(shù)中的 RecentSearchRepository 可以從容器中自動獲取使用。

@Module
@InstallIn(ActivityComponent::class)
object UseCaseModule {
    @Provides
    fun provideGetRecentSearchQueriesUseCase(recentSearchRepository: RecentSearchRepository) =
        GetRecentSearchQueriesUseCase { limit ->
            recentSearchRepository.getRecentSearchQueries(limit)
        }
}

當時用 Koin 作為 DI 容器時也沒問題,代碼如下:

single<GetRecentSearchQueriesUseCase> {
    GetRecentSearchQueriesUseCase { limit ->
       recentSearchRepository.getRecentSearchQueries(limit) 
    }
}

4. 總結

UseCase 作為官方架構中的新概念,尚沒有完全深入人心,需要不斷探索合理的使用方式,本文給出一些基本思考:

  • 考慮到架構的擴展性,推薦在 ViewModel 與 Repository 之間強制引入 UseCase,即使眼下的業(yè)務邏輯并不復雜
  • UseCase 不持有可變狀態(tài)但依賴 Repository,需要兼具 FP 與 OOP 的特性,更適合用 Class 定義而非 Function
  • 在引入 UseCase 之前應該先引入 DI 框架,確保 ViewModel 與 UseCase 的耦合。
  • Function Interface 是 Class 之外的另一種定義 UseCase 的方式,有利于代碼更加函數(shù)式

以上就是詳解Android官方架構中UseCase的詳細內容,更多關于Android官方架構UseCase 的資料請關注腳本之家其它相關文章!

相關文章

最新評論

贺兰县| 济源市| 库伦旗| 建水县| 林芝县| 溆浦县| 富川| 兴安盟| 正安县| 彩票| 通辽市| 涡阳县| 安顺市| 宁明县| 古浪县| 隆昌县| 韶关市| 永川市| 双峰县| 邯郸市| 民丰县| 剑川县| 永定县| 侯马市| 措勤县| 邵武市| 固安县| 南岸区| 泽州县| 北辰区| 柘城县| 定西市| 柳江县| 于田县| 武功县| 正阳县| 漳浦县| 乌拉特后旗| 迁西县| 七台河市| 弥渡县|