我有一个名为presenter的抽象类:
abstract class Presenter<V> {
fun bind(view: V) {
...
}
...
}
我有这些演示者的实现:
class FolderChooserPresenter : Presenter<FolderChooserView>() {
...
}
查看在指定点调用bind方法的类:
class FolderChooserActivity : BaseView(), FolderChooserView {
@Inject lateinit var presenter: FolderChooserPresenter
// method of baseview
override fun onStart() {
super.onStart()
presenter.bind(this)
}
}
我想要的是为FolderChooserActivity
这样的类创建一个基类,它自动调用bind方法。
在所有实现中一遍又一遍地重复这些调用感觉很愚蠢。
我的方法是创建一个抽象类,扩展调用bind方法的BaseView
。但这显然不起作用,因为绑定类需要实现而不是抽象类。
答案 0 :(得分:0)
您可以向this
课程添加两个通用参数,并将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)
}
}
:
class FolderPresenter : Presenter<FolderChooserView>() {
}
class FolderChooserView : BaseView<FolderPresenter, FolderChooserView>()
你会像
一样使用它class SomeOtherView : BaseView<SomeOtherPresenter, FolderChooserView>()
不幸的是,如果混淆参数,由于未选中的强制转换,您无法从编译器获得任何帮助:
var shell = PowerShell.Create();
shell.Commands.AddScript("Import-Module ServiceFabric");
shell.Commands.AddScript("Connect-ServiceFabricCluster");
var result = shell.Invoke();
答案 1 :(得分:0)
来自@nhaarman的答案很接近,但如果绑定的类实际上不是视图的类型,则会打开漏洞。
这个演员并不是一件坏事,如果有的话,对此没有很多好的答案。您总是可以添加一个提供真正直接错误消息的断言,并且由于这些消息在创建活动时立即发生,您将在测试的早期就看到错误
我不认为你能够轻松地找到一个更好的答案,而不会创建管理关系的所有部分的东西。我认为他的答案风险很小。
编译时间检查以避免运行时错误
你可以编写一个函数,可以在编译时检查缺失的部分,人们可以像编译时声明一样使用它。
// 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>()
使用函数创建类,使用编译时检查以避免运行时错误
您还可以要求使用函数来构造*Activity
类。但是,如果您无法强制人员确保他们拥有正确的视图基类,则您无法强制使用此功能。无论如何,这只是为了解决这个问题。
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>()
完整代码:
我在这里填写完整的代码,以便我可以更多地探索这一点并尝试获得另一个完整的答案。这实际上只是@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>()
}