Esta pregunta es sobre el diseño OOP (clase/interfaz).
Estoy desarrollando una biblioteca de Android, no una aplicación. La aplicación utilizará esta biblioteca. Esta biblioteca está desarrollada por el patrón Repository.
Un repositorio y 2 fuentes de datos (local, remota).
Debido a que la fuente de datos local usa "SharedPreference", necesita Contexto.
A continuación se muestra la interfaz de mi repositorio y sus implementos.
interface MyRepository { fun create(String data) fun get(key: String): String } class MyRepositoryImpl( private val localDataSource: LocalDataSource, private val remoteDataSource: RemoteDataSource ): MyRepository { fun create(String data) { localDataSource.create(data); remoteDataSource.create(data); } fun get(key: String): String { // temp code return localDataSource.get(key) } companion object { private var instance: MyRepository? = null fun getInstance(context: Context): MyRepository { if (instance == null) { val localDataSource: LocalDataSource = LocalDataSourceImpl.getInstance(context) val remoteDataSource: RemoteDataSource = RemoteDataSourceImpl.getInstance() instance = MyRepositoryImpl(localDataSource, remoteDataSource) } return instance!! } } }MyRepositoryImpl se implementa mediante el patrón Singleton. Porque debe usarse en cualquier parte de la aplicación. Entonces, los desarrolladores de aplicaciones deberían poder obtener la instancia de MyRepository como:
val myRepository = MyRepositoryImpl.getInstance(context) val data = myRepository.get("key")Pero se ve raro... "getInstance(context)". Creo que este no es un buen enfoque. ¿Hay algún diseño más inteligente, por favor?
En Kotlin, puede usar la palabra clave object para implementar el patrón singleton de una manera segura para subprocesos. No es necesario definir el método getInstance en su objeto complementario. Simplemente defina su clase MyRepository como objeto como se muestra a continuación. Al sobrecargar el operador de invocación, podrá pasar el contexto útil para inicializar sus instancias localDataSource y remoteDataSource.
object MyRepository { private lateinit var localDataSource: LocalDataSource private lateinit var remoteDataSource: RemoteDataSource operator fun invoke(context: Context): MyRepository { //... localDataSource = LocalDataSourceImpl.getInstance(context) remoteDataSource = RemoteDataSourceImpl.getInstance(context) return this } }Este código se compilará en el siguiente código Java (bloque de inicialización estático):
public final class MyRepository { public static final MyRepository INSTANCE; private SomeSingleton() { INSTANCE = (MyRepository) this; } static { new MyRepository(); } }De esta manera, podrá obtener una instancia de su clase MyRepository como una clase normal que no sea un objeto, simplemente haciendo lo siguiente:
val repo = MyRepository(this) // this is your context Se podrá acceder a cada método que defina dentro de la clase MyRepository como si fuera un método estático de Java, por lo que podrá llamarlo así:
MyRepository.myMethod()Más detalles aquí