Ну, почему они это делают, потому что они просто для этого. Я думаю, возможно, вы задаетесь вопросом, почему кто-то может захотеть. Простой ответ заключается в том, что производные классы должны иметь к ним доступ, а внешние классы - нет.
Модификаторы доступа (а также public
и protected
, существует private
, internal
и protected internal
) - это средства, позволяющие сделать код максимально понятным и уменьшить количество ошибок.
Существуют языки без какой-либо формы инкапсуляции. В крайнем случае, любой код может изменить любую часть любых данных. Дисциплинированный кодер уменьшит количество мест, которыми манипулирует данный тип данных, но все еще может быть неочевидным все комбинации операций, которые могут оставлять объекты * в разных состояниях. Ситуация ухудшается, когда их код используется как часть чужого кода.
Модификаторы доступа помогают нам справиться с этим. По умолчанию у нас есть личные участники. Тогда единственные места, к которым член может получить доступ, находятся внутри самого класса. Это значит:
- Единственная ошибка в том, как ими можно манипулировать, находится внутри класса.
- Единственный код, который должен заботиться о поддержании этих членов в согласованном состоянии, находится внутри класса, и этот код не должен беспокоиться о возможности другого кода, нарушающего это.
- Вы можете получить полное представление обо всех способах манипулирования этими полями, взглянув на определение одного класса, которое обычно содержится в одном файле и редко более чем в двух.
Это значительно облегчает нам кодирование.
Конечно, класс, где все приватно, не очень полезен. Мы обычно должны позволить некоторым членам быть публичными. Обычно у нас есть поля приватные, некоторые полезные методы приватные, а затем некоторые открытые методы и свойства используют их. Мы все еще можем исследовать все возможные манипуляции с закрытыми членами, изучая только этот один класс, хотя мы открыли вызов членов, которые делают это с другими классами. Таким образом, эти члены предоставляют нам интерфейс между кодом внутри и снаружи класса, границу, через которую мы защищаем состояние класса от ошибок, обеспечивая при этом полезную функциональность для другого кода.
К настоящему времени должно быть ясно, что мы не делаем ничего публичного, если только нам это не нужно, но нам нужно, чтобы полезная работа была возможной.
Создание защищенного члена дает нам золотую середину. Мы все еще сокращаем места, которыми можно манипулировать, но не так сильно. Как правило, это делается для того, чтобы производный класс мог предоставить собственный механизм для общего интерфейса, определенного в базе.
Меньше случаев, когда он используется, потому что обычно мы либо можем держать вещи в секрете - что безопаснее - либо должны быть публичными, чтобы быть полезными. Одним из наиболее распространенных случаев является то, что открытые члены предоставляют функциональность и защищенные средства определения для ее реализации. Например, HttpEncoder
предоставляет несколько методов для решения проблемы кодирования строк для HTML, но есть два защищенных абстрактных метода, которые переопределяют производные классы, чтобы обеспечить функциональность, общую для нескольких различных методов. Внешние классы не нуждаются в доступе к ним, но производные классы делают это.
Практический пример. Скажем, у нас есть базовый класс, который реализует INotifyPropertyChanging
. Этот интерфейс означает, что он должен отслеживать обработчики PropertyChangingEventHandler
и вызывать события, когда свойство собирается измениться.
Мы не хотим, чтобы внешние классы вызывали это событие, потому что это не их дело, и их получение просто приведет к ошибкам.
Мы должны позволить производным классам делать это, потому что они могут определять свои собственные свойства, о которых базовый класс не знает.
Поэтому мы определяем защищенный метод в этом базовом классе, который вызывает событие. Внешние классы не могут вызывать его (уменьшен риск неправильного вызова), но производные классы могут (способность выполнять работу, в которой они нуждаются).
* Люди из объектно-ориентированного фона могут даже не считать такие фрагменты данных «объектами».