Ответы Андрея и Димы охватывают один способ решения проблемы с использованием только oo-шаблонов.
Однако я хотел бы отметить другой подход, называемый typeclasses (которыйчаще встречается в функциональных языках) , что было бы полезно, если вы планируете писать универсальные функции с использованием вашего интерфейса.
Во-первых, вместо родительского класса у вас есть интерфейс который описывает операции, которые могут выполняться над экземплярами класса типов.
trait Typeclass[T] {
def something(t: T)(arg: Foo): T
}
Затем вы должны определить свои типы, на этот раз они не расширяют родительский класс, поэтому им не нужноничего не переопределять.
class Child {
...
}
Теперь вы должны доказать, что ваш тип является экземпляром класса типа.
(Обычное место, где это можно сделать, находится в сопутствующем объекте класса) .
object Child {
implicit final val ChildTypeclass: Typeclass[Child] = new Typeclass[Child] {
override def something(child: Child)(arg: Foo): Child = ???
}
}
Наконец, вы определяете универсальный метод, который может работать с любым типом T, если для этого типа существует экземпляр вашего класса типов.
def generic[T](t: T, arg: Foo)(implicit tt: Typeclass[T]): T =
tt.something(t)(arg)
Бонус, если вы хотите восстановить "точечную нотацию" , вы можете добавить шаблон Ops к вашему классу типов.
object syntax {
object typeclass {
implicit final class TypeclassOps[T](val t: T) extends AnyVal {
final def something(arg: Foo)(implicit tt: Typelcass[T]) =
tt.something(t)(arg)
}
}
}
import syntax.typeclasss._
def generic[T: Typelcass](t: T, arg: Foo): T
t.something(arg)
val newChild = generic(new Child, new Foo)
// newChild: Child = ???
Кроме того, общий подход заключается в определении something
метод в вашем классе и экземпляр класса типов перенаправляет вызов к определенному в классе, таким образом вы можете использовать свой метод в любом экземпляре Child
без необходимости помещать все механизмы класса типов.
Iдолжен сказать, что это полезно для абстракций очень высокого уровня, для которых вы планируете предоставлять экземпляры для многих типов (даже типов вне вашего контроля, как любой из стандартных типов коллекций) и писать очень общие функции, которые могут работатьна любом из них.
Если нет, F-ограниченные типы кажутся более рациональным решением.