Мартин Фаулер говорит о двух подходах к проектированию наследования: четкая спецификация того, что можно наследовать из класса с запрещением остального, либо свободное разрешение делать с базовым классом все, что позволяет язык (в соответствии с "разрешающей позицией").
Свободный подход ругают за то, что наследник может сломать поведение самого базового класса, если перекрытых методах не сделает каких-то обязательных вещей, на которые расчитывает остальной код класса.
Для оформления более строго наследования в языках, где есть скрытие данных (Delphi, C++, Java), широко применяется паттерн "Template Method" (из книжки "Design Patterns", которую должен прочитать каждый объектно-ориентированный программист). По этому паттерну поведение объекта оформляется невиртуальными публичными методами, которые сами по себе не перекрываются. А уже внутри такого метода выполняются как обязательные куски, так и вызываются виртуальные методы, которые можно наследовать.
TDocument=class
Private
Procedure Backup;
Protected
Procedure DoSaveData; Virtual;
Public
Procedure Save;
end;
Procedure TDocument.Save;
Begin
Backup;
DoSaveData; { Перекрывая этот метод, наследник не сможет забыть
вызвать Backup }
End;
Основной минус строго подхода в том, что при создании базового класса программисту нужно как-то предвидеть все возможные способы использования класса в будущем. И если она их не смогла все предвидеть, то тот, кому этот непредвиденный способ понадобится, будет, что называется, "outta business". Хотя, конечно, если они в одной команде или это один человек, то можно и базовый класс переписать...
В принципе, есть соглашение, что методы названные с одного подчерка — это внутреннее дело класса, и если вы их используете, то надо быть готовым к тому, что оно может и сломаться. Но это аналог скорее private
, чем protected
. Потому что protected
— это скорее "вот это удобнее использовать при наследовании". И вот этого — не хватает.
Комментарии: 6
Мне кажется, это задача разработчика, следить за тем, какие методы можно перекрывать и как это нужно делать. Конечно, для этого нужно хорошо ориентироваться в коде наследуемого класса, но Питон это такой язык, который позволяет держать в голове большой объем кода (а точнее знаний, о том, как этот код работает) из разных классов. Хаки типа _ это дополнительная подсказка, хороший тон при разработке. И этого, мне кажется, вполне достаточно.
Я, когда перекрываю метод, как правило делаю так:
То есть первое, что я делаю в "перекрываемом" методе, это вызываю этот метод в том виде, как он описан в наследуемом классе. Однако это не избавляет меня от необходимости заглянуть к код наследуемого класса, потому что мне нужно знать, какие аргументы этому методу надо передать.
Вообще, я без стеснения перекрываю методы типа
__init__
или__del__
, если это необходимо. В конце-концов это МОЙ класс, пусть даже он унаследован от "чужого" :)) Главное, это понимать, что ты делаешь.Иван, а почему "она [...] не смогла"?
Откуда там женский род?
Почему бы и не женский? :-) Вполне возможно, что этот гипотетический программист — девушка.
Которого разработчика? Который базовый класс пишет или который наследует? :-)
Я думаю, это все же не повод злоупотреблять его читаемостью. Чем меньше пользователю класса (или любого кода) приходится вникать в детали его реализации, тем больше времени и сил он потратит на свою задачу. А для этого нужны средства, как жестко зашитые в язык, так и соглашения. О чем, я, собственно, и хотел написать.
Иван для сокрытия функциональности я использовал несколько раз mxProxy. Задача правда немного отличается от вашей (получить аналог protected), но зато если хотите скрыть функциональность(аналог private), то он подошол мне неплохо.
А с другой стороны гибкость Питона это обоюдоострое лезвие, одним давай быстрое прототипирование, а другим сверхнадёжный софт, увы но усидеть на двух стульях сразу вряд ли получится.
Меня, честно говоря, сам аспект скрытия и вытекающая из него надежность не очень беспокоит. Мне хочется именно простого механизма документирования намерений.