你怎么能继承一个通用的工厂方法?

假设你有一个Person类,并通过扩展例如ArrayBuffer为它创建一个集合类:

class Persons extends ArrayBuffer[Person] {
// methods operation on the collection
}

现在,使用ArrayBuffer,可以在伴随对象上使用apply()方法创建一个集合,例如:

ArrayBuffer(1, 2, 3)

你希望能够对人员做同样的事情,例如:

Persons(new Person("John", 32), new Person("Bob", 43))

我的第一个直觉就是扩展了ArrayBuffer伴侣对象并免费获得了apply()方法。 但看起来你不能扩展对象。 (我不太清楚为什么。)

接下来的想法是用一个调用ArrayBuffer的apply方法的apply()方法创建Persons对象:

object Persons {
    def apply(ps: Person*) = ArrayBuffer(ps: _*) 
}

但是,这会返回一个ArrayBuffer [Person]而不是Persons。

在对Scaladoc和ArrayBuffer的源代码进行了一些挖掘之后,我想出了以下内容,我认为这会让Persons对象从GenericCompanion继承apply():

编辑:

object Persons extends SeqFactory[ArrayBuffer] {
    def fromArrayBuffer(ps: ArrayBuffer[Person]) = {
        val persons = new Persons
        persons appendAll ps
        persons
    }

    def newBuilder[Person]: Builder[Person, Persons] = new ArrayBuffer[Person] mapResult fromArrayBuffer
}

但是,它会提供以下错误消息:

<console>:24: error: type mismatch;
 found   : (scala.collection.mutable.ArrayBuffer[Person]) => Persons
 required: (scala.collection.mutable.ArrayBuffer[Person(in method newBuilder)])
=> Persons
        def newBuilder[Person]: Builder[Person, Persons] = new ArrayBuffer[Perso
n] mapResult fromArrayBuffer
             ^

也许这应该不鼓励我继续走下去,但是我正在学习Scala很棒的时间,我真的很想让这个工作。 请告诉我,如果我在错误的轨道上。 :)


不要直接扩展ArrayBuffer[Person] ,你可以使用pimp我的库模式。 这个想法是让PersonsArrayBuffer[Person]完全可以互换。

class Persons(val self: ArrayBuffer[Person]) extends Proxy {
   def names = self map { _.name }

   // ... other methods ...
}

object Persons {
   def apply(ps: Person*): Persons = ArrayBuffer(ps: _*)

   implicit def toPersons(b: ArrayBuffer[Person]): Persons = new Persons(b)

   implicit def toBuffer(ps: Persons): ArrayBuffer[Person] = ps.self
}

Persons伴随对象中的隐式转换允许您在拥有Persons引用时使用任何ArrayBuffer方法,反之亦然。

例如,你可以做

val l = Persons(new Person("Joe"))
(l += new Person("Bob")).names

请注意, lPersons ,但您可以调用ArrayBuffer.+=方法,因为编译器会自动添加对Persons.toBuffer(l)的调用。 +=方法的结果是一个ArrayBuffer ,但您可以在其上调用Person.names ,因为编译器会向Persons.toPersons插入一个调用。

编辑:

您可以用更高级的类型概括此解决方案:

class Persons[CC[X] <: Seq[X]](self: CC[Person]) extends Proxy {
   def names = self map (_.name)
   def averageAge = {
      self map (_.age) reduceLeft { _ + _ } / 
            (self.length toDouble)
   }
   // other methods
}

object Persons {
   def apply(ps: Person*): Persons[ArrayBuffer] = ArrayBuffer(ps: _*)

   implicit def toPersons[CC[X] <: Seq[X]](c: CC[Person]): Persons[CC] =
         new Persons[CC](c)

   implicit def toColl[CC[X] <: Seq[X]](ps: Persons[CC]): CC[Person] = 
         ps.self
}

这可以让你做类似的事情

List(new Person("Joe", 38), new Person("Bob", 52)).names

要么

val p = Persons(new Person("Jeff", 23))
p += new Person("Sam", 20)

请注意,在后面的例子中,我们正在给一个Persons打电话+= 。 这是可能的,因为Persons会“记住”底层集合类型,并允许您调用该类型定义的任何方法( ArrayBuffer在这种情况下,由于定义Persons.apply )。


除了anovstrup的解决方案,下面的例子不会做你想要的吗?


case class Person(name: String, age: Int)

class Persons extends ArrayBuffer[Person]

object Persons {
    def apply(ps: Person*) = {
      val persons = new Persons
      persons appendAll(ps)
      persons
    }
}

scala> val ps = Persons(new Person("John", 32), new Person("Bob", 43))
ps: Persons = ArrayBuffer(Person(John,32), Person(Bob,43))

scala> ps.append(new Person("Bill", 50))   

scala> ps
res0: Persons = ArrayBuffer(Person(John,32), Person(Bob,43), Person(Bill,50))
链接地址: http://www.djcxy.com/p/47233.html

上一篇: How can you inherit a generic factory method?

下一篇: Disk database storage, best practices