Что лучше - virtual или final по умолчанию


8 0

Такие языки как Java (как я понял Ruby on Rails тоже сюда относится) делают все методы по умолчанию виртуальными. Это значит, что любой наследник может переопределить любой метод, если явно не написано ключевое слово final. В C# наоборот, все методы по умолчанию final и если ты хочешь переопределение, то должен явно указать у предка слово virtual. 

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

В данном случае я сторонник подхода Microsoft и считаю его правильным. Закрывать все по умолчанию соответствует банальным требованиям безопасности - должно быть запрещено все, что явно не разрешено. Открытость Java - это хорошо, но открытость и безопасность - разные вещи. 

Переопределение действия методов - очень мощная возможность ООП, но это может нарушить работу класса и сделать поведение объекта неверным. Не думаю, что программисты Java при создании классов думают о том, что произойдет если наследник неверно переопределит метод. Скорей всего все методы оставляют по умолчанию с мыслью - а вдруг понадобиться переопределять. 

В C# у меня все закрыто и в тех случаях, когда нужно переопределять что-то, компилятор подсказывает, что метод у предка не виртуальный и если я на самом деле хочу написать что-то новое, то должен пойти и сделать его виртуальным явно. 

Тут возникает неудобство - а что если предок написан не мной, находится в скомпилированной библиотеке и у меня нет доступа к исходнику? Отличный вопрос - если программист явно не сделал возможность переопределения, значит я не должен туда лезть. Безопасность! Все классы должны работать без вмешательства из вне. 

Не смотря на то, что Microsoft дольше предпочитает в своих библиотеках наследования, я боле сторонник композиции, которая есть в библиотеках Apple. У низ нет такого крутого дерева наследования, максимальный уровень наверно 4. Для этого просто нужно больше использовать паттерны программирования. Переопределения как раз и приводят к тому, что появляются огромные деревья наследования, которые выходят из под контроля. 


Понравилось? Кликни Лайк, чтобы я знал, какой контент более интересен читателям. Заметку пока еще никто не лайкал и ты можешь быть первым


Комментарии

Максим

08 Марта 2015

Михаил, согласен с тобой полностью!


severvam

09 Марта 2015

Я согласен что подход MS правильнее в теории. И лучше использовать композицию вместо наследования. Но на практике мы имеем то что имеем и в этой ситуации подход Java с виртуальными по дефолту работает лучше. Мы сами создаем себе проблемы и потом героически их решаем =))


Radekk

09 Марта 2015

-> я боле сторонник композиции, которая есть в библиотеках Apple.

Михаил,  а можно поподробнее, а то не совсем понятно про \"композиции\".


urumchic

09 Марта 2015

я боле сторонник композиции, которая есть в библиотеках Apple. У низ нет такого крутого дерева наследования, максимальный уровень наверно 4. Для этого просто нужно больше использовать паттерны программирования.

Можно конкретный пример?


Михаил Фленов

09 Марта 2015

Композиция, еще известна как агрегирование - вместо наследования класса, ты включаешь его как свойство и используешь функции. https://ru.wikipedia.org/wiki/Агрегирование_(программирование)

Это не исключает наследование, которое все еще необходимо, просто наследовать нужно там, где это действительно нужно.


Михаил Фленов

09 Марта 2015

Но на практике мы имеем то что имеем и в этой ситуации подход Java с виртуальными по дефолту работает лучше.


А можно определение слову "лучше". В чем именно? У меня в .NET нет проблем с подходом MS, потому что переопределять приходится очень редко, а когда это нужно, все делается очень легко. В моем случае "лучше" как раз то, что я никогда не забуду закрыть те методы, которые не были предопределены и не должны быть, потому что они уже закрыты.


Spider_NET

09 Марта 2015

Достаточно старый холивар. Помню обсуждали его еще по статье в журнале ИТ-Спец. Я за вариант от Microsoft. Всегда придерживаюсь логики: сначала все закрываем, а потом выставляем разрешения


Andrey

12 Марта 2015

Джошуа Блох в своей "Эффективной Джаве" (must read для всех шарпистов кстати) рекомендует запрещать наследование (делать классы финальными) либо заранее тщательно проектировать наследование.
Мартин Фаулер в своем "чистом коде" также придерживается мнения, что композиция лучше наследования.
Так что если бизнес-модель не иерархическая, я закрываю классы и делаю композицию при расширении.


Добавить Комментарий

Еще что-нибудь

Хотите найти еще что-то интересное почитать? Можно попробовать отфильтровать заметки на блоге по категориям.

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне