mixins和继承有什么区别?

时间:2016-04-20 01:37:46

标签: scala oop

我试图在scala的上下文中理解Mixins。特别是我想知道继承概念和Mixins之间的区别。 Wiki说mixins和inheritance的概念之间有重要的区别,因此我想理解它。

wiki中Mixin的定义是:

mixin类充当父类,包含所需的功能。然后,子类可以继承或简单地重用此功能,但不作为专业化手段。通常,mixin会将所需的功能导出到子类,而不会创建严格的单个“是”关系。这里有mixins和inheritance的概念之间的重要区别,因为子类仍然可以继承父类的所有特性,但是,关于子元素的语义“作为一种”父类不需要是必然应用

在上面的定义中,我无法理解以粗体标出的语句。是什么意思

  1. 子类可以在mixin中继承功能,但不能作为专业化手段
  2. 在mixins中,子进程继承了父类的所有功能,但是关于子进程的语义“不是必须应用父进程”。 - 孩子如何延伸父母而不一定是父母?有没有这样的例子。
  3. 提前感谢您对上述内容的任何澄清。

5 个答案:

答案 0 :(得分:12)

我不确定我是否正确地理解了你的问题,但是如果我这样做了,你就会问一些事情如何能够继承,而不会像继承那样具有同样的意义。

然而,Mixins不是继承 - 它实际上更类似于动态地将一组方法添加到对象中。而继承说"这件事是另一种事情",mixins说,"这个对象有另外一些特征。"您可以在用于声明mixins的关键字中看到此内容:trait

从Scala主页上公然窃取一个例子:

abstract class Spacecraft {
  def engage(): Unit
}
trait CommandoBridge extends Spacecraft {
  def engage(): Unit = {
    for (_ <- 1 to 3)
      speedUp()
  }
  def speedUp(): Unit
}
trait PulseEngine extends Spacecraft {
  val maxPulse: Int
  var currentPulse: Int = 0
  def speedUp(): Unit = {
    if (currentPulse < maxPulse)
      currentPulse += 1
  }
}
class StarCruiser extends Spacecraft
                     with CommandoBridge
                     with PulseEngine {
  val maxPulse = 200
}

在这种情况下,StarCruiser不是CommandoBridgePulseEngine;但 它们,并获得这些特征中定义的方法。它是 一个Spacecraft,正如您所看到的那样,因为它继承自该类。

值得一提的是,当trait延伸class时,如果你想要制作某种特性with,那就必须扩展该类。例如,如果我有一个class Dog,除非Dog with PulseEngine延长Dog,否则我无法Spacecraft。这样,它就不像添加方法了;但是,它仍然相似。

答案 1 :(得分:3)

trait (当与类混合时称为 mixin )就像Java中的接口(尽管有很多differences)你可以在哪里为类添加其他功能,而不必使&#34;是&#34;关系。或者你可以说一般特征捆绑了可以被多个独立类使用的特征。

为了向您提供Scala库的示例,Ordered[A]trait,它提供了一些基本比较操作的实现(例如<<=,{{1} },>)可以拥有自然排序数据的类。

例如,假设您拥有自己的班级>=以及子类NumberEvenNumber,如下所示。

OddNumber

在上面的示例中,类class Number(val num : Int) extends Ordered[Number] { override def compare(that : Number) = this.num - that.num } trait Half extends Number { def half() = num / 2 } trait Increment extends Number { def increment() = num + 1 } class EvenNumber(val evenNum : Int) extends Number(evenNum) with Half class OddNumber(val oddNum : Int) extends Number(oddNum) with Increment EvenNumber共享是与OddNumber关系,但Number没有&#34;是一个&#34;与EvenNumber的关系Half分享&#34;是&#34;与OddNumber的关系。

另一个重点即使类Increment使用Number语法,也意味着extends Ordered具有隐式 Number的超类即<{1}}是关系。

答案 2 :(得分:3)

我认为它非常依赖于使用。 Scala是一种多范式语言,有时会使它变得强大而且有点令人困惑。 我认为Mixins在使用正确的方式时非常强大。 Mixins应该用于引入行为并减少bolierplate。

Scala中的特征可以有实现,并且很有可能扩展它们并使用它们。

Traits可用于继承。它也可以称为mixins,但在我看来,这不是使用mixin行为的最佳方式。在这种情况下,您可以将特征视为Java Abstract Classes。其中你得到的子类是&#34;类型的&#34;超级(特质)。

然而,Traits也可以用作proper mixins。现在使用特征mixin取决于实施情况&#34;如何将其混合在&#34;中。主要是问自己一个简单的问题。它是&#34;特征的子类真正是特征的kind,还是特质行为中减少样板的行为&#34;。 通常,最好通过将特征混合到对象而不是扩展特征来创建新类来实现。

例如,请考虑以下示例:

    //All future versions of DAO will extend this
trait AbstractDAO{
  def getRecords:String
  def updateRecords(records:String):Unit
}
//One concrete version
trait concreteDAO extends AbstractDAO{
  override def getRecords={"Here are records"}
  override def updateRecords(records:String){
    println("Updated "+records)
  }
}
//One concrete version
trait concreteDAO1 extends AbstractDAO{
  override def getRecords={"Records returned from DAO2"}
  override def updateRecords(records:String){
    println("Updated via DAO2"+records)
  }
}
//This trait just defines dependencies (in this case an instance of AbstractDAO) and defines operations based over that
trait service{
  this:AbstractDAO =>

  def updateRecordsViaDAO(record:String)={  
  updateRecords(record) 
  }
  def getRecordsViaDAO={
  getRecords
  }
}


object DI extends App{
  val wiredObject = new service with concreteDAO //injecting concrete DAO to the service and calling methods
  wiredObject.updateRecords("RECORD1")
  println(wiredObject.getRecords)

  val wiredObject1 = new service with concreteDAO1
  wiredObject1.updateRecords("RECORD2")
  println(wiredObject1.getRecords)

}

concreteDAO是一个扩展AbstractDAO的特征 - 这是继承

val wiredObject = new service with concreteDAO - 这是适当的mixin行为 由于服务特征要求mixin AbstractDAOService无论如何延长ConcreteDAO都是错误的,因为service需要AbstractDAO它不是AbstractDAO的类型。 相反,您使用不同的mixin创建service的实例。

答案 3 :(得分:1)

我认为它是在讨论实际的类层次结构。例如,如果Dog从类(继承)扩展,则AnimalAnimal的类型。它可以在$beautymail = app()->make(\Snowfire\Beautymail\Beautymail::class); 参数适用的任何地方使用。

答案 4 :(得分:0)

mixin和继承之间的区别在于语义级别。在语法级别上,它们都是相同的。

要混合使用特征或从特征继承,它们都使用extendswith,这是相同的语法。

在语义级别上,要混合的特征通常与与其混合的类不具有is a关系,而该类不同于要继承的特征。

对我而言,性状是混合还是父系是非常主观的,而时间往往是混乱的根源。