#java #oop #solid-principles
#java #ооп #solid-принципы
Вопрос:
Могу ли я наследовать от класса, зная, что некоторые из его полей никогда не будут использоваться?
Допустим, у меня есть родительский класс и его дочерний подкласс:
public class Parent {
private String a;
private String b;
private String c;
...
}
public class Child extends Parent {
private String d;
...
}
Могу ли я наследовать от такого класса, зная, что в моем дочернем классе я буду использовать только поля «a», «b», «d», а поле «c» никогда не будет использоваться?
PS Не спрашивая, собирается ли компилятор жаловаться или нет. Прошу улучшить практику проектирования. Если это плохая практика, то как это исправить?
Комментарии:
1. Определите » разрешено «. Будет ли жаловаться составитель? Нет. Это плохой дизайн? ДА.
2. Могу ли я наследовать класс, зная, что некоторые из его полей никогда не будут использоваться? — вы можете наследовать от класса, даже если вы не будете использовать ни одно из его полей, вам не нужно использовать поля супертипа, если вы наследуете от него. Вы можете наследовать от типа, чтобы получить определенное поведение (наследовать и / или переопределять методы) или просто пометить свой класс как некоторый определенный тип (например, реализовать Serializable).
3. Возможно, у суперкласса должны быть геттеры и, возможно, сеттеры для частных полей. Кроме того, иногда вам не нужно явно использовать скрытые поля, чтобы они понадобились.
Ответ №1:
Вы задаете неправильный вопрос. Проблема может быть, а может и не быть, но фокусироваться на данных, содержащихся в классах, неправильно. Вы должны сосредоточиться на их поведении.
В своем программном выступлении «Абстракция данных и иерархия» Барбара Лисков представила то, что обычно известно как принцип подстановки Лискова, расширенный в статье «Поведенческое понятие подтипирования» Лискова и Жаннет Винг. Идея заключается в том, что один тип является подтипом другого, если подтип может заменить супертип везде в программе, не влияя на ее корректность; то есть, не нарушая ее.
Что произойдет, если все Parent
экземпляры в вашей программе будут заменены на Child
экземпляры? Может ли дочерний элемент делать все, что делает родитель? Поддерживает ли оно те же операции? Даст ли это те же результаты?
Если ответ на этот вопрос положительный, то Child
это подтип Parent
. Если ответ на это отрицательный, то это не так, и оно не должно быть его подклассом. Является ли поле c
релевантным, полностью зависит от того, как оно используется.
Комментарии:
1. если я заменю родительское на дочернее, оно будет работать просто отлично. дело в том, что всякий раз, когда я использую дочерний класс, поле «c» никогда не требуется.
2. @syd Да, я понял это из вашего вопроса. Если поведение не меняется, то дочерний класс является подтипом родительского класса в соответствии с Принципом подстановки Лискова.
3. что означает, что я могу наследовать от родительского класса?
4. @syd Да, это так.
Ответ №2:
Если ваш родительский класс допускает расширение, а дочернему классу не требуется вся информация, которую предоставляет его родительский класс, то вероятно, что ваш родительский класс выполняет слишком много и его можно разделить на разные классы.
После того, как вы выполнили этот рефакторинг, вы можете расширить класс, который лучше соответствует желаемому поведению.
Комментарии:
1. класс нельзя разделить на два, все поля представляют его сущность. Я предполагаю, что в этом случае мой дочерний класс не проходит тест «is-a», потому что это поле «c» к нему неприменимо.
Ответ №3:
Вот пример разделения Parent
класса.
class AB {
Object a;
Object b;
}
class ABC extends AB {
Object c;
}
class ABD extends AB {
Object d;
}
Наследование — плохой инструмент для повторного использования кода, поэтому вы можете вместо этого рассмотреть композицию, если эти классы не имеют общего поведения.
class AB {
Object a;
Object b;
}
class ABC {
AB ab;
Object c;
}
class ABD {
AB ab;
Object d;
}
Комментарии:
1. я тоже думал об этом, но мне кажется, что это слишком много. По сути, при таком подходе вы можете создавать новый дочерний класс для каждого нового поля, которое там есть.
2. Предположительно, это новое (уникальное) поле имеет новое (уникальное) поведение при его использовании. Идея ООП заключается в том, чтобы инкапсулировать независимое поведение вместе с необходимыми данными в объект. Теоретически это может означать один метод и одно поле для каждого класса; но на практике все вряд ли будет настолько единообразно. Если случается так, что вы можете аккуратно разделить свой домен на небольшие объекты, вам либо очень повезло, либо вы очень хороши в OO-дизайне.