如何确定使用特质与'或者注意到'?

时间:2014-04-22 02:53:57

标签: class scala traits

在编写scala代码时,我很困惑地选择traitclass

首先,我有一个with几个特征的控制器:

class MyController extends Controller 
                   with TransactionSupport 
                   with JsonConverterSupport 
                   with LoggerSupport

在这些特征中,我定义了一些可以直接在MyController中使用的方法和字段。

但是我的朋友说:当你extendswith这个特性时,它应该be a这个特性。

查看MyController,它是Controller,但它不是TransactionSupport,而不是JsonConverterSupport,而不是LoggerSupport,所以不应该with他们。

所以代码变成:

class MyController(tranSupport: TransactionSupport, 
                   jsonConverter: JsonConverterSupport, 
                   loggerSupport: LoggerSupport) extends Controller

但是我对这段代码感觉不太好,这看起来很奇怪。

我看到trait在scala代码中大量使用,我什么时候应该使用它或使用类来注入?

4 个答案:

答案 0 :(得分:6)

我会推荐你​​Interfaces should be Adjectives。虽然一些特征可能扮演一个阶级的角色(因此,是名词并尊重“是 - ”关系),但当用作混合时,它们往往会扮演界面的角色。

作为一个“形容词”,该特征将为他们所扩展的任何内容添加一个合格的属性。例如,它们可能是ComparableSerializable

找到一个适合的形容词可能有点难度 - 你会用LoggerSupport这个形容词? - 所以不要觉得过分受到限制。请注意,特质是完全错误的,因为它必然是一种“是一种”的关系。

但我会尽量避免使用特征来代替“has-a”关系。

答案 1 :(得分:1)

我的意见是它没有to be它。混合是一种与继承不同的概念。尽管在语法上它是相同的,但它并不意味着相同。混合的典型用例就像你写的那样记录。如果您的服务类混合Logging特征it is记录器,这并不意味着。它只是另一种如何将功能组合成工作对象的方式。

Odersky建议,如果您不确定并且可以,请使用trait,因为它们更灵活。如果需要,您可以在将来将trait更改为class

答案 2 :(得分:1)

有时当我觉得混合特性看起来不太好时,我会使用这样的模块模式:

trait JsonConverterModule {

    protected def jsonConverter: JsonConverter

    protected trait JsonConverter {
      def convert(in: Json): Json
    }
  }

class MyController extends Controller with JsonConverterModule {
   private doSmth = jsonConverter.convert(...)
}

在这种情况下,MyController看起来更像是一个Controller,所有与Json相关的东西都隐藏在MyController'client'中

答案 3 :(得分:0)

你的第一个特征是"蛋糕模式"你的第二个例子是"构造函数注入"。两者都是在Scala中进行依赖注入的完全有效的方法。蛋糕模式功能强大,你可以注入类型成员,不同的特性可以很容易地相互交谈(我们不必创建单独的对象并将它们传递给彼此的对象,通常需要setter注入而不是简单的构造函数注入但是,类型必须在编译时实现,并且必须为每个特征组合实现单独的类。构造函数注入允许您在运行时构建对象,并且可以针对大量组合进行更好的扩展。