Mixins vs Scala中的成分 [英] Mixins vs composition in scala

查看:85
本文介绍了Mixins vs Scala中的成分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Java世界中(更确切地说,如果您没有多重继承/混合),经验法则非常简单:在类继承上是最重要的对象组成".

In java world (more precisely if you have no multiple inheritance/mixins) the rule of thumb is quite simple: "Favor object composition over class inheritance".

我想知道是否/也如何改变了mixin,尤其是在scala中?
是否将mixin视为一种多重继承或更多类组合的方法?
还有从对象组成到从类组成"(或相反)的指导原则吗?

I'd like to know if/how it is changed if you also consider mixins, especially in scala?
Are mixins considered a way of multiple inheritance, or more class composition?
Is there also a "Favor object composition over class composition" (or the other way around) guideline?

当人们使用(或滥用)mixins进行对象组合也可以完成工作时,我已经看到了很多示例,但我并不总是确定哪一个更好.在我看来,您可以用它们实现非常相似的功能,但是也有一些区别,例如:

I've seen quite some examples when people use (or abuse) mixins when object composition could also do the job and I'm not always sure which one is better. It seems to me that you can achieve quite similar things with them, but there are some differences also, some examples:

  • 可见性-使用mixins时,所有内容都成为公共api的一部分,而组合则不是这种情况.
  • 冗长性-在大多数情况下,mixin不太冗长,使用起来更容易一些,但并非总是如此(例如,如果您还在复杂的层次结构中使用自身类型)

我知道简短的答案是取决于情况",但可能会有一些典型的情况,那是更好的选择.

I know the short answer is "It depends", but probably there are some typical situation when this or that is better.

到目前为止,我可以提出一些准则示例(假设我具有A和B的两个特征,而A希望使用B的某些方法):

Some examples of guidelines I could come up with so far (assuming I have two traits A and B and A wants to use some methods from B):

  • 如果要使用B的方法扩展A的API,请使用mixins,否则进行组合.但是,如果我正在创建的类/实例不属于公共API的话,这将无济于事.
  • 如果您想使用一些需要混合的模式(例如可堆叠的特征模式),这是一个简单的决定.
  • 如果您具有循环依赖关系,那么具有self类型的mixin可以提供帮助. (我试图避免这种情况,但这并不总是那么容易)
  • 如果要动态地,在运行时决定如何进行合成,然后再进行对象合成.
  • If you want to extend the API of A with the methods from B then mixins, otherwise composition. But it does not help if the class/instance that I'm creating is not part of a public API.
  • If you want to use some patterns that need mixins (e.g. Stackable Trait Pattern) then it's an easy decision.
  • If you have circular dependencies then mixins with self types can help. (I try to avoid this situation, but it's not always easy)
  • If you want some dynamic, runtime decisions how to do the composition then object composition.

在很多情况下,mixin似乎更容易(和/或更不冗长),但是我敢肯定,它们也存在一些陷阱,例如神类"和其他两篇artima文章中所述的其他缺陷:第2部分(顺便说一句,在我看来,大多数其他问题与scala无关/并不那么严重).

In many cases mixins seem to be easier (and/or less verbose), but I'm quite sure they also have some pitfalls, like the "God class" and others described in two artima articles: part 1, part 2 (BTW it seems to me that most of the other problems are not relevant/not so serious for scala).

您还有更多类似的提示吗?

Do you have more hints like these?

推荐答案

如果只将抽象特征混入类定义中,然后再进行混用,则在Scala中可以避免人们对混入的很多问题.在对象实例化时对应的具体特征中.例如

A lot of the problems that people have with mix-ins can be averted in Scala if you only mix-in abstract traits into your class definitions, and then mix in the corresponding concrete traits at object instantiation time. For instance

trait Locking{
   // abstract locking trait, many possible definitions
   protected def lock(body: =>A):A
}

class MyService{
   this:Locking =>
}

//For this time, we'll use a java.util.concurrent lock
val myService:MyService = new MyService with JDK15Locking 

此构造有几件事值得推荐.首先,由于需要特征功能的不同组合,因此可以防止类爆炸.其次,它可以轻松进行测试,因为它可以创建并混入不做任何事情"的具体特征,类似于模拟对象.最后,我们已经从服务的使用者中完全隐藏了所使用的锁定特性,甚至锁定正在进行中.

This construct has several things to recommend it. First, it prevents there from being an explosion of classes as different combinations of trait functionalities are needed. Second, it allows for easy testing, as one can create and mix-in "do-nothing" concrete traits, similar to mock objects. Finally, we've completely hidden the locking trait used, and even that locking is going on, from consumers of our service.

由于我们已经克服了混搭所声称的大多数缺点,因此我们仍然需要权衡取舍 在混合和组成之间.对于我自己,我通常根据一个假设的委托对象是否完全被包含的对象封装,或者是否有可能被共享并拥有自己的生命周期来做出决定.锁定为完全封装的委托提供了一个很好的例子.如果您的类使用锁对象来管理对其内部状态的并发访问,则该锁将完全由包含对象控制,并且该锁及其操作都不会作为该类的公共接口的一部分进行宣传.对于这样的完全封装的功能,我使用了混入.对于共享的内容(例如数据源),请使用组合.

Since we've gotten past most of the claimed drawbacks of mix-ins, we're still left with a tradeoff between mix-in and composition. For myself, I normally make the decision based on whether a hypothetical delegate object would be entirely encapsulated by the containing object, or whether it could potentially be shared and have a lifecycle of its own. Locking provides a good example of entirely encapsulated delegates. If your class uses a lock object to manage concurrent access to its internal state, that lock is entirely controlled by the containing object, and neither it nor its operations are advertised as part of the class's public interface. For entirely encapsulated functionality like this, I go with mix-ins. For something shared, like a datasource, use composition.

这篇关于Mixins vs Scala中的成分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