我刚看完并喜欢Cake模式文章.但是,在我看来,使用依赖注入的一个关键原因是您可以改变XML文件或命令行参数使用的组件.
如何使用Cake模式处理DI的这个方面?我见过的例子都涉及静态混合特征.
我看到Scala中的特性与Java中的接口类似(但Java中的接口扩展了其他接口,它们不扩展类).我在SO上看到了一个关于特征使用的例子,其中特征扩展了一个类.
这样做的目的是什么?为什么traits可以扩展类?
在Scala中,我已经看到了这些结构
trait T extends S
Run Code Online (Sandbox Code Playgroud)
和
trait T { this: S =>
Run Code Online (Sandbox Code Playgroud)
用于实现类似的东西(即S
必须在创建实例之前定义抽象方法).他们之间有什么区别?你为什么要用另一个呢?
问题的作者
用抽象类型交换类型参数=>
在他的类定义的开头写了一个.例:
abstract class Thing { t =>
type A
type G <: Group { type A = t.A }
val group: G
}
Run Code Online (Sandbox Code Playgroud)
什么t =>
意思?
因为在Google&Co中很难找到,有人可以给我更多背景信息或提供链接,我可以在哪里找到有关这种语言结构的更多信息?
看起来可以在具有如下特征的类上更改方法的实现:
trait Abstract { self: Result =>
override def userRepr = "abstract"
}
abstract class Result {
def userRepr: String = "wtv"
}
case class ValDefResult(name: String) extends Result {
override def userRepr = name
}
val a = new ValDefResult("asd") with Abstract
a.userRepr
Run Code Online (Sandbox Code Playgroud)
现场代码可在此处获取:http://www.scalakata.com/52534e2fe4b0b1a1c4daa436
但是现在我想调用前面的或超级实现的函数,如下所示:
trait Abstract { self: Result =>
override def userRepr = "abstract" + self.userRepr
}
Run Code Online (Sandbox Code Playgroud)
要么
trait Abstract { self: Result =>
override def userRepr = "abstract" + super.userRepr
}
Run Code Online (Sandbox Code Playgroud)
但是,这些替代方案都没有编译.知道如何实现这一目标吗?
我有一个特性,它接受一个类型参数,我想说实现这个特征的对象也将符合这个类型参数(使用泛型,以便Java的兼容性)
以下代码:
trait HandleOwner[SELF <: HandleOwner[SELF]] {
self : SELF =>
// ...
def handle: Handle[SELF]
}
trait Common[SELF <: Common[SELF]] extends HandleOwner[SELF] {
// ...
}
Run Code Online (Sandbox Code Playgroud)
给我以下错误:
illegal inheritance; self-type test.Common[SELF] does not conform to
test.HandleOwner[SELF]'s selftype SELF
Run Code Online (Sandbox Code Playgroud)
如果我将Common更改为:
trait Common[SELF <: Common[SELF]] extends HandleOwner[SELF] {
self : SELF =>
// ...
}
Run Code Online (Sandbox Code Playgroud)
然后错误就消失了.
为什么我必须在每个非具体类型中重复相同的声明.如果我有一个基类,并说"extends Comparable",我不必在每个派生类型中重复"extends Comparable",只要具体类实现compareTo方法即可.我认为这应该是一回事.我只是说扩展HandleOwner的类型也将是一个SELF,编译器应该只接受它,并考虑它,同时不要求每个非具体子类型再次重复相同的事情.
我这样做是为了避免使用类强制转换,但我将从字面上扩展每个类,我不会看到我应该重复这个声明数百甚至数千次!
以下两个有什么区别?
1#
trait B extends A {
}
Run Code Online (Sandbox Code Playgroud)
2#
trait B { self: A =>
}
Run Code Online (Sandbox Code Playgroud)
哪里A
是抽象类.
>>编辑:
请解释以下Duck
具有可插拔飞行和嘎嘎行为的s 示例:
abstract class Duck {
def fly(): Unit
def quack(): Unit
def swim() {
println("Woodoowoodoowoodoo...")
}
}
trait FlyingWithWings extends Duck {
override def fly() {
println("Me can fliez! :D")
}
}
trait FlyingNoWay { self: Duck =>
def fly() {
println("Me cannot fliez! :(")
}
}
trait Quack extends Duck {
override def quack() {
println("Quack! …
Run Code Online (Sandbox Code Playgroud) 似乎Scala的显式类型自引用最常见的用法是" Cake模式 ",其中模块的依赖项声明如下:
class Foo { this: A with B with C =>
// ...
}
Run Code Online (Sandbox Code Playgroud)
通常,暂时忽略蛋糕模式A
,B
并且C
可以引用任何类型级别的东西,例如类型参数:
class Outer[A, B, C] {
class Inner { this: A with B with C =>
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
......或抽象类型的成员:
class Outer {
type A
type B
type C
class Inner { this: A with B with C =>
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
在这些情况中,我们都不能写abstract class Inner extends A with B with C …
所以我希望将一个通用特征作为一个类型参数,一个具有从特定基类继承的伴随对象的类,并引用伴随对象和类本身.所以,
abstract class BaseModel[T] {
def all: Seq[T]
}
case class Customer(email: String, password: String)
object Customer extends BaseModel[Customer]
// This trait is my issue
trait BaseCrud[T] {
def table[T](f: T => String): String = {
T.all.map(f _).mkString("")
}
}
object Controller with BaseCrud {
def foo = table(_.email)
}
Run Code Online (Sandbox Code Playgroud)
我有一些解决方案,这个特性更接近,但我把它提炼下来,这样你就可以看到我想要做的事情.
谢谢
UPDATE
所以我选择了Frank下面的解决方案,但我确实设法解决了我最初的难题.虽然,在这种情况下解决方案有点难看,但为了完整起见,我会将其包含在这里.
abstract class BaseModel[T] {
def all: Seq[T] = Seq()
}
case class Customer(email: String, password: String)
object Customer extends BaseModel[Customer]
trait BaseCrud[T, U <: BaseModel[T]] { …
Run Code Online (Sandbox Code Playgroud) 有这样的模型(简化):
case class User(id:Int,name:String)
case class Address(id:Int,name:String)
...
Run Code Online (Sandbox Code Playgroud)
Slick(2.1.0版)表映射:
class Users(_tableTag: Tag) extends Table[User](_tableTag, "users") with WithId[Users, User] {`
val id: Column[Int] = column[Int]("id", O.AutoInc, O.PrimaryKey)
...
}
trait WithId[T, R] {
this: Table[R] =>
def id: Column[Int]
}
Run Code Online (Sandbox Code Playgroud)
混合特性WithId
我想用列实现不同表的通用DAO方法id: Column[Int]
(我希望方法findById
与两者User
和Address
表映射一起使用)
trait GenericSlickDAO[T <: WithId[T, R], R] {
def db: Database
def findById(id: Int)(implicit stk: SlickTableQuery[T]): Option[R] = db.withSession { implicit session =>
stk.tableQuery.filter(_.id === id).list.headOption
}
trait SlickTableQuery[T] { …
Run Code Online (Sandbox Code Playgroud) scala ×10
traits ×4
self-type ×2
cake-pattern ×1
class ×1
composition ×1
generics ×1
mixins ×1
polymorphism ×1
slick ×1
types ×1