3

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

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

  • Давайте начнём с того, что вы ответила для чего вам публичное поле, какую задачу оно решает? – Андрей NOP Dec 28 '19 at 18:24
  • Если подразумевается всегда, то это предрассудки и догматизм. Все зависит от смысла полей. Если поле относится к "внутренностям" алгоритмов, реализуемых методами класса, то лучше его делать private и таким образом не загружать пользователей класса лишними деталями. В остальных случаях public может быть лучшим (с т.з. сопровождения программ) решением – avp Dec 28 '19 at 18:28
  • 1
    А потом почитайте ещё это: https://ru.stackoverflow.com/a/197075/218063 в других языках, конечно, свойств может не быть, но там все равно не делают поле публичным, а делают метод или пару для доступа к полю – Андрей NOP Dec 28 '19 at 18:28

3 Answers3

9

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

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

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

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), должно иметь отношение больше к назначению класса, чем быть деталью его реализации. Например, если ваш класс отсылает электронную почту, вы должны опубликовать методы для отправки письма (чтобы этим классом могли пользоваться клиенты), но не должны опубликовывать информацию, как именно ваш класс выполняет отсылку писем (чтобы клиенты не оглядывались на вашу реализацию). В этом случае, вы будете иметь возможность переписать реализацию вашего класса, не сломав обратную совместимость.
tym32167
  • 32,857
  • Хм.. Оказывается вопрос про private vs public, а я думал, что про public int Smth; vs public int Smth { get; set; }. – Qwertiy Dec 29 '19 at 00:31
  • Ну, этот вопрос из той же оперы. Тоже тесно связан с инкапсуляцией и обратной совместимостью. – tym32167 Dec 29 '19 at 00:59
  • Ну, бинарная совместимость нужна только библиотекам, на практике обычно перекомпилируется весь проект целиком. А на уровне кода они совместимы за исключением out-параметров (хотя, VB.NET вроде и их умел, странно что в шарпе не сделали). – Qwertiy Dec 29 '19 at 01:26
  • Точно, VB.NET может: https://dotnetfiddle.net/sqioMh – Qwertiy Dec 29 '19 at 01:33
  • Ну все таки поле и свойство - это разные вещи. С точки зрения назначения, безопасности, контроля, валидации и даже рефлексии. – tym32167 Dec 29 '19 at 01:38
2
  1. Не переменных, а полей.
  2. В большинстве случаев ничем, просто так принято.
  3. В интерфейсах нельзя перечислять поля, только свойства.
  4. Некоторые библиотеки, работающие с объектами через рефлексию, не любят поля.
  5. Если вдруг захочется прикрутить валидацию, а у тебя ddl, то прогу, которая её использует, придётся перекомпилировать.
Qwertiy
  • 123,725
2

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

AseN
  • 13,629
  • Хм.. Ты как и @tym32167 отвечал про приватность? Только я что ли подумал про поля и свойства? – Qwertiy Dec 29 '19 at 00:32
  • Qwertiy, ага, про инкапсуляцию. Но "поля и свойства" тоже отвечают на вопрос ТС – AseN Dec 29 '19 at 10:18