Scala 混合和继承之间有什么区别?
我试图在scala的上下文中理解mixin。我特别想知道继承和混合概念之间的区别 Mixin的定义是: mixin类充当父类,包含所需的功能。然后,子类可以继承或简单地重用此功能,但不能作为专门化的手段。通常,mixin会将所需的功能导出到子类,而不会创建一个僵硬的、单一的“is-a”关系。这里是mixin和继承概念之间的重要区别,因为子类仍然可以继承父类的所有特性,但是,不必应用关于子类“是”父类的语义 在上述定义中,我无法理解用粗体标记的语句。这是什么意思Scala 混合和继承之间有什么区别?,scala,oop,Scala,Oop,我试图在scala的上下文中理解mixin。我特别想知道继承和混合概念之间的区别 Mixin的定义是: mixin类充当父类,包含所需的功能。然后,子类可以继承或简单地重用此功能,但不能作为专门化的手段。通常,mixin会将所需的功能导出到子类,而不会创建一个僵硬的、单一的“is-a”关系。这里是mixin和继承概念之间的重要区别,因为子类仍然可以继承父类的所有特性,但是,不必应用关于子类“是”父类的语义 在上述定义中,我无法理解用粗体标记的语句。这是什么意思 子类可以继承mixin中的功能,但
我认为这是在讨论实际的类层次结构。例如,
Dog
是Animal
的一种类型,如果它是从类(继承)扩展而来的。它可以在动物
参数适用的任何地方使用。我不确定我是否正确理解了你的问题,但如果我理解了,你是在问什么东西可以继承,而不是真正意义上的继承
然而,mixin不是继承——它实际上更类似于动态地将一组方法添加到对象中。继承说“这个东西是另一种东西”,而mixin说,“这个对象有这个东西的一些特征。”你可以在用于声明mixin的关键字中看到这一点: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
}
抽象类航天器{
def接合():装置
}
特徵CommandoBridge扩展航天器{
def接合():装置={
例如(trait(与类混合时称为mixin)就像Java中的一个接口(尽管有很多),在这个接口中,您可以向类添加额外的特性,而不必具有“is A”关系。或者您可以说,通常trait将多个独立类可以使用的特性捆绑在一起
给你一个Scala库的例子,是一个trait
,它提供了一些基本的比较操作(比如=
)到类的实现,这些类可以具有自然排序的数据
例如,假设您有自己的类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
share与Number
是一种关系,但是EvenNumber
与Half
没有“是”关系,也不是OddNumber
share”与Increment
的关系
另一个重要的观点是,尽管类Number
使用扩展有序的语法,但这意味着Number
有一个隐含的关系,即有序的超类,即任何,我认为它非常依赖于用法。Scala是一种多范式语言,因此它是powerful以及有时有点混乱。
我认为如果使用正确的方法,mixin是非常强大的。
应使用混合剂来引入行为并减少bolierplate
Scala中的一个特性可以有实现,并且很容易扩展和使用它们
Traits可以用于继承。它也可以被称为mixin,但在我看来,这不是使用mixin
行为的最佳方式。在这种情况下,您可以将Traits视为Java抽象类。在这种情况下,您可以得到超类(trait)的“类型”的子类
但是,trait也可以用作适当的mixin
。现在,将trait用作mixin
取决于实现,即“如何将其混合”。这主要是一个简单的问题,你可以问自己“特质的子类是否真的是该特质的种类
,或者特质行为中的行为是否简化了样板”。
通常,最好通过将特征混合到对象中来实现,而不是扩展特征来创建新类
例如,考虑下面的例子:
//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=使用concreteDAO的新服务
-
这是正确的混合行为
由于服务特性要求AbstractDAO
的mixin
。service
扩展ConcreteDAO
无论如何都是错误的,因为service
requiredAbstractDAO
不是AbstractDAO
的一种类型。
相反,您使用不同的mixin创建服务的实例。mixin和继承的区别在于语义级别。在语法级别,它们都是相同的
为了混入一个特征,或者从一个特征继承,它们都使用相同语法的extends
或with
在语义层面上,一个想要被混合的特征通常没有一个是一个与混合它的类的关系,它不同于一个想要被继承的特征
对我来说,一个特征是mixin还是父特征是非常主观的,这通常是一个混乱的根源。在Scala中,将mixin看作是一个整洁的编译时转换,它将用额外的方法装饰某些类型。在本文中