如何在Scala中实现多态性

时间:2014-02-10 09:17:19

标签: oop scala

我一直在学习Scala用于网络开发很长一段时间,我偶然发现缺少接口。来自PHP,我使用了很多方法级别的多态性和IoC这样的接口:

interface iAnimal
{
    function makeVoice();
}

class Cat implements iAnimal
{
    function makeVoice()
    {
        return "Meow";
    }
}

class Dog implements iAnimal
{
    function makeVoice()
    {
        return "Woof!";
    }
}

class Box
{
    private $_animal;

    function __construct(iAnimal $animal)
    {
        $this->_animal = $animal;         
    }

    function makeSound()
    {
        echo $this->_animal->makeVoice();
    }
}

等等,这是一种简单的方法,可以确保我传递给Box对象的任何内容都有makeVoice方法,我在其他地方调用它。现在,我很好奇的是,我如何使用Scala实现类似的功能。我试着寻找这个,但信息非常稀少。我找到的唯一答案是使用特征,但据我所知,它们用于具体实现,而不是声明。

提前致谢。

2 个答案:

答案 0 :(得分:5)

根据其他答案,解决方案是使用特征:

trait Animal {
  def makeVoice(): Unit //no definition, this is abstract!
}

class Cat extends Animal{
  def makeVoice(): Unit = "Meow"
}
class Dog extends Animal{
  def makeVoice(): Unit = "Woof"
}

class Box(animal:Animal) {
  def makeSound() = animal.makeVoice()
}

Scala中的trait将直接编译为Java中的interface。如果它包含任何具体成员,那么这些将直接复制到任何继承该特征的类中。您可以愉快地使用Scala特性作为Java的接口,但是您没有为您混合使用具体功能。


然而......这只是图片的一部分。到目前为止我们实现的是子类型多态,Scala也允许ad-hoc多态(a.k.a类型类):

// Note: no common supertype needed here
class Cat { ... }
class Dog { ... }

sealed trait MakesVoice[T] {
  def makeVoice(): Unit
}
object MakesVoice {
  implicit object CatMakesVoice extends MakesVoice[Cat] {
    def makeVoice(): Unit = "Meow"
  }
  implicit object DogMakesVoice extends MakesVoice[Dog] {
    def makeVoice(): Unit = "Woof"
  }
  //helper method, not required, but nice to have
  def makesVoice[T](implicit mv: MakesVoice[T]) = mv
}

import MakesVoice._
//context-bound version
class Box[T : MakesVoice] {
  //using a helper:
  def makeSound() = makesVoice[T].makeVoice()
  //direct:
  def makeSound() = implicitly(MakesVoice[T]).makeVoice()
}

//using an implicit param
class Box[T](implicit mv : MakesVoice[T]) {
  def makeSound() = mv.makeVoice()
}

这里重要的是MakesVoice类型类可以与任何类型相关联,无论它属于哪个层次结构。您甚至可以使用从第三方库导入的基元或类型的类型类,这些基类或类型无法使用新接口进行改造。

当然,你也有参数多态性,你可能更熟悉“泛型”:)

答案 1 :(得分:1)

Traits用于声明和具体实现。这是您的示例的直接翻译

trait Animal {
  def makeVoice()
}

class Cat extends Animal{
  override def makeVoice(): Unit = "Meow"
}
class Dog extends Animal{
  override def makeVoice(): Unit = "Woof"
}

class Box(animal:Animal) {
  def makeSound()={
    animal.makeVoice()
  }
}

此外,您可以直接在特征中定义具体实现,这对不同类层次结构的成员共享的行为很有用:

trait Fish{
  def swim()="Swim"
}
class Truit extends Fish 

trait Bird{
  def fly() = "Fly"
}
class Eagle extends Bird

class Duck extends ???{
  def swim=???
  def fly=???
}

鸭子都会游弋苍蝇,你可以这样定义:

trait Swimmer{
  def swim
}
trait Fish extends Swimmer{
  def swim()="Swim"
}
class Truit extends Fish 
trait Bird{
  def fly()="Fly"
}
class Eagle extends Bird

class Duck extends Bird with Swimmer
相关问题