Такие языки как Java (как я понял Ruby on Rails тоже сюда относится) делают все методы по умолчанию виртуальными. Это значит, что любой наследник может переопределить любой метод, если явно не написано ключевое слово final. В C# наоборот, все методы по умолчанию final и если ты хочешь переопределение, то должен явно указать у предка слово virtual.
Я так понял, что у обоих лагерей есть противники не сторонники и вроде бы есть какой-то халивар на эту тему? Я решил не гуглить и не искать никаких заметок, где были бы описаны недостатки или преимущества, а то можно поддаться влиянию. Вместо этого я решил написать свое мнение. Я понимаю, что здесь может начаться спор и со мной могут не согласится, а именно этого я и хочу, потому что в споре рождается истина.
В данном случае я сторонник подхода Microsoft и считаю его правильным. Закрывать все по умолчанию соответствует банальным требованиям безопасности - должно быть запрещено все, что явно не разрешено. Открытость Java - это хорошо, но открытость и безопасность - разные вещи.
Переопределение действия методов - очень мощная возможность ООП, но это может нарушить работу класса и сделать поведение объекта неверным. Не думаю, что программисты Java при создании классов думают о том, что произойдет если наследник неверно переопределит метод. Скорей всего все методы оставляют по умолчанию с мыслью - а вдруг понадобиться переопределять.
В C# у меня все закрыто и в тех случаях, когда нужно переопределять что-то, компилятор подсказывает, что метод у предка не виртуальный и если я на самом деле хочу написать что-то новое, то должен пойти и сделать его виртуальным явно.
Тут возникает неудобство - а что если предок написан не мной, находится в скомпилированной библиотеке и у меня нет доступа к исходнику? Отличный вопрос - если программист явно не сделал возможность переопределения, значит я не должен туда лезть. Безопасность! Все классы должны работать без вмешательства из вне.
Не смотря на то, что Microsoft дольше предпочитает в своих библиотеках наследования, я боле сторонник композиции, которая есть в библиотеках Apple. У низ нет такого крутого дерева наследования, максимальный уровень наверно 4. Для этого просто нужно больше использовать паттерны программирования. Переопределения как раз и приводят к тому, что появляются огромные деревья наследования, которые выходят из под контроля.
Понравилось? Кликни Лайк, чтобы я знал, какой контент более интересен читателям. Заметку пока еще никто не лайкал и ты можешь быть первым
Михаил, согласен с тобой полностью!
Я согласен что подход MS правильнее в теории. И лучше использовать композицию вместо наследования. Но на практике мы имеем то что имеем и в этой ситуации подход Java с виртуальными по дефолту работает лучше. Мы сами создаем себе проблемы и потом героически их решаем =))
-> я боле сторонник композиции, которая есть в библиотеках Apple.
Михаил, а можно поподробнее, а то не совсем понятно про \"композиции\".
Композиция, еще известна как агрегирование - вместо наследования класса, ты включаешь его как свойство и используешь функции. https://ru.wikipedia.org/wiki/Агрегирование_(программирование)
Это не исключает наследование, которое все еще необходимо, просто наследовать нужно там, где это действительно нужно.
Достаточно старый холивар. Помню обсуждали его еще по статье в журнале ИТ-Спец. Я за вариант от Microsoft. Всегда придерживаюсь логики: сначала все закрываем, а потом выставляем разрешения
Джошуа Блох в своей "Эффективной Джаве" (must read для всех шарпистов кстати) рекомендует запрещать наследование (делать классы финальными) либо заранее тщательно проектировать наследование.
Мартин Фаулер в своем "чистом коде" также придерживается мнения, что композиция лучше наследования.
Так что если бизнес-модель не иерархическая, я закрываю классы и делаю композицию при расширении.
Хотите найти еще что-то интересное почитать? Можно попробовать отфильтровать заметки на блоге по категориям.