目标是将通用对象(不同类型参数(的列表存储在列表中,并以类型安全且符合人体工程学的方式对其进行操作。
我目前的设计使用访客模式:
sealed interface Element {
fun visit(visitor: Visitor)
}
interface Visitor {
fun <T> accept(elementA: ElementA<T>)
}
data class ElementA<T>(
// example members, many more in the real code
val produce : () -> T,
val doSomething: (T) -> Unit
) : Element {
override fun visit(visitor: Visitor) = visitor.accept(this)
}
尽管如此,访问者写起来不是很方便,因为必须将Visitor
:子类化
fun exampleUse(elements: List<Element>) {
for (element in elements) {
element.visit(object : Visitor {
override fun <T> accept(elementA: ElementA<T>) {
// We don't care about the actual type T, just that it exists
elementA.doSomething(elementA.produce())
}
})
}
}
它不是很符合人体工程学,我希望用户只需要编写传统的短代码,比如CCD_ 2。
唯一的要求是:
- 元素应该可以存储在列表中(同构集合(
- 用法(例如:
a.doSomething(a.produce())
(应该与类分开,因为它们是在具有不同关注点的不同包中定义的
如果有办法避免访客的样板,那就更好了。
这似乎满足了您的要求(我假设Element
仅作为所有ElementA<Something>
的公共超类型存在(:
data class ElementA<T>(
// example members, many more in the real code
val produce : () -> T,
val doSomething: (T) -> Unit
)
// optional
typealias Element = ElementA<*>
// or fun exampleUse(elements: List<ElementA<*>>)
// if you don't create Element
fun exampleUse(elements: List<Element>) {
fun <T> use(elementA: ElementA<T>) {
// We don't care about the actual type T, just that it exists
elementA.doSomething(elementA.produce())
}
for (element in elements) {
use(element)
}
}
注意,本地函数也可以是扩展函数:
fun exampleUse(elements: List<Element>) {
fun <T> ElementA<T>.use() {
// We don't care about the actual type T, just that it exists
doSomething(produce())
}
for (element in elements) {
element.use()
}
}
我不确定这是否符合您的要求,但我在Kotlin中实现了一个类型安全的异构映射:https://github.com/broo2s/typedmap。它与您的示例有点不同,因为它不是列表,而是地图。你可以这样使用它:
val map = simpleTypedMap()
sess += User("alice")
val user = sess.get<User>()
每个密钥类型仍然可以存储多个项目,但由于这是一个映射,每个项目都必须是唯一可识别的,所以我不确定这是否适合你:
map[UserKey(1)] = User("alice")
map[UserKey(2)] = User("bob")
val alice = map[UserKey(1)]
val bob = map[UserKey(2)]