当前位置:   article > 正文

Kotlin泛型之 循环引用泛型(A的泛型是B的子类,B的泛型是A的子类)

Kotlin泛型之 循环引用泛型(A的泛型是B的子类,B的泛型是A的子类)

IDE(编辑器)报错

循环引用泛型是我起的名字,不知道官方的名字是什么。这个问题是我在定义Android 的MVP时提出来的。具体是什么样的呢?我们看一下我的基础的MVP定义:

interface IPresenter<V> {  
	fun getView(): V  
}

interface IView<P> {  
	fun getPresenter(): P  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这里我定义了一个View和Presenter的接口,但是实际上这两个东西现在没什么关联。

这时,我想提供一个Presenter与View的基类,在基类中实现某些通用功能,并且增加这样的约束:Presenter中拿到的V必须是View的子类,View中拿到的P必须是Presenter的子类,那我们知道,可以通过kotlin,指定上界的方式。

我们修改上边的代码:改成下边这样:

interface IPresenter<V: IView> {  
	fun getView(): V  
}

interface IView<P: IPresenter> {  
	fun getPresenter(): P  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

同时我们也很容易发现,编译器报错了:

请添加图片描述

IDE提示这个错误:One type argument expected for interface IPresenter<V>,意思是:IPresenter必须指定一个泛型类型才可以。在Kotlin中,这样的写法是直接保存的,在Java中,这种写法只是警告,所以Java中使用这种写法,“没问题”(没有IDE报错问题)。

Java 中如何实现这个定义

我们来看一下Java

interface IPresenter<V extends IView> {  
	V getView();  
}  
  
interface IView<P extends IPresenter> {  
	P getPresenter();  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

接着我们看IDE的提示:

请添加图片描述

出现了警告,但是不报错了,我们看一下提示是什么:
Raw use of parameterized class 'IPresenter' 意思是其实和Kotlin提示的差不多,希望你指定一个泛型类型,而不是直接使用这个类。

在Java中,为了解决这个提示,可以使用?

interface IPresenter<V extends IView<?>> {  
	V getView();  
}  
  
interface IView<P extends IPresenter<?>> {  
	P getPresenter();  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

当我们在后边的泛型中加入来规定一下泛型,编译器就不会提示错误和警告。

在Kotlin中如何实现类似的接口定义?

我们尝试在Kotlin的代码中实现增加上界的方式: 我们知道kotlin 的通配符 *对应着java中的?,那我们模仿一下Java的方式不就行了吗?

interface IView<P: IPresenter<*>> {  
	fun getPresenter(): P  
}  
  
interface IPresenter<V: IView<*>> {  
	fun getView(): V  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

结果发现又报错了:

This type parameter violates the Finite Bound Restriction
  • 1

请添加图片描述

然后我又尝试了很多方式都不行。

解决方案

1、利用Kotlin与Java混合开发

既然Java中是可以定义的,那么可以通过定义一个Java类型的接口不就行了。确实可以,但是当这个定义不是接口,而是抽象类时,你需要再Java代码中写一堆方法实现、属性定义,这时你就无法体验到Kotlin代码的优势了。

定义用Java,实现用Kotlin。

2、增加Self泛型

在StackOverFlow 找到了一个解决方案,就是增加一个泛型,

interface IView<Self: IView<Self, P>, P: IPresenter<P, Self>> {  
	fun getPresenter(): P  
}  
  
interface IPresenter<Self: IPresenter<Self,V>, V: IView<V, Self>> {  
	fun getView(): V  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

我们通过增加一个泛型,并传递自己的方式,实现了循环引用泛型。

但是这样的代码,看起来定义变长了

当然我们为了看起来更清晰,也可以改成kotlin的另一种写法:

interface IView<Self, P> where Self: IView<Self, P>, P: IPresenter<P, Self>{  
	fun getPresenter(): P  
}  
  
interface IPresenter<Self, V> where Self: IPresenter<Self,V>, V: IView<V, Self>{  
	fun getView(): V  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

虽然变长了,但是定义看起来清晰了,缺点就是,增加多了一个泛型。

也可以把Self放在后边

interface IView<P, Self> where P: IPresenter<Self, P>, Self: IView<P, Self> {  
	fun getPresenter(): P  
}  
  
interface IPresenter<V, Self> where Self: IPresenter<V, Self>, V: IView<Self, V>{  
	fun getView(): V  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在使用时,我们只需要把Self指定为当前类即可。

class LoginView() : IView<LoginPresenter, LoginView> {  
	override fun getPresenter(): LoginPresenter {  
		TODO("Not yet implemented")  
	}  
}  
  
class LoginPresenter() : IPresenter<LoginView, LoginPresenter> {  
	override fun getView(): LoginView {  
		TODO("Not yet implemented")  
	}  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

完整案例MVP

通常我们不会在接口的位置直接定义循环引用,更多的时候是在实现某一个方案时,发现有通用的功能,想把通用功能统一抽离在父类里边。

案例:登录功能,我现在有一个登录的功能,为了简单,此处只增加两种方式:手机号码&密码登录。手机号码&验证码登录。

首先看这个功能的通用逻辑部分:
1、手机号码验证。
2、登录成功之后的用户数据获取。

各自独立的部分:
密码登录:检查密码位数,用密码登录。
验证码登录:发送验证码,检查验证码,用验证码登录。

  
interface IView<P> {  
	fun getPresenter(): P?  
}  
  
interface IPresenter<V> {  
	fun getView(): V?  
}  
  
abstract class BaseView<P : BasePresenter<*>>() : IView<P> {  
  
