Подтвердить что ты не робот

Инкапсуляция - зачем нам это нужно, когда сеттеры уже открыты?

Инкапсуляция скрывает данные. Я хотел бы услышать некоторые действительно интересные ответы здесь.

В чем смысл сохранения переменных как private, когда мы уже объявляем public методы setter для переменных.

Я понимаю использование инкапсуляции, но когда мы создаем сеттеры как общедоступные, что заставляет поддерживать переменные как private, мы можем напрямую использовать модификаторы доступа public

Это потому, что мы не хотим, чтобы другие знали точный способ хранения данных или управления данными на внутреннем сервере?

4b9b3361

Ответ 1

Это потому, что мы не хотим, чтобы другие знали точный способ, которым мы являемся хранения данных или управления данными на внутреннем сервере?

Да, это точка. Это связано с концепциями абстракции и скрытия информации.

Вы предоставляете публичный сеттер, который при вызове клиентом класса будет иметь эффект, который вы документировали. Это не бизнес-клиент, как этот эффект действительно достигается. Вы изменяете один из атрибутов класса? Хорошо, пусть клиент это знает, но не факт, что вы на самом деле изменяете переменную. В будущем вы можете захотеть изменить свой класс, чтобы вместо простой переменной резервного копирования он использовал нечто совершенно другое (словарь атрибутов? Внешняя служба? Что бы ни было!), И клиент не сломается.

Итак, ваш сеттер - это абстракция, которую вы предоставляете клиенту для "модификации этого атрибута класса". В то же время вы скрываете, что используете внутреннюю переменную, потому что клиенту не нужно знать этот факт.

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

Ответ 2

Я полностью согласен с ответом Konamiman, но я хотел бы добавить одну вещь:

Есть случаи, когда вы действительно не хотите эту абстракцию. И это прекрасно.

Простым примером, который я хотел бы использовать здесь, является класс для 3-мерного вектора float:

class Vector3f {
public:
    float x;
    float y;
    float z;
};

Не могли бы вы сделать эти поля частными и предоставить сеттеры вместо этого? Конечно, можно. Но здесь вы можете утверждать, что класс действительно должен обеспечивать кортеж поплавков, и вы не хотите никаких дополнительных функций. Таким образом, добавление сеттеров только усложнит класс, и вы предпочтете оставить поля общедоступными.

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

Это ваш вызов как программист, чтобы решить, какие абстракции имеют смысл для проблемы, и какие из них будут только мешать выполнить работу. Ненужные абстракции over-engineering и повредят вашей производительности так же сильно, как абстрагирование.

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

Ответ 3

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

String username; 

public void setUsername(String username){
this.username = username;
}

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

Ответ 4

Хотя Konamiman ответ, я бы хотел добавить, что в в частном случае публичных установщиков, а не непосредственно выставляя публичные поля, которые вы задаете, существует еще одно очень важное различие, которое следует учитывать, кроме того, что скрытие и развязка информации с публичной поверхности или API класса; Проверка.

В сценарии открытого поля невозможно изменить значение поля при его изменении. В случае публичного сеттера (будь то свойство Foo {get; set;} или SetFoo(Foo value)) у вас есть возможность добавить код проверки и запустить необходимые побочные эффекты, и таким образом убедитесь, что ваш класс всегда находится в допустимом или предсказуемом состоянии.

Ответ 5

Подумайте об этом: я представляю объект реальной жизни, лев через класс. Я бы сделал что-то подобное.

class Lion {
    public int legs;
} 

Теперь мой класс необходим другому разработчику для создания объекта и установки его поля ног. Он сделал бы что-то вроде этого

Lion jungleKing = new Lion();
jungleKing.legs=15;

Теперь вопрос в том, что Java не будет ограничивать его установкой любого числа более 4 в качестве количества ног для этого объекта. Это не ошибка, и все будет нормально. Но это логичная ошибка, и компилятор вам не поможет. Таким образом, у Льва может быть любое количество ног. Но если мы напишем код таким образом

