Suggestion on creating a module that only exposes a public API
from the CommonsWare Community archivesAt March 10, 2020, 3:46am, sagarsuri56 asked:
I am working on a multi-module android project. I have created a separate module that will have the database(room) implementation in it. I want to only expose an interface that avoids other modules to directly access the room specific APIs so that it will be easy to replace room with SQLDelight in the future. How should I approach this problem where I can limit access to just an interface and not any database specific APIs?
I found protection proxy design pattern can be of help here but still I would like your overview on it.
@mmurphy
At March 10, 2020, 11:26am, mmurphy replied:
That may not be possible. In the end, you will wind up using
-
private
in Java and Kotlin - package-private in Java
-
internal
in Kotlin
as much as you can, to limit what other modules can see. However, Room will have its own requirements. For example, I think entities and DAOs need to be public
. That will limit your ability to hide them from other modules.
At March 10, 2020, 12:04pm, sagarsuri56 replied:
I took the following approach:
- I created a separate database module.
- Made
DAO
,Entity
andDatabase
asinternal
. - Created a separate model class(data class) with the same properties as the Entity.
- Created an interface which has functions mapping to the
DAO
functions. - Created an implementation of the above interface which takes database instance as a constructor parameter.
interface UserLocalSource {
fun addUser(user: User)
fun getUser(firstName: String): User
fun deleteUser(user: User)
}
class UserLocalSourceImpl private constructor(private val database: Database) : UserLocalSource {
override fun addUser(user: User) {
database.insert(user.toUserEntity())
}
override fun getUser(firstName: String): User {
return database.find(firstName).toUser()
}
override fun deleteUser(user: User) {
database.delete(userEntity = user.toUserEntity())
}
companion object {
fun newInstance(): UserLocalSource {
return UserLocalSourceImpl(Database())
}
}
}
Now the app
module can only access UserLocalSource
.
At March 10, 2020, 12:40pm, mmurphy replied:
That’s certainly a fine plan, even if you were doing this all in one module. And I am glad to hear that Room is more internal
-friendly than I was expecting.
Just bear in mind that anything that is public
(which is the default visibility in Kotlin) will still be visible in the other module.
At March 10, 2020, 5:18pm, sagarsuri56 replied:
Yeah that’s right. I have just made sure that no DAO
or Entity
should be directly accessible instead it should be behind a public API.