Если Field › CharField › EmailField, нарушает ли EmailField принцип замены Лискова с CharField?

Скажем, я пишу веб-приложение с классом Form, а класс Form может иметь несколько классов Fields.

Field сам по себе является абстрактным классом. Он содержит абстрактное свойство validators, представляющее собой список методов, которые будут вызываться для определения того, является ли содержимое поля допустимым. Эти валидаторы вызываются вызовом метода экземпляра Field.run_validators(value)

CharField — это подкласс Field, допускающий произвольный текст. Это поле всегда допустимо, пока ему задана некоторая строка ненулевой длины.

EmailField — это подкласс CharField с дополнительными требованиями. Это поле допустимо только тогда, когда value проходит ряд тестов. (например, '@' in value).

У меня вопрос: нарушает ли EmailField LSP по отношению к CharField? Должен ли это быть родственный класс? Хотя Field определяет изменчивость, позволяя подклассам предоставлять свои собственные validators, TextField явно не расширяет эту изменчивость.

Я продолжаю пытаться найти больше объяснений LSP, но все они повторно используют один и тот же пример Rectangle/Square.

Дано:

def transmogulate(field):
    """field must be a TextField instance."""
    assert isinstance(field, TextField)
    instance.run_validators("hello")

При использовании CharField transmogulate(my_text_field) будет работать без проблем. Но если my_text_field вместо этого является экземпляром EmailField, он всегда будет вызывать ValidationError. Является ли это нарушением LSP? Или мои рассуждения полностью назад? (что случается достаточно часто)

Также вы можете так же счастливо представить, что run_validators() возвращает False вместо возбуждения исключения, если это каким-то образом меняет анализ; Я просто хотел, чтобы мой пример был как можно ближе к исходному материалу.


person Dan Passaro    schedule 11.06.2013    source источник
comment
Пока это работает, кого это волнует?   -  person clavio    schedule 11.06.2013


Ответы (1)


Я думаю, что дизайн в порядке, пока EmailField предоставляет те же методы, что и CharField (что, похоже, так и есть). Он следует за LSP, если все еще крякает, как утка. Для подклассов нормально иметь разные реализации или поведение.

person bwbrowning    schedule 11.06.2013
comment
Но то же самое относится и к обычному примеру с прямоугольником/квадратом, который нарушает LSP. Square предоставляет те же методы, поэтому он по-прежнему крякает, как утка. Но он ведет себя неожиданно, что, я думаю, и приводит к нарушению LSP. - person Dan Passaro; 11.06.2013
comment
Хороший вопрос... Мне интересно услышать другие ответы на этот вопрос. Я думаю, что это немного отличается от прямоугольника/квадрата, потому что проблема с квадратом, как я понимаю, заключается в том, что setHeight и setWidth теперь делают неожиданные вещи. Однако в этом случае run_validators() по-прежнему просто сообщает нам, действительно ли это или нет, хотя и с немного другой логикой. И поскольку он работает с пользовательскими данными, я не думаю, что эта разница в поведении влияет на программиста в реальном мире. - person bwbrowning; 11.06.2013