Предположим, что у меня есть класс с именем Rational
, который представляет рациональные числа "чисто", то есть он поддерживает представление a / b как (a, b)
и реализует обычные операторы +, -, *, /
и другие для работы с этими кортежами, вместо оценки фактических дробей для каждой операции.
Предположим теперь, что я хочу определить, что произойдет, если я добавлю Rational
экземпляр к Int
, в дополнение к уже определенному поведению для Rational
, добавленному к Rational
. Тогда, конечно, я мог бы в конечном итоге захотеть добавить Rational
к Double
или к Float
, BigInt
другим числовым типам ...
Подход № 1: Предоставить несколько реализаций +(Rational, _)
:
def + (that:Rational):Rational = {
require(that != null, "Rational + Rational: Provided null argument.")
new Rational(this.numer * that.denom + that.numer * this.denom, this.denom * that.denom)
}
def + (that:Int): Rational = this + new Rational(that, 1) // Constructor takes (numer, denom) pair
def + (that:BigInt): Rational = ....
.
.
.
Подход № 2: Сопоставление с образцом на Any
:
def + (that:Any):Rational = {
require(that != null, "+(Rational, Any): Provided null argument.")
that match {
case that:Rational => new Rational(this.numer * that.denom + that.numer * this.denom, this.denom * that.denom)
case that:Int | BigInt => new Rational(this.numer + that * this.denom, this.denom) // a /b + c = (a + cb)/b
case that:Double => ....
.
.
.
case _ => throw new UnsupportedOperationException("+(Rational, Any): Unsupported operand.")
}
}
Одно из преимуществ подхода сопоставления с образцом, которое я вижу, - это сохранение с точки зрения фактических строк исходного кода, но, возможно, с уменьшением читабельности. Возможно, что еще более важно, я могу контролировать то, что я делаю, когда мне предоставляют тип, для которого я не определила поведение +
. Я не уверен, как этого можно достичь с помощью первого подхода, возможно, путем добавления перегрузки для Any
под всеми остальными? В любом случае, это звучит опасно.
Идеи о том, следует ли выбирать первый или второй подход? Есть ли проблемы с безопасностью, которых я не вижу? Я открываю себя для ClassCastException
s или других видов исключений?