Чем плоха публичность переменных в ООП?

161
30 января 2022, 04:20

Я работаю на C#, но полагаю, это касается любого языка использующий объектно - ориентированную парадигму.

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

Answer 1

Это называется инкапсуляция.

Каждый созданный класс должен служить какой то цели. Все публичные члены класса должны быть предназначаны для взаимодействия этого класса с внешним миром (с клиентами класса). Если у вас есть какие то поля\свойства\методы, которые являются публичными, но не предназначены для того, чтобы ими пользовались извне класса, то у такого класса явно проблемы. Особенно, если такие члены класса меняют его состояние, так как, получается, клиенты класса могут использовать класс не только так, как было предназначенно разработчиком класса.

Приведем небольшой пример. Допустим, мы пишем класс для вывода в консоль.

public class ConsoleLogger 
{
    private TextWriter _writer;
    public ConsoleLogger()
    {
        _writer = Console.Out;
    }
    public void WriteLine(string message)
    {
        _writer.WriteLine(message);     
    }
}

Мы видим, что у нас есть скрытое поле писателя, мы его используем для вывода. Поле скрытое, публичные только конструктор и один метод для записи. Единственный путь для клиента использовать наш класс, это

var logger = new ConsoleLogger();
logger.WriteLine("hello");

Теперь сделаем публичным.

public class ConsoleLogger 
{
    public TextWriter _writer;
    public ConsoleLogger()
    {
        _writer = Console.Out;
    }
    public void WriteLine(string message)
    {
        _writer.WriteLine(message);     
    }
}

После этого мы больше не контроллируем наш класс. Клиент может писать в поле писателя все, что ему вздумается. Например

var logger = new ConsoleLogger();
logger._writer = null;
logger.WriteLine("hello"); // ошибка!

Более того, после релиза такого кода, мы уже не можем спрятать поле обратно а приватные поля, не потеряв обратную совместимость с уже существующими клиентами, котоые используют это поле.

При этом обратное направление работает. То есть сделать публичное приватным - это означает потерю совместимости. Но сделать приватное публичным - это будет означать просто дополнительный функционал. Например, если у нас есть такой код

public class ConsoleLogger
{
    public TextWriter _writer;
    public ConsoleLogger()
    {
        _writer = Console.Out;
    }
    public void WriteLine(string message)
    {
        _writer.WriteLine(message);
    }
    private void Write(string message)
    {
        _writer.Write(message);
    }
}

Как видите, тут есть приватный метод Write и публичное поле _writer. Если сделать поле _writer обратно приватным, то код клиента, что мы уже написали, перестанет компилироваться

var logger = new ConsoleLogger();
//logger._writer = null; -- не компилируется
logger.WriteLine("hello");

Но если сделать приватный Write метод публичным, не сломается ровным счетом ничего.

Отсюда выводы:

  1. по умолчанию делайте в ваших классах все приватным. Вы должны иметь вескую причину, чтобы что то сделать публичным (или защищенным), так как обратной дороги в приватность для публичных членов часто нет.
  2. чтобы иметь причину сделать что то публичным у класса, это чтото (поле\метод\etc), должно иметь отношение больше к назначению класса, чем быть деталью его реализации. Например, если ваш класс отсылает электронную почту, вы должны опубликовать методы для отправки письма (чтобы этим классом могли пользоваться клиенты), но не должны опубликовывать информацию, как именно ваш класс выполняет отсылку писем (чтобы клиенты не оглядывались на вашу реализацию). В этом случае, вы будете иметь возможность переписать реализацию вашего класса, не сломав обратную совместимость.
Answer 2

Если кратко - пропадает возможность взаимодействовать с классом, как с "черным ящиком", и ящик становится трудно заменяемым (как деталь в сложном механизме). Публичные переменные уничтожают контракт взаимодействия с мнимым "черным ящиком".

Answer 3
  1. Не переменных, а полей.
  2. В большинстве случаев ничем, просто так принято.
  3. В интерфейсах нельзя перечислять поля, только свойства.
  4. Некоторые библиотеки, работающие с объектами через рефлексию, не любят поля.
  5. Если вдруг захочется прикрутить валидацию, а у тебя ddl, то прогу, которая её использует, придётся перекомпилировать.
READ ALSO
Событие на нарисованный объект c#

Событие на нарисованный объект c#

Есть класс Circle, который рисует окружности заданного размераЯ попытался сделать событие на клик мыши, которое показывало бы информацию по данному...

88
Функция в Unity наподобие SetInterval из JavaScript

Функция в Unity наподобие SetInterval из JavaScript

Нужно вызывать функцию каждый определённый n-ый промежуток времени

173
Поиск данных через RowFilter в dataGridView по всем столбцам

Поиск данных через RowFilter в dataGridView по всем столбцам

Есть таблица authors со столбцами fio, count, urlВсе данные загружаются в datagridview (столбец с ID тоже, но он не отображается на форме)

106
Ошибка авторизации

Ошибка авторизации

Подскажите пожалуйста, почему я получаю сообщение об ошибке когда на моём компьютере нету пользователя, которым я пытаюсь пройти удалённую...

123