Надеюсь, не слишком академично ...
Допустим, мне нужны реальные и комплексные числа в моей библиотеке SW.
На основе отношения is-a (или здесь ) действительное число представляет собой комплексное число, где b в мнимой части комплексного числа просто 0.
С другой стороны, моя реализация состояла бы в том, что этот дочерний объект расширяет родительский, поэтому в родительском RealNumber у меня будет реальная часть, а дочерний ComplexNumber добавит воображаемую графику.
Также есть мнение, что наследство это зло .
Я помню, как вчера, когда я изучал ООП в университете, мой профессор сказал, что это не очень хороший пример наследования, поскольку абсолютное значение этих двух значений вычисляется по-разному (но для этого у нас есть метод перегрузки / полиморфизм, верно?) .. ,
Мой опыт показывает, что мы часто используем наследование для решения DRY, в результате чего у нас часто возникают искусственные абстрактные классы в иерархии (у нас часто возникает проблема с поиском имен, поскольку они не представляют объекты из реального мира).
источник
Ответы:
Даже если в математическом смысле действительное число является комплексным числом, нехорошо выводить вещественное из сложного. Это нарушает принцип подстановки Лискова, говоря (среди прочего), что производный класс не должен скрывать свойства базового класса.
В этом случае действительное число должно было бы скрыть мнимую часть комплексного числа. Понятно, что нет смысла хранить скрытое число с плавающей запятой (мнимую часть), если вам нужна только действительная часть.
Это в основном та же проблема, что и в примере прямоугольника / квадрата, упомянутом в комментарии.
источник
На самом деле это не убедительная причина против всего наследования, а только предложенная
class RealNumber
<->class ComplexNumber
модель.Вы могли бы разумно определить интерфейс
Number
, который и такRealNumber
иComplexNumber
будет реализовывать.Это может выглядеть как
Но тогда вы захотите ограничить другие
Number
параметры в этих операциях тем же производным типомthis
, к которому вы можете приблизиться с помощьюИли вместо этого вы бы использовали язык, который допускает структурный полиморфизм, а не полиморфизм подтипа. Для конкретного случая чисел вам может потребоваться только возможность перегрузки арифметических операторов.
источник
Решение: не иметь публичный
RealNumber
классЯ бы нашел, что все в порядке, если бы
ComplexNumber
у меня был статический фабричный методfromDouble(double)
, который возвращал бы комплексное число с мнимым нулем. Затем вы можете использовать все операции, которые вы бы использовали наRealNumber
экземпляре в этомComplexNumber
экземпляре.Но мне трудно понять, почему вы хотите / должны иметь открытый унаследованный
RealNumber
класс. Обычно наследование используется по этим причинам (из моей головы, поправьте меня, если пропустили некоторые)расширяя поведение.
RealNumbers
не может делать никаких дополнительных операций, комплексное число не может делать, поэтому нет смысла делать это.реализация абстрактного поведения с конкретной реализацией. Так как
ComplexNumber
не должно быть абстрактным, это также не относится.повторное использование кода. Если вы просто используете
ComplexNumber
класс, вы повторно используете 100% кода.более конкретная / эффективная / точная реализация для конкретной задачи. Это может быть применено здесь,
RealNumbers
может быстрее реализовать некоторые функции. Но тогда этот подкласс должен быть скрыт за статикойfromDouble(double)
и не должен быть известен снаружи. Таким образом, не нужно было бы скрывать мнимую часть. Снаружи должны быть только комплексные числа (которые являются действительными числами). Вы также можете вернуть этот закрытый класс RealNumber из любых операций в классе комплексных чисел, которые приводят к действительному числу. (Это предполагает, что классы неизменны, как большинство числовых классов.)Это похоже на реализацию подкласса Integer, который называется Zero, и жестко закодировать некоторые операции, поскольку они тривиальны для нуля. Вы можете сделать это, так как каждый ноль является целым числом, но не делайте его открытым, скрывайте его за фабричным методом.
источник
Утверждение, что действительное число является комплексным числом, имеет большее значение в математике, особенно в теории множеств, чем в информатике.
В математике мы говорим:
Однако это не означает, что вы должны или даже должны использовать наследование при разработке вашей библиотеки для включения классов RealNumber и ComplexNumber. В эффективной Java, второе издание Джошуа Блоха; Пункт 16 - «Композиция в пользу наследования». Чтобы избежать проблем, упомянутых в этом элементе, после определения класса RealNumber его можно использовать в классе ComplexNumber:
Это дает вам все возможности повторного использования вашего класса RealNumber, чтобы сохранить код сухим, избегая проблем, выявленных Джошуа Блохом.
источник
Здесь есть два вопроса. Во-первых, обычно используются одни и те же термины для типов контейнеров и типов их содержимого, особенно с примитивными типами, такими как числа. Термин
double
, например, используется для описания значения с плавающей запятой двойной точности и контейнера, в котором оно может быть сохранено.Вторая проблема заключается в том, что хотя отношения is-a между контейнерами, из которых могут считываться различные типы объектов, ведут себя так же, как отношения между самими объектами, те, которые существуют между контейнерами, в которые могут быть помещены различные типы объектов, ведут себя противоположно отношениям между их содержимым. , Каждая клетка, которая, как известно, содержит экземпляр,
Cat
будет клеткой, которая содержит экземплярAnimal
, но не обязательно должна быть клеткой, которая содержит экземплярSiameseCat
. С другой стороны, каждая клетка, которая может содержать все экземпляры,Cat
будет клеткой, которая может содержать все экземплярыSiameseCat
, но не обязательно должна быть клеткой, которая может содержать все экземплярыAnimal
. Единственный вид клетки, который может содержать все экземплярыCat
и может быть гарантированно, никогда не содержит ничего, кроме экземпляраCat
КлеткаCat
. Любой другой вид клетки либо не сможет принять некоторые случаи,Cat
которые он должен принять, либо будет способен принимать вещи, которые не являются примерамиCat
.источник