Должны ли конструкторы соблюдать принцип замещения Лискова?

Обычно я стараюсь, чтобы экземпляры моих объектов соответствовали Liskov Substitution Principle, но я Мне всегда было интересно, думают ли люди, что LSP следует применять и к конструкторам?

Я пробовал поискать в Google по этому поводу, но так или иначе не смог найти твердого мнения.

Я должен отметить, что большая часть моего кода написана на Ruby, но иногда я обнаруживаю, что конструкторы моих подклассов немного отличаются от родительского класса. Они принимают тот же базовый набор аргументов и часто дополнительные аргументы. Иногда это также происходит с другими методами класса.

В глубине души это всегда казалось нарушением LSP, но я хотел посмотреть, чувствует ли кто-нибудь это тоже так.


person dkubb    schedule 30.03.2011    source источник
comment
Я не понимаю, почему это закрыто как основание для мнения. LSP четко сформулирован и не подлежит интерпретации.   -  person Deblaton Jean-Philippe    schedule 08.06.2018
comment
Согласен, это не должно было закрываться. Этот вопрос касается теории информатики.   -  person Neil G    schedule 08.09.2020


Ответы (3)


Нет, когда вы используете конструктор, вы знаете, что имеете дело с подтипом. Это позволяет иметь предварительные условия, которые не требуются для родительского конструктора, такие как другие параметры. Вот почему на большинстве языков имя конструктора совпадает с именем создаваемого класса.

Хороший пример того, как ColoredSquare может быть правильным подтипом Square, но требует дополнительного параметра: color. Если бы вы не могли делать что-то подобное, от подтипов было бы гораздо меньше пользы.

В некотором смысле конструктор на самом деле не является частью типа: это функция, возвращающая элемент этого типа. Таким образом, определение нового конструктора для подтипа не нарушает LSP.

person Philip JF    schedule 30.03.2011
comment
когда вы используете конструктор, вы знаете, что имеете дело с подтипом. Спасибо. Это отличный момент. - person Chance; 25.05.2011
comment
Вероятно, важно проводить различие между конструкторами, статическими фабричными методами, фабричными методами, которые являются экземплярами создаваемого типа (в первую очередь Clone), и другими фабриками. Статические фабрики могут производить различные типы объектов, производные от возвращаемого типа, но LSP должен применяться ко всем произведенным объектам; Однако не требуется, чтобы производные классы поддерживали те же статические методы, что и базовый класс. Если класс поддерживает фабричный метод, такой как Clone, следует соблюдать LSP и поддерживать аналогичную семантику в подтипах. - person supercat; 23.12.2011
comment
Для фабрик, которые возвращают вещи других типов, элемент, возвращаемый производной фабрикой, должен использоваться как экземпляр элемента, который будет возвращен из базовой фабрики. Итак, если CarFactory имеет метод MakeCar(), который возвращает Car, который, в свою очередь, поддерживает метод Drive(), можно вызвать SomeCarFactory.MakeCar().Drive(), даже если SomeCarFactory действительно FordFactory (который наследует CarFactory), который возвращает Ford (который наследует Car). - person supercat; 23.12.2011

Определенно нет.

Конструкторы обычно специализируются на подтипах. Пытаться применить LSP к конструкторам - все равно что сказать, что к подтипам нельзя добавить определенные методы или члены. Но ограничение только наоборот.

И я также согласен с Филипом, конструкторы на самом деле не являются частью типа (и на некоторых языках вы можете легко использовать другие фабрики вместо конструкторов). Используя терминологию smalltalk, можно сказать, что конструкторы - это методы метаклассов.

Здесь нет нарушения LSP, это относится только к методам экземпляра, а не к методам класса (конструкторам или любым другим методам класса).

person kriss    schedule 30.03.2011

Это своего рода самоуверенный вопрос, но я обычно пишу так, что дополнительные параметры не имеют реального отношения к изменению функциональности. Под этим я подразумеваю, что когда моему конструктору требуется дополнительный параметр в подклассе, он должен поддерживать стандартную функциональность (но делать разные базовые вещи), таким образом, я могу сказать, что я создаю ClassA = new ClassB (с некоторыми аргументами); тогда функциональность одинакова, делаю ли я это или ClassA = new ClassA (); и я обычно использую какой-то метод Factory для их создания, чтобы они работали безупречно. Опять же, это то, как я делаю что-то, и это никоим образом не является абсолютно правильным способом делать что-то.

person Jesus Ramos    schedule 30.03.2011