Недавно мне пришлось обновить абстрактный базовый класс на некоторых OSS, которые я использовал, чтобы он был более тестируемым, сделав их виртуальными (я не мог использовать интерфейс, так как он объединял два). Это заставило меня задуматься о том, должен ли я отмечать все методы, которые мне нужны, как виртуальные, или я должен отмечать все открытые методы / свойства как виртуальные. Я в целом согласен с Роем Ошеровом, что каждый метод должен быть виртуальным, но я наткнулся на эту статью, которая заставила меня задуматься о том, было ли это необходимо или нет . Однако я собираюсь ограничить это абстрактными классами для простоты (особенно сомнительно, должны ли все конкретные публичные методы быть виртуальными).
Я мог видеть, где вы можете разрешить подклассу использовать метод, но не хотите, чтобы он переопределял реализацию. Однако, если вы уверены, что принцип замены Лискова будет соблюдаться, то почему бы вам не допустить его отмены? Помечая его как абстрактный, вы в любом случае вызываете определенное переопределение, поэтому мне кажется, что все открытые методы внутри абстрактного класса действительно должны быть помечены как виртуальные.
Тем не менее, я хотел спросить, есть ли что-то, о чем я не думаю. Должны ли все открытые методы в абстрактном классе быть виртуальными?
источник
Ответы:
Например, потому что я хочу, чтобы каркасная реализация алгоритма была фиксированной, и позволяла (пере) определять только определенные части подклассами. Это широко известно как шаблонный метод (выделено мной ниже):
Обновить
Некоторые конкретные примеры проектов, над которыми я работал:
В первых двух случаях первоначальная унаследованная реализация использовала стратегию , в результате чего появилось много дублирующегося кода, который, разумеется, с годами увеличивал тонкие различия здесь и там, содержал множество дублированных или слегка отличающихся ошибок, и их было очень трудно поддерживать. Рефакторинг к Template Method (и некоторым другим улучшениям, таким как использование аннотаций Java) уменьшил размер кода примерно на 40-70%.
Это только самые последние примеры, которые приходят мне в голову. Я мог бы привести больше примеров из почти каждого проекта, над которым я до сих пор работал.
источник
Вполне разумно, а иногда желательно иметь не виртуальные методы в абстрактном базовом классе; просто потому, что это абстрактный класс, не обязательно означает, что каждая его часть должна использоваться полиморфно.
Например, вы можете использовать идиому «Не виртуальный полиморфизм», при котором функция вызывается полиморфно из не виртуальной функции-члена, чтобы гарантировать выполнение определенных предварительных условий или постусловий до вызова виртуальной функции.
источник
Достаточно, чтобы класс содержал ОДИН виртуальный метод, чтобы класс стал абстрактным. Возможно, вы захотите обратить внимание на то, какие методы вы хотите использовать виртуальные, а какие нет, в зависимости от типа полиморфизма, который вы планируете использовать.
источник
Спросите себя, какой смысл использовать не виртуальный метод в абстрактном классе. Такой метод должен иметь реализацию, чтобы сделать его полезным. Но если у класса есть реализация, может ли он все еще называться абстрактным классом? Даже если язык / компилятор это позволяет, имеет ли это смысл? Лично я так не думаю. У вас будет нормальный класс с абстрактными методами, которые потомки должны реализовать.
Мой основной язык Delphi, а не C #. В Delphi, если вы помечаете метод как абстрактный, вы также должны пометить его как виртуальный, иначе компилятор пожалуется. Я не следил за последними изменениями языка слишком внимательно, но если абстрактные классы находятся или придут в Delphi, я ожидаю, что компилятор будет жаловаться на любые не виртуальные методы, любые частные методы и на любые реализации методов для класса, помеченного как абстрактный на уровне класса.
источник
abstract
, вы также должны пометить весь классabstract
.Вы не делаете некоторые методы виртуальными, потому что не считаете, что это так. Кроме того, делая определенные методы не виртуальными, вы даете понять наследникам, какой метод (ы) должен быть реализован.
Лично я часто делаю перегрузки методов, которые существуют для удобства, а не виртуальные, чтобы пользователи класса могли иметь непротиворечивые значения по умолчанию, а разработчики даже не могли сделать ошибку, нарушая это подразумеваемое поведение.
источник