Class 如何决定使用trait来';与';或类到';注入';?
在编写scala代码时,我很难选择Class 如何决定使用trait来';与';或类到';注入';?,class,scala,traits,Class,Scala,Traits,在编写scala代码时,我很难选择特征或类 首先,我有一个控制器,具有以下几个特点: class MyController extends Controller with TransactionSupport with JsonConverterSupport with LoggerSupport 在这些特性中,我定义了一些可以直接在MyController中使用的方法和字段
特征
或类
首先,我有一个控制器,具有以下几个特点:
class MyController extends Controller
with TransactionSupport
with JsonConverterSupport
with LoggerSupport
在这些特性中,我定义了一些可以直接在MyController中使用的方法和字段
但是我的朋友说:当你扩展了
或者了
一种特质时,它应该是一种
那种特质
看看MyController
,它是控制器
,但它不是交易支持
,不是JsonConverterSupport
,也不是日志支持
,因此它不应该与一起使用
因此,代码变成:
class MyController(tranSupport: TransactionSupport,
jsonConverter: JsonConverterSupport,
loggerSupport: LoggerSupport) extends Controller
但是我对这段代码感觉不好,它看起来很奇怪
我看到trait
s在scala代码中被大量使用,我应该在什么时候使用它或使用类来注入?我的观点是,它没有成为它。混入与继承是不同的概念。即使在句法上它是相同的,但并不意味着相同。混入的典型用例是像您所写的那样记录日志。这并不意味着如果您的服务类混合了日志记录
特性,那么就是一个日志记录者。这只是将功能组合到工作对象中的另一种方式
奥德斯基建议,如果你不确定并且你可以,使用trait
s,因为它们更灵活。如果需要,您可以在将来将trait
更改为class
。我会让您参考。尽管某些特征可能扮演一个类的角色(因此,它们是名词并尊重“is-a”关系),但当用作混搭时,它们往往扮演接口的角色
作为一个“形容词”,特质将为其扩展的内容添加限定属性。例如,它们可能是可比较的
或可序列化的
要找到一个合适的形容词可能有点困难——你会用哪个形容词来形容LoggerSupport
?——所以,不要觉得自己受到了太多的约束。只是要意识到,将特质的东西视为必然的“是一种”关系是完全错误的
不过,我会尽量避免使用特质来取代“has-a”关系。有时当我觉得混合特质看起来不太好时,我会使用如下模块模式:
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看起来更像一个控制器,所有与Json相关的内容都隐藏在MyController的“客户端”中。您的第一个带有traits的示例是“蛋糕模式”,第二个示例是“构造函数注入”。这两种方法都是在Scala中进行依赖项注入的非常有效的方法。cake模式功能强大,可以注入类型成员,不同的trait可以很容易地相互对话(我们不必创建单独的对象并将它们传递给其他对象,通常需要setter注入而不是简单的构造函数注入),等等。但是,类型必须在编译时实现,每一个特征组合都必须实现一个单独的类别。构造函数注入使您能够在运行时构建对象,并能更好地扩展大量组合