	private var myPresenter: P? = null  
	  
	override fun getPresenter(): P? {  
		if (myPresenter == null) {  
			myPresenter = createPresenter()  
			myPresenter?.setView(this)  
		}  
		return myPresenter  
	}  
	  
	fun showLoadingView() {  
		// 具体的展示加载中动画的实现  
	}  
	  
	fun hideLoadingView() {  
		// 具体的去除加载中动画的实现  
	}  
	  
	fun destroyView() {  
		hideLoadingView()  
		// 其他页面销毁时操作  
	}  
	  
	abstract fun createPresenter(): P?  
}  
  
  
abstract class BasePresenter<V> : IPresenter<V> {  
	protected var myView: V? = null  
	  
	override fun getView(): V? {  
		return myView  
	}  
	  
	fun setView(view: Any?) {  
		this.myView = view as V?  
	}  
	  
  
}  
  
  
abstract class BaseLoginView<Presenter, Self> :  
	BaseView<Presenter>() where Self : BaseLoginView<Presenter, Self>, Presenter : BaseLoginPresenter<Self, Presenter> {  
  
}  
  
abstract class BaseLoginPresenter<View, Self> :  
	BasePresenter<View>() where View : BaseLoginView<Self, View>, Self : BaseLoginPresenter<View, Self> {  
  
	fun checkPhone(phone: String): Boolean {  
		// 检查手机号具体实现  
		return true  
	}  
  
	fun onObtainTokenSuccess(token: String) {  
	// 登录成功具体操作  
	}  
}  
  
class LoginCodeView : BaseLoginView<LoginCodePresenter, LoginCodeView>() {  
	override fun createPresenter(): LoginCodePresenter {  
		return LoginCodePresenter()  
	}  
  
}  
  
class LoginCodePresenter : BaseLoginPresenter<LoginCodeView, LoginCodePresenter>() {  
	fun checkCode(): Boolean {  
		// 检查Code 的具体代码  
		return true  
	}  
}  
  
  
class LoginPasswordView : BaseLoginView<LoginPasswordPresenter, LoginPasswordView>() {  
	override fun createPresenter(): LoginPasswordPresenter {  
	return LoginPasswordPresenter()  
	}  
	  
}  
  
class LoginPasswordPresenter : BaseLoginPresenter<LoginPasswordView, LoginPasswordPresenter>() {  
	fun checkCode(): Boolean {  
		// 检查Code 的具体代码  
		return true  
	}  
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

参考链接

https://stackoverflow.com/questions/46682455/how-to-solve-violation-of-finite-bound-restriction-in-kotlin

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/538064
推荐阅读
相关标签
  

闽ICP备14008679号