简体   繁体   English

如何确定使用特征'''或类来“注入”?

[英]How to determine to use trait to 'with' or class to 'inject'?

I'm puzzled to choose a trait or class when writing scala code. 在编写scala代码时,我很困惑地选择一个traitclass

At first, I have a controller which with several traits: 起初,我有一个控制器, with几个特点:

class MyController extends Controller 
                   with TransactionSupport 
                   with JsonConverterSupport 
                   with LoggerSupport

In these traits, I defined some methods and fields which can be used in MyController directly. 在这些特性中,我定义了一些可以直接在MyController使用的方法和字段。

But my friend says: when you extends or with a trait, it should be a that trait. 但我的朋友说:当你extendswith特质时,它应该be a特质。

Look at the MyController , it is a Controller , but it isn't a TransactionSupport , not a JsonConverterSupport , not a LoggerSupport , so it should not with them. 看看MyController ,它是一个Controller ,但它不是一个TransactionSupport ,不是一个JsonConverterSupport ,不是一个LoggerSupport ,所以它不应该with它们一起使用。

So the code becomes: 所以代码变成:

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

But I don't feel good about this code, it just seems strange. 但我对这段代码感觉不太好,这看起来很奇怪。

I see trait s used heavily in scala code, when should I use it or use classes to inject? 我看到trait在scala代码中大量使用,我什么时候应该使用它或者使用类来注入?

I'll refer you to Interfaces should be Adjectives . 我会推荐你接口应该是形容词 Though some traits may play the part of a class (and, therefore, be nouns and respect the "is-a" relationship), when used as mixins they'll tend to play the part of interfaces. 虽然一些特征可能扮演一个类的一部分(因此,是名词并尊重“是一个”关系),但当用作mixin时,它们往往会扮演界面的一部分。

As an "adjective", the trait will add a qualifying property to whatever they are extending. 作为一个“形容词”,该特征将为他们所扩展的任何内容添加一个合格的属性。 For example, they may be Comparable or Serializable . 例如,它们可能是ComparableSerializable

It can be a bit hard to find an adjective to fit -- what adjective would you use for LoggerSupport ? 找到一个适合的形容词可能有点难度 - 你会用什么形容词来表示LoggerSupport -- so don't feel overly constrained by that. - 所以不要觉得过分受到限制。 Just be aware that it is completely wrong to thing of traits as necessarily an "is-a" relationship. 请注意,特质是完全错误的,因为它必然是一种“是一种”的关系。

I would try to avoid using traits to replace "has-a" relationships, though. 不过,我会尽量避免使用特征来代替“has-a”关系。

My opinion is that it doesn't have to be it. 我的意见是,它不一定to be它。 Mixing-in is a different concept than inheritance. 混合是一种与继承不同的概念。 Even though syntactically it is the same, it doesn't mean the same. 即使在语法上它是相同的,但它并不意味着相同。 Typical use case for mixing-in is logging just like you wrote. 混合的典型用例就像你写的那样记录。 It doesn't mean that if your service class mixes-in a Logging trait that it is a logger. 这并不意味着如果您的服务类混合了Logging特性, it is一个记录器。 It's just a yet another way how to compose functionality into working objects. 这只是如何将功能组合到工作对象中的另一种方式。

Odersky proposes that if you are not sure and you can, use trait s because they are more flexible. 奥德斯基建议,如果你不确定,你可以使用trait因为它们更灵活。 You can change trait to class in the future if you need. 如果需要,您可以在将来将trait更改为class

Sometime when I feel that mixing-in trait doesn't look good, I use module pattern like this: 有时当我觉得混合特性看起来不好时,我会使用这样的模块模式:

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 in this case looks more like a Controller, and all Json-related stuff is hidden from MyController 'client' 在这种情况下,MyController看起来更像是一个Controller,所有与Json相关的东西都隐藏在MyController'client'中

Your first example with traits is the "cake pattern" and your second example is "constructor injection". 你的第一个特征示例是“蛋糕模式”,第二个例子是“构造函数注入”。 Both are perfectly valid ways to do dependency injection in Scala. 两者都是在Scala中进行依赖注入的完全有效的方法。 The cake pattern is powerful, you can inject type members, the different traits can easily talk to each other (we don't have to create separate objects and pass them to each other object, often requiring setter injection rather than simple constructor injection), etc. However, the type has to be realized at compile-time, and a separate class must be realized for every combination of traits. 蛋糕模式功能强大,你可以注入类型成员,不同的特性可以很容易地相互通信(我们不必创建单独的对象并将它们传递给每个其他对象,通常需要setter注入而不是简单的构造函数注入),但是,必须在编译时实现类型,并且必须为每个特征组合实现单独的类。 Constructor injection lets you build your object at run-time and scales better for a large number of combinations. 构造函数注入允许您在运行时构建对象,并且可以针对大量组合进行更好的扩展。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM