Kotlin Academy · Pelajaran

Berkongsi Lapisan Repository dan Use Case

Pindahkan logik perniagaan dan capaian data ke commonMain untuk penggunaan semula maksimum.

Pelajaran 3 daripada 413 langkah

Berkongsi Lapisan Repository dan Use Case ialah pelajaran Kotlin Academy percuma di CoddyKit. Ini ialah pelajaran 3 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Kotlin Academy, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Kotlin Academy merangkumi sejumlah 4 pelajaran.

Matlamat Seni Bina

Dalam KMP, matlamatnya ialah meletakkan sebanyak mungkin logik dalam commonMain: model domain, antara muka repositori, kes penggunaan dan ViewModels. Hanya I/O platform kekal dalam set sumber platform.

// Target architecture:
// commonMain:
//   domain/    - data classes, interfaces
//   data/      - repository implementations using shared clients
//   usecase/   - business logic, composing repositories
// androidMain / iosMain:
//   DI wiring, platform drivers (DB, network)

Lapisan Domain dalam commonMain

Takrifkan entiti domain dan antara muka repositori dalam commonMain. Tiada import platform.

// commonMain/domain/User.kt
data class User(val id: String, val name: String, val email: String)

// commonMain/domain/UserRepository.kt
interface UserRepository {
    suspend fun getUser(id: String): User?
    suspend fun getAllUsers(): List<User>
    suspend fun saveUser(user: User)
}

Pelaksanaan Repositori Dikongsi dengan Ktor

Laksanakan repositori dalam commonMain menggunakan klien Ktor (multiplatform). Enjin HTTP sebenar disediakan bagi setiap platform.

// commonMain/data/RemoteUserRepository.kt
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.request.*
class RemoteUserRepository(private val client: HttpClient) : UserRepository {
    override suspend fun getUser(id: String): User? =
        client.get("https://api.example.com/users/$id").body()
    override suspend fun getAllUsers(): List<User> =
        client.get("https://api.example.com/users").body()
    override suspend fun saveUser(user: User) {
        client.post("https://api.example.com/users") { setBody(user) }
    }
}

Lapisan Kes Penggunaan

Kes penggunaan (interaktor) menyelaraskan repositori dan mengandungi logik perniagaan. Kes ini ialah Kotlin tulen tanpa kebergantungan platform.

// commonMain/usecase/GetUserUseCase.kt
class GetUserUseCase(private val repo: UserRepository) {
    suspend operator fun invoke(id: String): Result<User> =
        runCatching { repo.getUser(id) ?: error("User not found: $id") }
}

// commonMain/usecase/SaveUserUseCase.kt
class SaveUserUseCase(private val repo: UserRepository) {
    suspend operator fun invoke(user: User): Result<Unit> =
        runCatching { repo.saveUser(user) }
}

ViewModel Dikongsi

ViewModels boleh berada dalam commonMain menggunakan kotlinx-coroutines dan StateFlow. Android menggunakannya secara langsung; iOS membalutnya dalam SwiftUI.

// commonMain/viewmodel/UserViewModel.kt
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
class UserViewModel(private val getUser: GetUserUseCase) {
    private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
    private val _user = MutableStateFlow<User?>(null)
    val user = _user.asStateFlow()
    fun load(id: String) {
        scope.launch { _user.value = getUser(id).getOrNull() }
    }
    fun clear() = scope.cancel()
}

Konfigurasi Ktor HttpClient

Cipta Ktor HttpClient dalam commonMain dengan konfigurasi dikongsi. Enjin (OkHttp / Darwin) disuntik atau dicipta bagi setiap platform.

// commonMain/network/HttpClientFactory.kt
import io.ktor.client.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.serialization.kotlinx.json.*
fun createHttpClient(engine: io.ktor.client.engine.HttpClientEngine? = null) =
    HttpClient(engine ?: io.ktor.client.engine.cio.CIO) {
        install(ContentNegotiation) { json() }
    }

SQLDelight untuk Ketekalan Dikongsi

SQLDelight menjana Query Kotlin yang selamat dari segi jenis untuk semua platform daripada fail .sq dalam commonMain. Pemacu pangkalan data sebenar adalah khusus platform.

// commonMain/db/UserQueries.sq:
// CREATE TABLE User (id TEXT NOT NULL PRIMARY KEY, name TEXT NOT NULL);
// selectAll:
// SELECT * FROM User;

// Usage in commonMain:
// val db = UserDatabase(driver)
// val users = db.userQueries.selectAll().executeAsList()

