Scala: Как я могу сделать мои неизменяемые классы легче подклассами? - PullRequest
14 голосов
/ 29 августа 2011

Я недавно создал неизменный класс, поддерживающий такие операции, как +, - и т. Д., Который возвращает новый экземпляр этого класса при его изменении.

Я хотел создать подкласс этого класса для добавлениянемного состояния и функциональности, но теперь я сталкиваюсь с проблемой, заключающейся в том, что все методы исходного класса возвращают экземпляры самого себя, а не подкласса.

Основываясь на моих текущих ограниченных знаниях Scala, я могу придуматьthis:

class Foo(val bar:Int) { 
  def copy(newBar:Int) = new Foo(newBar)
  def + (other:Foo):This = copy(this.bar + other.bar) 
}
class Subclass(barbar:Int) extends Foo(barbar) { 
  override def copy(newBar:Int) = new Subclass(newBar)
  override def + (other:Subclass) = super.+(other).asInstanceOf[Subclass]
}

Проблема здесь совершенно очевидна - все операции суперкласса, которые возвращают новый экземпляр, должны быть переопределены в подклассе с помощью приведения.

Сначала«this.type» показался многообещающим, но «this.type» включает в себя только «this», а не любой другой объект того же типа.

Существует ли стандартный шаблон для облегчения подкласса неизменяемых классов?Примерно так:

class Foo(val bar:Int) { 
  def copy(newBar:Int):SameType = new Foo(newBar)
  def + (other:Foo) = copy(this.bar + other.bar) 
}
class Subclass(barbar:Int) extends Foo(barbar) { 
  override def copy(newBar:Int):SameType = new Subclass(newBar)
  override def + (other:Subclass) = super.+(other).asInstanceOf[Subclass]
}

Этот конкретный подход требует, чтобы компилятор требовал, чтобы все подклассы реализовывали метод copy (), который возвращает тот же тип, что и этот подкласс, что было бы прекрасно для меня.Тем не менее, я не думаю, что в настоящее время в Scala существует что-то подобное.

Некоторые возможные обходные пути:

  1. Использование делегирования - но, конечно, я 'все равно буду повторно реализовывать все методы как вызовы делегатов
  2. Использовать неявные типы для добавления операций вместо подклассов
  3. Использовать изменяемую структуру данных.Возможно, это самое простое и быстрое решение, но я бы потерял преимущества использования неизменяемых структур данных (о которых я все еще надеюсь узнать больше).

Я уверен, что это былообсуждали уже много раз, и я прошу прощения за повторный запрос.Я сделал Google для дублирующего вопроса без успеха, поэтому мои условия поиска были неправильно составлены.

Заранее спасибо,

Dobes

1 Ответ

9 голосов
/ 29 августа 2011

Вы можете использовать черту реализации, как это делают классы коллекции, которая параметризована конкретным типом.Например, что-то вроде:

trait FooLike[+A] {
  protected def bar: Int

  protected def copy(newBar: Int): A
  def +(other: Foo): A = copy(bar + other.bar)
}

class Foo(val bar: Int) extends FooLike[Foo] {
  protected def copy(newBar: Int): Foo = new Foo(newBar)
}

class Subclass(barbar: Int) extends Foo(barbar) with FooLike[Subclass] {
  protected def copy(newBar: Int): Subclass = new Subclass(newBar)
}
...