Я читал эту страницу о том, когда геттеры / сеттеры оправданы, и ОП дал следующий пример кода:
class Fridge
{
int cheese;
void set_cheese(int _cheese) { cheese = _cheese; }
int get_cheese() { return cheese; }
}
void go_shopping(Fridge fridge)
{
fridge.set_cheese(fridge.get_cheese() + 5);
}
В признанных ответ гласит:
Кстати, в вашем примере, я дал бы класс и методы, вместо и . Тогда у вас все равно будет инкапсуляция.
Fridge
putCheese()
takeCheese()
get_cheese()
set_cheese()
Как сохраняется инкапсуляция, переименовывая ее из get / set в putCheese()
/ takeCheese()
Вы очевидно получаете / устанавливаете значение, так почему бы просто не оставить его как get / set?
В том же ответе также говорится:
Наличие геттеров и сеттеров само по себе не нарушает инкапсуляцию. Что нарушает инкапсуляцию, так это автоматическое добавление метода получения и установки для каждого элемента данных (каждое поле в языке Java), не задумываясь об этом.
В этом случае у нас есть только одна переменная, cheese
и вы можете захотеть взять и вернуть сыр в холодильник, поэтому пара get / set в этом случае оправдана.
источник
putCheese
добавил бы сыр в холодильник иtakeCheese
удалил бы его - это доменные абстракции (более высокого уровня), а не получатели и установщики поля объекта (которые являются (низкоуровневыми) абстракциями компьютерного программирования).Ответы:
Я думаю, что вы упускаете суть. Нельзя сказать, что вы должны переименовать сеттер и геттер, но есть методы, которые добавляют и удаляют элементы из холодильника. т.е.
Теперь приватная переменная инкапсулирована. Я не могу просто установить все, что захочу, я могу только добавлять и удалять кусочки сыра из холодильника, используя методы, которые, в свою очередь, гарантируют, что применяются любые правила бизнес-логики сыра, которые я хочу.
источник
setCheese()
есть с той же логикой в сеттере. В любом случае, вы пытаетесь скрыть тот факт, что вы используете сеттер, переименовывая метод, но вы явно что-то получаете / устанавливаете.AddCheese(Integer.MAX_VALUE)
, произойдет сбой, но не будет.Получатели и установщики нарушают инкапсуляцию каждый раз по определению. Что может утверждать, что иногда мы должны сделать это. С этим из пути, вот мои ответы:
Разница заключается в семантике, то есть в значении того, что вы пишете. Инкапсуляция - это не только защита, но и сокрытие внутреннего состояния. Внутреннее состояние даже не должно быть известно извне, вместо этого предполагается, что объект предлагает бизнес-релевантные методы (иногда называемые «поведением») для манипулирования / использования этого состояния.
Так
get
иset
технические термины , и , кажется , не имеют ничего общего с «холодильником» области, в то время какput
и ,take
возможно , на самом деле какой - то смысл.Однако , независимо от того
put
илиtake
сделать фактический смысл все еще зависит от требований и не может быть объективно оценен. Смотрите следующий пункт:Это не может быть объективно определено без большего контекста. Ваш пример содержит
go_shopping()
метод где-то еще. Если это то,Fridge
для чего это нужно , то в чем оно не нуждаетсяget
илиset
, в чем оно нуждаетсяFridge.go_shopping()
. Таким образом, у вас есть метод, основанный на требованиях, все необходимые ему данные являются локальными, и у вас есть реальное поведение, а не просто завуалированная структура данных.Помните, вы не строите универсальный, многоразового использования
Fridge
. Вы строите толькоFridge
для своих требований. Любые усилия, потраченные на то, чтобы сделать его больше, чем нужно, на самом деле расточительныисточник
Getters and setters break encapsulation every single time
- Это слишком сильно сформулировано на мой вкус. Методы (включая геттеры и сеттеры) имеют ту же цель, что и ворота на концерте: они позволяют упорядоченно входить и выходить из зала.public int getFoo()
практически, практически невозможно перейти на другой тип.Почти все это показывает фундаментальное неправильное понимание инкапсуляции и того, как она применяется.
Первоначальный ответ, что вы нарушали инкапсуляцию, просто неверен. Вашему приложению может потребоваться просто установить значение сыра в холодильнике вместо увеличения / уменьшения или добавления / удаления. Кроме того, это не семантика, независимо от того, как вы ее называете, если вам нужно получить доступ и / или изменить атрибуты, вы не нарушаете инкапсуляцию, предоставляя их. Наконец, инкапсуляция на самом деле не о «сокрытии», а об управлении доступом к состоянию и значениям, которые не должны быть открытыми или управляемыми вне класса, при этом предоставляя их тем, кто должен, и выполняя задачу, доступную внутри.
Метод получения или установки не нарушает инкапсуляцию, когда есть законная необходимость получить или установить значение. Вот почему методы могут быть обнародованы.
Инкапсуляция - это хранение данных и методов, которые изменяют эти данные непосредственно в одном логическом месте, классе.
В этом конкретном случае явно необходимо изменить стоимость сыра в приложении. Независимо от того, как это делается, через get / set или add / remove, при условии, что методы инкапсулированы в классе, вы следуете объектно-ориентированному стилю.
Для пояснения я приведу пример того, как нарушается инкапсуляция, предоставляя доступ независимо от имени метода или логического выполнения.
Скажем, у вашего холодильника есть «срок службы», просто несколько тиков, прежде чем холодильник перестанет работать (ради аргумента, холодильник не может быть отремонтирован). По логике вещей, пользователь (или остальная часть вашего приложения) не сможет изменить это значение. Это должно быть частным. Он будет виден только через другой открытый атрибут, известный как isWorking. Когда время жизни истекает, внутренне холодильник устанавливает isWorking в false.
Выполнение обратного отсчета времени жизни и переключение переключателя isWorking - все это происходит внутри холодильника, ничто снаружи не может / не может повлиять на процесс. isWorking должен быть только видимым, поэтому получатель не нарушает инкапсуляцию. Однако добавление методов доступа к элементам процесса жизни нарушит вашу инкапсуляцию.
Как и большинство вещей, определение инкапсуляции не буквальное, а относительное. Должны ли вы видеть Х вне класса? Должны ли вы быть в состоянии изменить Y? Все ли это относится к вашему объекту здесь, в этом классе, или функциональность распространяется на несколько классов?
источник
Это не просто переименование метода. Два метода работают по-разному.
(Представьте себе это в уме)
get_cheese и set_cheese выставляют сыр. putCheese () и takeCheese () скрывают сыр, заботятся об управлении им и дают пользователю возможность обрабатывать его. Наблюдатель не видит сыр, он видит только два метода манипулирования им.
источник