Android開發(fā)中的前五個(gè)代碼異味:Jetpack Compose UI和MVVM
代碼異味是指軟件代碼中潛在問題的指標(biāo),可能并不一定是錯(cuò)誤,但可能會(huì)導(dǎo)致問題,如增加維護(hù)復(fù)雜性、降低性能或降低可讀性。我們將探討Android開發(fā)中的前五個(gè)代碼異味,其中包括使用Jetpack Compose UI和Model-View-ViewModel(MVVM)架構(gòu)的示例。
1. 上帝對(duì)象或上帝類:
上帝對(duì)象或上帝類是指試圖做太多事情的單個(gè)類,違反了單一職責(zé)原則。在Android開發(fā)中,這可能會(huì)使代碼更難理解、維護(hù)和修改。
示例:
我們將以一個(gè)充當(dāng)“上帝對(duì)象”的ViewModel為例,然后使用存儲(chǔ)庫模式進(jìn)行重構(gòu)。
上帝對(duì)象ViewModel示例:
class GodObjectViewModel : ViewModel() {
private val apiService = ApiService()
private val database = AppDatabase.getInstance()
// LiveData to expose data to the UI
private val _data = MutableLiveData<List<DataItem>>()
val data: LiveData<List<DataItem>> = _data
init {
loadData()
}
private fun loadData() {
viewModelScope.launch {
// Fetch data from API
val apiData = apiService.getData()
// Save data to database
database.dataDao().insertAll(apiData)
// Load data from database
val dbData = database.dataDao().getAll()
// Transform data
val transformedData = transformData(dbData)
// Update LiveData
_data.value = transformedData
}
}
private fun transformData(input: List<DataItem>): List<DataItem> {
// Perform some transformations on the data
// ...
return transformedData
}
}
使用倉庫模式重構(gòu)后的 ViewModel:
class RefactoredViewModel(private val dataRepository: DataRepository) : ViewModel() {
// LiveData to expose data to the UI
private val _data = MutableLiveData<List<DataItem>>()
val data: LiveData<List<DataItem>> = _data
init {
loadData()
}
private fun loadData() {
viewModelScope.launch {
// Fetch data using the repository
val transformedData = dataRepository.fetchData()
// Update LiveData
_data.value = transformedData
}
}
}
為了改進(jìn)代碼,我們使用倉庫模式對(duì) ViewModel 進(jìn)行了重構(gòu)。我們創(chuàng)建了一個(gè)獨(dú)立的 DataRepository
類,它負(fù)責(zé)處理 API 調(diào)用、數(shù)據(jù)庫操作和數(shù)據(jù)轉(zhuǎn)換的職責(zé)。然后,重構(gòu)后的 ViewModel 被簡(jiǎn)化為僅專注于通過委托數(shù)據(jù)獲取任務(wù)到 DataRepository
來向 UI 公開數(shù)據(jù)。
2. 深層繼承層次結(jié)構(gòu):
過度使用繼承可能導(dǎo)致代碼復(fù)雜且難以維護(hù)。在適當(dāng)?shù)那闆r下,應(yīng)優(yōu)先考慮組合而非繼承。
示例:
使用 Kotlin 和 Jetpack Compose,展示了一個(gè)深層的繼承層次結(jié)構(gòu),然后使用組合對(duì)其進(jìn)行了重構(gòu)。
abstract class BaseComposable {
abstract fun DrawScope.draw()
}
class FirstLevelComposable : BaseComposable() {
override fun DrawScope.draw() {
// Implement some functionality
}
}
class SecondLevelComposable : FirstLevelComposable() {
override fun DrawScope.draw() {
super.draw()
// Add more functionality
}
}
class ThirdLevelComposable : SecondLevelComposable() {
override fun DrawScope.draw() {
super.draw()
// Add even more functionality
}
}
@Composable
fun DeepInheritanceHierarchyExample() {
val thirdLevelComposable = ThirdLevelComposable()
Canvas(modifier = Modifier.fillMaxSize()) {
thirdLevelComposable.draw()
}
}
使用組合進(jìn)行重構(gòu):
@Composable
fun BaseComposable() {
// Implement some functionality
}
@Composable
fun FirstLevelComposable() {
BaseComposable()
// Add more functionality
}
@Composable
fun SecondLevelComposable() {
FirstLevelComposable()
// Add even more functionality
}
@Composable
fun CompositionExample() {
Canvas(modifier = Modifier.fillMaxSize()) {
SecondLevelComposable()
}
}
在重構(gòu)的示例中,我們使用組合替換了深度繼承層次結(jié)構(gòu),使代碼更易于理解和維護(hù)。我們創(chuàng)建了小型可重用的 Composable 函數(shù),而不是從多個(gè)父類繼承,可以組合這些函數(shù)來實(shí)現(xiàn)所需的功能。這種方法更加靈活,并遵循 Jetpack Compose 的原則。
3. 硬編碼值或“魔法數(shù)字”:
硬編碼值可能會(huì)使代碼不夠靈活,難以維護(hù)。使用常量或資源文件存儲(chǔ)可能會(huì)發(fā)生更改的值。
示例:
在 Jetpack Compose 中,我們不使用像 colors.xml、dimens.xml 和 strings.xml 這樣的 XML 文件。相反,我們?cè)?Kotlin 文件中定義這些資源。以下是一個(gè)使用硬編碼值的示例,并對(duì)其進(jìn)行重構(gòu)以使用常量:
硬編碼代碼示例:
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
@Composable
fun HardcodedValuesExample() {
Text(
text = "Hello, World!",
color = Color(0xFF3F51B5),
modifier = Modifier.padding(16.dp)
)
}
使用常量進(jìn)行重構(gòu):
創(chuàng)建一個(gè)專門的文件,例如Theme.kt
:
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
object Constants {
val primaryColor = Color(0xFF3F51B5)
val defaultPadding = 16.dp
}
更新 HardcodedValuesExample
使用常量:
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import Constants.primaryColor
import Constants.defaultPadding
@Composable
fun RefactoredValuesExample() {
Text(
text = "Hello, World!",
color = primaryColor,
modifier = Modifier.padding(defaultPadding)
)
}
在重構(gòu)的示例中,我們使用在專門的文件中定義的常量來代替硬編碼的值。這使得代碼更易于維護(hù)和更新。對(duì)于文本字符串,您可以使用類似的方法,在單獨(dú)的文件中定義字符串常量,并在您的 Composables 中使用它們。
4. 長(zhǎng)方法或類:
長(zhǎng)方法或類難以理解和維護(hù)。將它們拆分成更小、更集中的功能單元。
示例:
使用 Kotlin 和 Jetpack Compose,我們有一個(gè) ViewModel 類,其中包含一個(gè)長(zhǎng)方法,處理數(shù)據(jù)轉(zhuǎn)換和業(yè)務(wù)邏輯。我們將通過將方法拆分為更小、更專注的函數(shù)來進(jìn)行重構(gòu)。
長(zhǎng)方法示例:
class LongMethodViewModel : ViewModel() {
// ...
private fun processData(data: List<DataItem>): List<ProcessedDataItem> {
// Step 1: Filter the data
val filteredData = data.filter { item ->
item.isActive && item.value > 10
}
// Step 2: Transform the data
val transformedData = filteredData.map { item ->
ProcessedDataItem(
id = item.id,
displayName = "${item.name} (${item.value})",
important = item.value > 50
)
}
// Step 3: Sort the data
val sortedData = transformedData.sortedByDescending { item ->
item.important
}
return sortedData
}
}
重構(gòu)成更小更專一的代碼:
class RefactoredViewModel : ViewModel() {
// ...
private fun processData(data: List<DataItem>): List<ProcessedDataItem> {
return data.filter(::filterData)
.map(::transformData)
.sortedByDescending(::sortData)
}
private fun filterData(item: DataItem): Boolean {
return item.isActive && item.value > 10
}
private fun transformData(item: DataItem): ProcessedDataItem {
return ProcessedDataItem(
id = item.id,
displayName = "${item.name} (${item.value})",
important = item.value > 50
)
}
private fun sortData(item: ProcessedDataItem): Boolean {
return item.important
}
}
在重構(gòu)的例子中,我們將長(zhǎng)的processData方法分解為更小、更專注的函數(shù):filterData、transformData和sortData。這使得代碼更易于理解、測(cè)試和維護(hù)。
5. 強(qiáng)耦合:
高度依賴彼此的類或組件可能會(huì)使修改或測(cè)試代碼變得困難。通過設(shè)計(jì)具有良好定義接口和最小依賴關(guān)系的組件來實(shí)現(xiàn)松耦合。
例子:
使用Kotlin和Jetpack Compose,ViewModel和Composable函數(shù)之間存在強(qiáng)耦合。我們將使用StateFlow重構(gòu)它以實(shí)現(xiàn)松耦合。
強(qiáng)耦合例子:
class TightCouplingViewModel : ViewModel() {
val data = mutableStateOf(listOf<DataItem>())
init {
loadData()
}
private fun loadData() {
// Load data...
data.value = loadedData
}
}
@Composable
fun TightCouplingExample(viewModel: TightCouplingViewModel) {
val data = viewModel.data.value
LazyColumn {
items(data) { item ->
// Display data item...
}
}
}
使用松散耦合進(jìn)行重構(gòu):
更新 ViewModel 以使用 StateFlow:
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
class LooseCouplingViewModel : ViewModel() {
private val _data = MutableStateFlow(listOf<DataItem>())
val data: StateFlow<List<DataItem>> = _data
init {
loadData()
}
private fun loadData() {
// Load data...
_data.value = loadedData
}
}
更新 Composable
函數(shù)以觀察來自 ViewModel
的數(shù)據(jù):
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@Composable
fun LooseCouplingExample(viewModel: LooseCouplingViewModel) {
val data by viewModel.data.collectAsState()
LazyColumn {
items(data) { item ->
// Display data item...
}
}
}
在重構(gòu)的示例中,我們通過使用StateFlow來觀察和響應(yīng)ViewModel中數(shù)據(jù)的變化,實(shí)現(xiàn)了ViewModel和Composable函數(shù)之間的松耦合。這種方法使得修改或測(cè)試代碼更容易,因?yàn)閂iewModel和UI組件不會(huì)直接引用彼此。
結(jié)論
總之,在Android開發(fā)中解決五大代碼壞味道有助于創(chuàng)建更清晰、更高效、更高質(zhì)量的代碼庫。通過遵循Jetpack Compose UI和MVVM架構(gòu)的最佳實(shí)踐,開發(fā)人員可以創(chuàng)建具有模塊化、可維護(hù)和可測(cè)試性的應(yīng)用程序。文章來源:http://www.zghlxwxcb.cn/news/detail-434018.html
- 通過將大型類分解為更小、更集中的功能單元,實(shí)現(xiàn)避免過多使用god對(duì)象,并實(shí)現(xiàn)存儲(chǔ)庫模式。
- 通過組合取代深層繼承層次結(jié)構(gòu),創(chuàng)建更小、可重用的可組合項(xiàng)或混合項(xiàng),以實(shí)現(xiàn)所需的功能。
- 通過將硬編碼的值或“神奇數(shù)字”替換為常量或資源文件,使代碼更具靈活性和可維護(hù)性。
- 通過將長(zhǎng)方法或類分解為更小、更集中的功能單元,使其更易于理解、測(cè)試和維護(hù)。
- 通過設(shè)計(jì)具有良好定義接口和最小依賴關(guān)系的組件、使用LiveData或StateFlow來觀察和響應(yīng)ViewModel中的數(shù)據(jù)變化,并避免ViewModel和UI組件之間的直接引用,實(shí)現(xiàn)松耦合。
通過解決這些代碼壞味道,您可以增強(qiáng)開發(fā)過程,改善可維護(hù)性,并創(chuàng)建提供優(yōu)秀用戶體驗(yàn)的Android應(yīng)用程序。
參考
https://medium.com/@fauzisho/top-5-code-smells-in-android-development-jetpack-compose-ui-and-mvvm-e3934ddbc14c文章來源地址http://www.zghlxwxcb.cn/news/detail-434018.html
到了這里,關(guān)于Android開發(fā)中的前五個(gè)代碼異味:Jetpack Compose UI和MVVM的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!