开发者

Is it a good style having a trait and an equally named object extending that trait?

While I was browsing Paul Phillips GitHub repositories I noticed that he often uses a certain structur:

trait A {
 // ...
}
object A extends A

For example here: scala-improving, strings First, comming from Java, I wasn´t aware of having the same name for a trait and an object in the same scope.

And now I am asking what is it good for? What are the advantages over directly defining the object with all开发者_开发问答 the trait members? Ok, I know that the trait can be mixed in, but I assume using only the object in practice.


At least one case where this pattern comes in handy is when you're building a library of functions. You can regroup the functions (actually methods, but let's call them functions in this context) into several traits (which can then be seen as modules), say, MyLibA, MyLibB, MyLibC, etc. Then, if for each of them, you define an object implementing it, users of your lib can easily use it by writing, for instance, this:

import mypackage.MyLibA._

(assuming mypackage is the containing package). Moreover, you can easily provide a way to import all functions of your lib by providing an object MyLib as follows:

object MyLib extends MyLibA with MyLibB with MyLibC

and then users can simply import mypackage.MyLib._ instead of writing an import for each module separately. Better yet, you could define a package object mypackage extends MyLibA with MyLibB with MyLibC, and then users would simply write import mypackage._. And, the bonus is that picky users who would like to import only MyLibA and MyLibB in one line are also free to define their own “import object,” possibly even completing it with their own utility functions, or overriding your own:

object UserLibImport extends MyLibA with MyLibB {
    def userAdditionalFunction = /* ... */
    override def someRedefinedLibAFunction = /* ... */
}

… and then import all of it with import UserLibImport._

So, I'd say, in this case, not only is it good style, it's highly recommended to provide your functions in this way, as it allows for maximal flexibility.

(This was also briefly explained in this answer.)


An object is an obvious choice when you want a global singleton for utility methods. Unlike Java's statics, you can pass this object around typed as an instance of the trait.

One big advantage here is that you can then create another instance of that trait/interface for use in unit tests. Very handy if you're into TDD/BDD, statics have often been a pain in the neck when it comes to testability.


Trait is reusable. Trait just defines the contract of object A, and may be some implementation. But this trait can be used for Mock objects and as discussed above for aggregating functionality.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