Scala 强制实现trait以提供trait可以扩展的内部类
一个trait是否可能要求它的实现类实现一些内部类,然后可以扩展这些内部类?例如Scala 强制实现trait以提供trait可以扩展的内部类,scala,inheritance,Scala,Inheritance,一个trait是否可能要求它的实现类实现一些内部类,然后可以扩展这些内部类?例如 trait BaseTrait { // not actually an "abstract class", but a requirement that // subclasses provide a class named Foo with this constructor signature abstract class Foo(bar: Bar) def normalFoo(bar: Ba
trait BaseTrait {
// not actually an "abstract class", but a requirement that
// subclasses provide a class named Foo with this constructor signature
abstract class Foo(bar: Bar)
def normalFoo(bar: Bar): Foo = new Foo(bar)
// trait needs to be able to extend the Foo class implemented by the subclass.
// this seems to be the impossible part, as far as I can tell...
def fancyFoo(bar: Bar): Foo with SomeMixin = new Foo(bar) with SomeMixin {
def anExtraMethod() = println("I'm an extra!")
}
}
object ThingA extends BaseTrait {
class Foo(bar: Bar) {
def getThingAStuff() = println("I'm part of ThingA")
}
}
object ThingB extends BaseTrait {
class Foo(bar: Bar) {
def getThingBStuff() = println("I'm part of ThingB")
}
}
// calling `fancyFoo` on the concrete implementations should grant
// access to the specific methods in their respective `Foo` classes,
// as well as the "extra method" that the trait adds
val aFoo: ThingA.Foo with SomeMixin = ThingA.fancyFoo(bar)
aFoo.getThingAStuff()
aFoo.anExtraMethod()
val bFoo: ThingB.Foo with SomeMixin = ThingB.fancyFoo(bar)
bFoo.getThingBStuff()
bFoo.anExtraMethod()
我想要这样做的原因是我有大量的ThingX
类,它们目前都被迫实现自己的fancyFoo
(以及其他类似的方法,需要将Mixin添加到它们特定的Foo类中)。我想通过将fancyFoo
及其朋友转移到BaseTracit中来减少样板文件,但我无法想出比已经存在的内容更详细的内容
编辑: 我上面的概括可能模糊了整体意图,因此这里有一些背景: 我的实际用例围绕着对数据库模式和一些表连接逻辑进行建模。团队开始从Slick的“提升”语法转向原始sql,这个系统的出现有助于支持编写原始查询
Foo
=TableReference
。每个ThingX
对象表示一个特定的表,它们各自的引用类包含引用该表列的方法
SomeMixin
=TableJoin
,它应该添加连接逻辑(即如何从另一个表访问一个表)。ThingX
对象通常定义一个def direct
来直接引用表(即SQL查询中FROM
子句的开头)、一个创建内部联接的def FROM(someOtherRef)
,以及一个创建左联接的def optFrom(someOtherRef)
。这三种方法正是我试图抽象为BaseTrait
的方法
我相信我们确实需要能够提供一个普通的TableReference
,以及提供一个带有TableJoin的TableReference
,因为我们有一个用于组合所有连接逻辑的实用程序,我们希望禁止没有任何连接逻辑的引用被传递到其中。在整个代码库中,普通引用有几种用法
我希望能定义一些类似于
trait TableSupport {
type Reference <: TableReference
trait CanMatch[Ref] {
// corresponds to the `ON` part of a `JOIN` clause
def matchCondition(self: Reference, other: Ref): RawSQL
}
def defaultAlias: String
// All of the below would be implemented by the `TableSupport` trait
// in terms of the `Reference` constructor and mixing in TableJoin.
// But currently each table companion has to explicitly implement these.
def reference(alias: String = defaultAlias): Reference = ???
def direct(alias: String = defaultAlias): Reference with TableJoin = ???
def from[Ref: CanMatch](ref: Ref, alias: String = defaultAlias): Reference with TableJoin = ???
def optFrom[Ref: CanMatch](ref: Ref, alias: String = defaultAlias): Reference with TableJoin = ???
}
trait表支持{
类型引用我找到的解决方案是包装类,而不是扩展类,并且使用隐式unwrapper让我与事物交互,就像它们被扩展一样
SomeTableRef与TableJoin
变为TableJoin[SomeTableRef]
class TableJoin[T <: TableReference](val self: T, val joinStep: RawSQL)
object TableJoin {
import language.implicitConversions
implicit def unwrap[T <: TableReference](tj: TableJoin[T]): T = tj.self
}
使用这种方法,我能够实现我所希望的direct
、from
和optFrom
方法。像trait Base这样的方法怎么样{trait Foo;type Bar为什么需要所有这些类的普通版和高级版,为什么不让它们都高级化呢?这感觉像是一个XYproblem@Tim关于XY问题,你可能是对的。我更新了这个问题,以详细说明我的实际用例(因为从Foo和Bar的角度来概括它似乎没有什么帮助)“X”是指我希望共享几个非常相似的方法的实现,这些方法目前在30多个对象上重复。
class SomeTableRef(alias: String) extends TableReference {
def id = column("ID")
}
val joinedRef = new TableJoin(new SomeTableRef(defaultAlias), /* raw sql */)
joinedRef.id // compiles fine because of `unwrap`