我试图在scala的上下文中理解Mixins。特别是我想知道继承概念和Mixins之间的区别。 Wiki说mixins和inheritance的概念之间有重要的区别,因此我想理解它。
wiki中Mixin的定义是:
mixin类充当父类,包含所需的功能。然后,子类可以继承或简单地重用此功能,但不作为专业化手段。通常,mixin会将所需的功能导出到子类,而不会创建严格的单个“是”关系。这里有mixins和inheritance的概念之间的重要区别,因为子类仍然可以继承父类的所有特性,但是,关于子元素的语义“作为一种”父类不需要是必然应用。
在上面的定义中,我无法理解以粗体标出的语句。是什么意思
提前感谢您对上述内容的任何澄清。
答案 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
不是CommandoBridge
或PulseEngine
;但 它们,并获得这些特征中定义的方法。它是 一个Spacecraft
,正如您所看到的那样,因为它继承自该类。
值得一提的是,当trait
延伸class
时,如果你想要制作某种特性with
,那就必须扩展该类。例如,如果我有一个class Dog
,除非Dog with PulseEngine
延长Dog
,否则我无法Spacecraft
。这样,它就不像添加方法了;但是,它仍然相似。
答案 1 :(得分:3)
trait (当与类混合时称为 mixin )就像Java中的接口(尽管有很多differences)你可以在哪里为类添加其他功能,而不必使&#34;是&#34;关系。或者你可以说一般特征捆绑了可以被多个独立类使用的特征。
为了向您提供Scala库的示例,Ordered[A]是trait
,它提供了一些基本比较操作的实现(例如<
,<=
,{{1} },>
)可以拥有自然排序数据的类。
例如,假设您拥有自己的班级>=
以及子类Number
和EvenNumber
,如下所示。
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
AbstractDAO
。 Service
无论如何延长ConcreteDAO
都是错误的,因为service
需要AbstractDAO
它不是AbstractDAO
的类型。
相反,您使用不同的mixin创建service
的实例。
答案 3 :(得分:1)
我认为它是在讨论实际的类层次结构。例如,如果Dog
从类(继承)扩展,则Animal
是Animal
的类型。它可以在$beautymail = app()->make(\Snowfire\Beautymail\Beautymail::class);
参数适用的任何地方使用。
答案 4 :(得分:0)
mixin和继承之间的区别在于语义级别。在语法级别上,它们都是相同的。
要混合使用特征或从特征继承,它们都使用extends
或with
,这是相同的语法。
在语义级别上,要混合的特征通常与与其混合的类不具有is a
关系,而该类不同于要继承的特征。
对我而言,性状是混合还是父系是非常主观的,而时间往往是混乱的根源。