Genéricos: class abstracta y tipo de niño

Tengo una class abstracta llamada Presentador:

abstract class Presenter<V> { fun bind(view: V) { ... } ... } 

Y tengo implementaciones de estos presentadores:

 class FolderChooserPresenter : Presenter<FolderChooserView>() { ... } 

Y ver las classs que llaman al método bind en un punto específico:

 class FolderChooserActivity : BaseView(), FolderChooserView { @Inject lateinit var presenter: FolderChooserPresenter // method of baseview override fun onStart() { super.onStart() presenter.bind(this) } } 

Lo que me gustaría crear es tener una class base para classs como FolderChooserActivity que llama automáticamente al método bind.
Se siente estúpido repetir estas llamadas una y otra vez en todas las implementaciones.

Mi enfoque es tener una class abstracta que amplíe la BaseView que llama al método bind. Pero obviamente eso no funciona, ya que la class bind requiere la implementación y no la class abstracta.

Puede agregar dos parameters generics a su class BaseView y convertir this a V :

 open class Presenter<V> { fun bind(v: V) {} } open class BaseView<P, V> where P : Presenter<V> { lateinit var presenter: P fun onStart() { p.bind(this as V) } } 

Lo usarías así

 class FolderPresenter : Presenter<FolderChooserView>() { } class FolderChooserView : BaseView<FolderPresenter, FolderChooserView>() 

Lamentablemente, no obtendrá ninguna ayuda de su comstackdor si mezcla los parameters, debido al lanzamiento no verificado:

 class SomeOtherView : BaseView<SomeOtherPresenter, FolderChooserView>() 

La respuesta de @nhaarman está cerca, pero deja abierto el agujero si la class que se enlaza no es realmente el tipo de vista.

Este elenco no es tan malo, no hay muchas respuestas buenas para esto, si es que hay alguno. Siempre puede agregar una afirmación que dé un post de error realmente directo y dado que esto ocurre inmediatamente cuando se crea una actividad, verá el error muy temprano en la testing.

No creo que pueda get fácilmente una mejor respuesta sin crear algo que maneje todas las partes de la relación como una sola. Creo que su respuesta tiene un riesgo mínimo.

Comprobación del time de compilation para evitar el error de time de ejecución

Podría escribir una function que pueda verificar la pieza faltante en time de compilation y las personas podrían usarla como una afirmación en time de compilation.

 // a function that is used when people want to check validity at compile time, // it does nothing but cause compiler error if wrong heirarchy fun <A: V, P: Presenter<V>, V : View> checkValid() { // empty on purpose, used for compile time check } // successful: checkValid<FolderChooserActivity, FolderPresenter, FolderChooserView>() // error below: "Kotlin: Type argument is not within its bounds: should be subtype of 'test.so.FolderChooserView'" checkValid<TryingToFoolItActivity, FolderPresenter, FolderChooserView>() // this is blocked because SomeOtherActivity has its own compiler error so SomeOtherActivity type is not fully known checkValid<SomeOtherActivity, FolderPresenter, FolderChooserView>() 

Usar una function para crear la class, con comprobación del time de compilation para evitar el error de time de ejecución

También puede requerir que se use una function para build la *Activity class de *Activity . Pero si no puede hacer cumplir a las personas asegurándose de que tengan la class base de vista correcta, no puede exigir el uso de esta function. Aquí está de todos modos, solo para dar más ideas a este problema.

 inline fun <reified A: V, P: Presenter<V>, V : View> makeActivity(): A { return A::class.java.newInstance() } // successful: val good1 = makeActivity<FolderChooserActivity, FolderPresenter, FolderChooserView>() // error below: "Kotlin: Type argument is not within its bounds: should be subtype of 'test.so.FolderChooserView'" val bad1 = makeActivity<TryingToFoolItActivity, FolderPresenter, FolderChooserView>() 

Código completo:

Pongo el código completo aquí para poder explorar esto más y tratar de get una respuesta completa alternativa. Esto es realmente solo una variación de la respuesta de @nhaarman.

 // sample classes class FolderPresenter : Presenter<FolderChooserView>() { } class BadPresenter : Presenter<RandomView>() { } // successful declaration class FolderChooserActivity : BaseActivity<FolderPresenter, FolderChooserView>(), FolderChooserView { } // Error: "Kotlin: Type argument is not within its bounds: should be subtype of 'test.so.Presenter<test.renlearn.solrpref.FolderChooserView>'" class SomeOtherActivity : BaseActivity<BadPresenter, FolderChooserView>(), FolderChooserView {} // Runtime error, we are not a FolderChooserView class TryingToFoolItActivity : BaseActivity<FolderPresenter, FolderChooserView>() {} // now the version using a function to construct the activity, where // this function adds the missing step of compiler time validation. inline fun <reified A: V, P: Presenter<V>, V : View> makeActivity(): A { return A::class.java.newInstance() } // or a function that is used when people want to check validity at compile time, // it does nothing but cause compiler error if wrong heirarchy fun <A: V, P: Presenter<V>, V : View> checkValid() { // empty on purpose, used for compile time check } public fun foo() { // successful: val good1 = makeActivity<FolderChooserActivity, FolderPresenter, FolderChooserView>() // error below: "Kotlin: Type argument is not within its bounds: should be subtype of 'test.so.FolderChooserView'" val bad1 = makeActivity<TryingToFoolItActivity, FolderPresenter, FolderChooserView>() // this is blocked because SomeOtherActivity has its own compiler error so SomeOtherActivity type is not fully known val bad2 = makeActivity<SomeOtherActivity, FolderPresenter, FolderChooserView>() // successful: checkValid<FolderChooserActivity, FolderPresenter, FolderChooserView>() // error below: "Kotlin: Type argument is not within its bounds: should be subtype of 'test.so.FolderChooserView'" checkValid<TryingToFoolItActivity, FolderPresenter, FolderChooserView>() // this is blocked because SomeOtherActivity has its own compiler error so SomeOtherActivity type is not fully known checkValid<SomeOtherActivity, FolderPresenter, FolderChooserView>() } 
  • Kotlin coroutines unit testing usando mockito
  • ¿Hay alguna manera de cambiar mi método a la stream Observable que será una cadena de modificadores?
  • Reproducción solo del audio 1, no 2, 3 y 4
  • Necesito una manera de cambiar de forma dinámica y progama el background de un ImageView en una vista de reciclador
  • BeanDefinitionParsingException cuando se intenta usar JPA con Kotlin y Spring boot
  • Proporcionar una instancia genérica en Kotlin & Guice
  • Kotlin: Alcance interno: este
  • Propiedad de superclass no inicializada en class Derivada
  • Spring Data Elasticsearch con Script Field con Kotlin Data Class da como resultado un problema de serialization de Jackson
  • No se puede acceder a BaseColumns proporciona la propiedad _ID en Kotlin
  • Devoluciones de llamada de Android y reutilización de código