class Lion {
    private int legs;
    public void setLegs(int legs){
        if(legs>4)
            this.legs=4;
        else this.legs=legs;
    } 
} 

Теперь у вас не будет льва с более чем 4 ногами, потому что политика обновления полей класса была определена самим классом, и никто из тех, кто не знает, что политика собирается обновить поле ног, не знает, потому что единственный способ обновить поле ног - через метод setLegs(), и этот метод знает политику класса.

Ответ 6

Что делать, если вы хотите проверить диапазон до назначения? В одном из случаев я использую сеттеры и геттеры

Ответ 7

Более или менее простой и реалистичный пример, с которым я столкнулся на практике, - это класс Options, который имеет множество сеттеров и геттеров. В какой-то момент вы можете добавить новую опцию, которая зависит от других или имеет побочные эффекты. Или даже замените группу опций на Enum. В этом случае функция setA не будет просто изменять поле a, но скроет некоторую дополнительную логику конфигурации. Аналогично getA не просто вернет значение a, но что-то вроде config == cStuffSupportingA.

Ответ 8

В Википедии есть хороший обзор [методов мутатора (https://en.wikipedia.org/wiki/Mutator_method), что и есть методы setter и как они работают на разных языках.

Короткий вариант: если вы хотите ввести подтверждение или другую логику, которая выполняется при изменении объекта, приятно иметь установщик, чтобы включить эту логику. Также вы можете скрыть, как вы храните вещи. Таким образом, это причины для получения геттеров/сеттеров. Аналогично, для геттеров у вас может быть логика, которая предоставляет значения или значения по умолчанию, которые зависят от, например, конфигурация для таких вещей, как Locale, кодировка символов и т.д. Существует множество веских причин, по которым нужно иметь логику, отличную от получения или установки переменной экземпляра.

Очевидно, что если у вас есть getters и setteres, вы не хотите, чтобы люди обходили их, манипулируя состоянием объекта напрямую, поэтому вы должны сохранять частные переменные экземпляра.

Другие вещи, которые следует учитывать, включают в себя: действительно ли вы хотите, чтобы ваши объекты были вообще изменены (если нет, сделайте поля окончательными), хотите ли вы изменить статус состояния потокобезопасными, например. блокировки, синхронизация и т.д.

Ответ 9

Поля полей в качестве частных документов являются важным фактом: эти частные поля используются только в текущем классе. Это помогает сопровождающим, не отслеживая использование поля. Они могут лучше рассуждать о коде, просматривая класс и определяя, что эффекты в этих областях и из этих полей с окружающей средой класса проходят через общедоступные и защищенные вызовы методов. Он ограничивает поверхность экспозиции в классе.

В свою очередь, определение "сеттера" для частного поля заключается не в том, чтобы снова дать ему гласность. Речь идет о объявлении еще одного важного факта: объект, принадлежащий этому классу, обладает свойством, которое может быть изменено извне. (Термины object и свойство используются в смысле ограниченной части целого и наблюдаемого факта об этой части, а не в смысле ООП)

Почему тогда объявить "сеттер" в поле при создании поля публичным? Поскольку Объявление поле не только связывает имя с атрибутом объектов класса, но также обязывает использовать память для этого свойства.

Поэтому, если вы объявляете "частное поле с установщиком", вы объявляете три вещи:

  • Вы объявляете, что имя, присвоенное кластеру field/setter, представляет собой свойство объекта, представляющего интерес, когда объект рассматривается как черный ящик.
  • Вы объявляете, что значение этого свойства модифицируется средой объекта.
  • Вы объявляете, что в этом конкретном конкретном классе свойство объекта реализуется путем фиксации некоторого хранилища памяти.

Я выступаю за то, чтобы вы никогда не делали ваши поля частными с геттерами и сеттерами без разбора. Поля предназначены для описания хранилища. Методы предназначены для взаимодействия с окружающей средой. (И конкретный случай "геттеров" и "сеттеров" предназначен для описания интересующих свойств)