Pendawaian DI Platform

Sambungkan semuanya dalam modul DI khusus platform. Antara mukanya dikongsi; hanya argumen pembina yang berbeza.

// androidMain:
val androidModule = module {
    single { AndroidSqliteDriver(UserDatabase.Schema, androidContext(), "users.db") }
    single { UserDatabase(get()) }
    single<UserRepository> { RemoteUserRepository(get()) }
    single { GetUserUseCase(get()) }
    viewModel { UserViewModel(get()) }
}

// iosMain:
// Same pattern with NativeSqliteDriver

Menguji Kes Penggunaan dalam commonTest

Kes penggunaan tiada kebergantungan platform, jadi kes ini mudah diuji sebagai ujian unit dalam commonTest menggunakan repositori palsu.

// commonTest/usecase/GetUserUseCaseTest.kt
import kotlin.test.Test
import kotlin.test.assertEquals
class FakeUserRepo : UserRepository {
    override suspend fun getUser(id: String) = if (id == "1") User("1", "Alice", "a@b.com") else null
    override suspend fun getAllUsers() = emptyList<User>()
    override suspend fun saveUser(user: User) {}
}
class GetUserUseCaseTest {
    private val useCase = GetUserUseCase(FakeUserRepo())
    @Test
    fun testGetExistingUser() = kotlinx.coroutines.runBlocking {
        val result = useCase("1")
        assertEquals("Alice", result.getOrNull()?.name)
    }
}

Pengendalian Ralat dalam Kes Penggunaan

Gunakan pulangan Result atau kelas tertutup daripada kes penggunaan untuk menyebarkan ralat tanpa pengecualian merentasi sempadan dikongsi/platform.

// commonMain:
sealed class UserResult {
    data class Success(val user: User) : UserResult()
    data class NotFound(val id: String) : UserResult()
    data class Error(val cause: Throwable) : UserResult()
}
class SafeGetUser(private val repo: UserRepository) {
    suspend operator fun invoke(id: String): UserResult = try {
        val user = repo.getUser(id)
        if (user != null) UserResult.Success(user) else UserResult.NotFound(id)
    } catch (e: Exception) { UserResult.Error(e) }
}

Perkongsian tanpa Mengorbankan Idiom Platform

Kongsi logik, bukan UI. Android menggunakan Compose; iOS menggunakan SwiftUI. Kedua-duanya memerhati keadaan ViewModel dikongsi yang sama melalui pengikatan khusus platform.

// Android (Compose):
// val user by viewModel.user.collectAsState()

// iOS (SwiftUI):
// @State var user = viewModel.user.value
// viewModel.load(id: "1")

// Shared ViewModel:
// _user.value = ... (commonMain)
fun main() { println("Share logic; use platform UI frameworks") }

Semakan Pantas

Lapisan manakah yang TIDAK sepatutnya mempunyai import khusus platform dalam projek KMP yang tersusun dengan baik?

Imbas Kembali

Letakkan model domain, antara muka repositori, kes penggunaan dan ViewModels dikongsi dalam commonMain. Gunakan Ktor (rangkaian) dan SQLDelight (pangkalan data) dengan enjin platform yang disuntik pada lapisan DI. Uji logik perniagaan dalam commonTest menggunakan repositori palsu.

Percuma untuk bermula

Pelajari Kotlin dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
51
Pelajaran
203

Soalan Lazim

Adakah pelajaran “Berkongsi Lapisan Repository dan Use Case” percuma?

Ya — sebanyak 3 pelajaran dalam laluan pembelajaran Kotlin Academy, termasuk “Berkongsi Lapisan Repository dan Use Case”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus Kotlin Academy merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Berkongsi Lapisan Repository dan Use Case”?

Pindahkan logik perniagaan dan capaian data ke commonMain untuk penggunaan semula maksimum. Anda berlatih Kotlin Academy menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Kotlin Academy?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Kotlin Academy di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 3 daripada 4.

Berapa lamakah pelajaran “Berkongsi Lapisan Repository dan Use Case” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Kotlin Academy ini?

Ya. Setiap pelajaran Kotlin Academy menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Struktur Projek KMP: commonMain, androidMain, iosMain
  2. Mekanisme expect/actual untuk API Platform
  3. Berkongsi Lapisan Repository dan Use Case
  4. Suntikan Kebergantungan dalam KMP dengan Koin
← Kembali ke Kotlin Academy