🔍 What is Tight Coupling and Loose Coupling? (Android Developer Explanation)
✅ Tight Coupling
Two classes/components are tightly coupled when they depend on each other directly.
If one changes, the other must also change.
It reduces flexibility and reusability.
📌 Example (Bad Practice – Tight Coupling)
class UserRepository {
fun getUser() = "Android Developer"
}
class UserViewModel {
private val repository = UserRepository() // Direct object creation → TIGHT COUPLING
fun printUser() {
println(repository.getUser())
}
}
🔴 Problems:
-
UserViewModelcannot work withoutUserRepository -
Hard to unit test (cannot inject mock repo)
-
If repository changes, viewmodel breaks
-
Not reusable
✅ Loose Coupling
Two classes are loosely coupled when they depend on abstractions (interfaces) instead of concrete classes.
You can replace dependency without modifying main logic → more flexible.
📌 Example (Good Practice – Loose Coupling with DI)
interface UserRepository {
fun getUser(): String
}
class UserRepositoryImpl : UserRepository {
override fun getUser() = "Android Developer"
}
class UserViewModel(private val repository: UserRepository) {
fun printUser() {
println(repository.getUser())
}
}
✅ Benefits:
-
You inject dependency, not create it
-
Easier unit testing (can pass fake/mock repo)
-
Supports dependency injection (Hilt, Koin, Dagger)
-
Better for Clean Architecture
Unit Test Example:
class FakeRepo : UserRepository {
override fun getUser() = "Test User"
}
val viewModel = UserViewModel(FakeRepo())
🔁 Comparison Table
| Feature | Tight Coupling | Loose Coupling |
|---|---|---|
| Flexibility | ❌ Low | ✅ High |
| Testability | ❌ Hard | ✅ Easy |
| Uses interface? | ❌ No | ✅ Yes |
| Dependency created inside class? | ✅ Yes | ❌ No (Injected) |
| Works well with DI (Hilt/Koin)? | ❌ No | ✅ Yes |
🏗 Real Android Example of Loose Coupling (Hilt)
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
fun provideUserRepo(): UserRepository = UserRepositoryImpl()
}
@HiltViewModel
class UserViewModel @Inject constructor(
private val repository: UserRepository
) : ViewModel() {
fun getUserName() = repository.getUser()
}
✅ ViewModel doesn’t know which implementation is injected
✅ Can switch to MockUserRepo() easily for testing
✅ Architecture-friendly
💡 Simple Definition for Interview
Tight coupling = classes depend directly on each other
Loose coupling = classes communicate through interfaces or injected dependencies
Comments
Post a Comment