Я пытаюсь разработать иерархию классов с кучей похожих классов, которые не совсем разделяют отношения "есть". Давайте назовем эти Model
классы. Эти классы предназначены для сопряжения с набором похожих алгоритмов, которые используют классы Model
, но не имеют одинаковых требований. Давайте назовем эти Strategy
классы. Хитрость в том, что классы Strategy
требуют многих из классов Model
, но не все классы Model
могут реализовать эти необходимые методы. Мне бы не хотелось иметь пустые методы-заглушки, которые будут просто генерировать UnsupportedOperationException
s, а вместо этого использовать безопасный для типов способ решения этой проблемы - есть ли шаблон проектирования, который я могу применить?
Например,
object Main extends App {
trait A {
def f(one: Int): Int
def g(two: Int): Int
def h(three: Int): Int
}
class A1 extends A {
override def f(one: Int): Int = {one + 1}
override def g(two: Int): Int = {two + 2}
override def h(three: Int): Int = {assert(false); 0}
}
class A2 extends A {
override def f(one: Int): Int = {assert(false); 0}
override def g(two: Int): Int = {two - 2}
override def h(three: Int): Int = {three - 3}
}
trait B {
def combine(i: Int): Int
}
trait B1 extends B {
this: A =>
override def combine(i: Int) = {f(i) + g(i)}
}
trait B2 extends B {
this: A =>
override def combine(i: Int) = {g(i) + h(i)}
}
override def main(args: Array[String]): Unit = {
val a11 = new A1 with B1
val a22 = new A2 with B2
println(a11.combine(3))
println(a22.combine(3))
val a12 = new A1 with B2
println(a12.combine(3))
}
}
Здесь A
- это класс Model
, а B
- это класс Strategy
. Обратите внимание, что A1
может быть не в состоянии реализовать h()
и что A2
может быть не в состоянии реализовать f()
, и в зависимости от класса стратегии это может быть или не быть проблемой. Мне бы хотелось узнать, какая реализация A может работать с какой реализацией B во время компиляции.
Я использовал self-types для выражения отношения «больше», чем «это», которое обычно идет с расширением.