Зачем использовать геттеры и сеттеры / средства доступа?


1544

В чем преимущество использования геттеров и сеттеров - которые только получают и устанавливают - вместо простого использования открытых полей для этих переменных?

Если геттеры и сеттеры когда-либо делают больше, чем просто получают / устанавливают, я могу понять это очень быстро, но я не на 100% уверен в том, как:

public String foo;

хуже чем:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

В то время как первый занимает гораздо меньше стандартного кода.


6
@Dean J: дублируйте многие другие вопросы: stackoverflow.com/search?q=getters+setters
Asaph

8
Конечно, оба одинаково плохи, когда объект не нуждается в изменении свойства. Я бы предпочел сделать все приватным, а затем добавить геттеры, если они полезны, и сеттеры, если это необходимо.
Tordek

26
Гугл "злоумышленники злые"
OMG Ponies

34
«Средства доступа - это зло», если вы пишете функциональный код или неизменяемые объекты. Если вы пишете изменяемые объекты с изменяемым состоянием, то они очень важны.
Кристиан Хейтер

18
Скажи, не спрашивай. pragprog.com/articles/tell-dont-ask
Дейв Джарвис,

Ответы:


982

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

Вот некоторые из причин, которые мне известны:

  • Инкапсуляция поведения, связанного с получением или установкой свойства - это позволяет более легко добавлять дополнительные функции (например, проверку) позже.
  • Скрытие внутреннего представления свойства при выставлении свойства с использованием альтернативного представления.
  • Изоляция вашего открытого интерфейса от изменений - позволяет общему интерфейсу оставаться неизменным, пока реализация меняется, не затрагивая существующих потребителей.
  • Управление семантикой свойства времени жизни и управления памятью (распоряжения) - особенно важно в неуправляемых средах памяти (таких как C ++ или Objective-C).
  • Предоставление точки перехвата отладки для случая, когда свойство изменяется во время выполнения - отладка, когда и где свойство изменилось на определенное значение, может быть довольно трудной без этого на некоторых языках.
  • Улучшенная совместимость с библиотеками, предназначенными для работы с методами получения / установки свойств - на ум приходят Mocking, Serialization и WPF.
  • Позволяет наследникам изменять семантику поведения и представления свойства путем переопределения методов получения / установки.
  • Позволяет получать / извлекать как лямбда-выражения, а не как значения.
  • Получатели и установщики могут разрешать разные уровни доступа - например, получение может быть открытым, но набор может быть защищен.

60
+1. Просто добавить: разрешить ленивую загрузку. Разрешить копирование на запись.
NewbiZ

6
@bjarkef: Я считаю, что publicметоды доступа вызывают дублирование кода и раскрывают информацию. Публичные средства доступа не нужны для сортировки (сериализации). В некоторых языках (Java) publicметоды доступа get не могут изменять тип возвращаемого значения, не нарушая зависимые классы. Более того, я считаю, что они противоречат принципам ОО. Смотрите также: stackoverflow.com/a/1462424/59087
Дейв Джарвис

15
@sbi: Одна вещь, которая покупается с помощью установщика свойств, даже в хорошо спроектированной среде, - это возможность заставить объект уведомлять другой объект об изменении свойства.
суперкат

22
@supercat: Тем не менее, я, как правило, не продвигаю публичные данные. Уведомление о других объектах также может быть сделано с помощью реальных методов, обеспечивающих существенную абстракцию простого контейнера данных с (более или менее) открытыми полями данных. Вместо того, plane.turnTo(dir); plane.setSpeed(spd); plane.setTargetAltitude(alt); plane.getBreaks().release();чтобы сказать plane.takeOff(alt). Какие внутренние поля данных необходимо изменить, чтобы перевести плоскость в takingOffрежим, это не мое дело. И какие другие объекты ( breaks) метод уведомляет, я тоже не хочу знать.
2012 г.

8
@BenLee: я действительно не знаю, как еще сказать это. «Accessors» - это просто синоним «getters / setters», и в моих первых двух комментариях я объяснил, почему это злоупотребление термином «OOP». Если вам нужно проникнуть в него и напрямую манипулировать состоянием, это не объект в смысле ООП этого термина.
2012 г.

480

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


84
Я сижу и смотрю на приложение 500k line, где оно никогда не было нужно. Тем не менее, если бы это было необходимо однажды, это вызвало бы кошмар обслуживания. Достаточно хорошо для галочки для меня.
декан J

20
Я могу только завидовать вам и вашему приложению :-) Тем не менее, это действительно зависит и от вашего программного стека. Например, Delphi (и C # - я думаю?) Позволяет вам определять свойства как граждан 1-го класса, где они могут читать / писать поля непосредственно изначально, но - если вам это нужно - делайте это также с помощью методов получения / установки. Мучо удобно. В Java, увы, нет - не говоря уже о стандарте javabeans, который заставляет вас также использовать геттеры / сеттеры.
ChssPly76

14
Хотя это действительно хорошая причина для использования средств доступа, многие среды программирования и редакторы теперь предлагают поддержку рефакторинга (в среде IDE или в виде бесплатных надстроек), что несколько снижает влияние проблемы.
Л.Бушкин

62
звучит как
предзрелая

41
Когда вы задаетесь вопросом, следует ли реализовывать методы получения и установки, нужно задать вопрос: зачем пользователям класса вообще нужен доступ к внутренностям класса? На самом деле не имеет значения, делают ли они это напрямую или экранируются тонким псевдослойом - если пользователям нужен доступ к деталям реализации, то это признак того, что класс не предлагает достаточно абстракции. Смотрите также этот комментарий .
СБИ

358

Открытое поле не хуже пары получатель / установщик, которая ничего не делает, кроме как возвращает поле и присваивает ему значение. Во-первых, ясно, что (в большинстве языков) функциональной разницы нет. Любая разница должна быть в других факторах, таких как ремонтопригодность или удобочитаемость.

Часто упоминаемое преимущество пар геттер / сеттер - это не так. Есть утверждение, что вы можете изменить реализацию, и ваши клиенты не должны перекомпилироваться. Предположительно, сеттеры позволяют вам добавлять функциональность, такую ​​как проверка позже, и вашим клиентам даже не нужно знать об этом. Однако добавление проверки к установщику является изменением его предварительных условий, нарушением предыдущего контракта , который, по сути, заключался в том, что «вы можете положить сюда что-нибудь, и вы можете получить то же самое позже от получателя».

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

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

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

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

class Foo {
public:
    int DaysLeft;
    int ContestantNumber;
};

Добавление пар сквозного геттера / сеттера к такому классу не имеет значения. Другие классы должны обеспечивать значимые операции, а не только операции, которые уже предоставляют поля. Вот как вы можете определить и поддерживать полезные инварианты.

Клиент : «Что я могу сделать с объектом этого класса?»
Дизайнер : «Вы можете читать и писать несколько переменных».
Клиент : "Ох ... круто, наверное?"

Есть причины использовать геттеры и сеттеры, но если этих причин не существует, создание пар геттер / сеттер во имя ложных богов инкапсуляции не очень хорошая вещь. Допустимые причины для создания или получения включают в себя такие вещи, которые часто упоминаются как потенциальные изменения, которые вы можете сделать позже, такие как проверка или другие внутренние представления. Или, может быть, значение должно быть доступно для чтения клиентами, но не доступно для записи (например, чтение размера словаря), поэтому простой метод получения - это хороший выбор. Но эти причины должны быть, когда вы делаете выбор, а не просто как потенциальная вещь, которую вы можете захотеть позже. Это пример ЯГНИ ( Тебе это не нужно ).


13
Отличный ответ (+1). Моя единственная критика состоит в том, что мне потребовалось несколько чтений, чтобы выяснить, чем «валидация» в последнем абзаце отличалась от «валидации» в первых нескольких (которые вы выбросили в последнем случае, но способствовали в первом); корректировка формулировки может помочь в этом отношении.
Гонки легкости на орбите

14
Это отличный ответ, но, увы, нынешняя эпоха забыла, что такое «сокрытие информации» или для чего оно нужно. Они никогда не читали об неизменности и в поисках наиболее гибких, никогда не рисовали диаграмму состояний-переходов, которая определяла, какими были правовые состояния объекта и, следовательно, что нет.
Даррелл Тиг,

2
Ключевое наблюдение заключается в том, что геттеры гораздо полезнее, чем сеттеры. Получатель может вернуть вычисленное значение или кэшированное вычисленное значение. Все, что может сделать установщик, - это некоторая проверка и затем изменение privateполя. Если у класса нет сеттеров, его легко сделать неизменным.
Raedwald

7
Я полагаю, вы не знаете, что такое инвариант класса. Если это нетривиальная структура, это в значительной степени означает, что у нее есть инварианты, которые нужно отстаивать, и просто невозможно спроектировать ее без учета этого. «Была ошибка, один участник был обновлен неправильно». также в значительной степени читается как «Обновление члена нарушило инварианты класса». Хорошо разработанный класс не позволяет клиентскому коду нарушать его инварианты.
Р. Мартиньо Фернандес

5
+1 за «глупые держатели данных должны выглядеть как глупые держатели данных» К сожалению, в наши дни все, кажется, проектируют все вокруг глупых держателей данных, и многим фреймворкам даже требуется это ...
Joeri Hendrickx

93

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

Допустим, вы просматриваете сотни строк кода и сталкиваетесь с этим:

person.name = "Joe";

Это красивый кусок кода, пока вы не поймете, что это сеттер. Теперь вы следуете за этим установщиком и обнаруживаете, что он также устанавливает person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName и вызывает person.update (), который отправляет запрос в базу данных и т. Д. где произошла утечка памяти.

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


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

31
Это аргумент против синтаксического сахара, а не против сеттеров вообще.
Фил

6
Верно и верно, но, кроме того, в нем указывается, почему отдельные установщики свойств открывают дверь для недопустимых состояний без каких-либо мер для обеспечения целостности любого данного объекта, который позволяет утечке абстракции.
Даррелл Тиг

«Это красивый кусок кода, пока вы не поймете, что он является сеттером» - эй, это был оригинальный пост о Java или о C #? :)
Хонза Зидек

Я полностью согласен в отношении читабельности. Совершенно ясно, что происходит, когда person.name = "Joe";вызывается. Нет никакой информации о способе получения информации, выделение синтаксиса показывает, что это поле, а рефакторинг проще (нет необходимости в рефакторинге двух методов и поля). Во-вторых, все эти потраченные впустую мозговые циклы, думающие «getIsValid ()» или «isValid ()» и т. Д., Могут быть забыты. Я не могу вспомнить ни одного раза, когда я был спасен от ошибки получателем / установщиком.
Будет

53

Есть много причин. Мой любимый, когда вам нужно изменить поведение или регулировать то, что вы можете установить для переменной. Например, допустим, у вас был метод setSpeed ​​(int speed). Но вы хотите, чтобы вы могли установить максимальную скорость только 100. Вы бы сделали что-то вроде:

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}

Теперь, что если ВЕЗДЕ в своем коде вы используете открытое поле, а затем поняли, что вам нужно вышеуказанное требование? Получайте удовольствие, охотясь за каждым использованием публичного поля, а не просто изменяя ваш сеттер.

Мои 2 цента :)


62
Охота за каждым использованием публичного поля не должна быть такой сложной. Сделайте это приватным и позвольте компилятору найти их.
Натан Феллман

12
это правда, конечно, но зачем делать это сложнее, чем было задумано. Подход «получить / установить» - все еще лучший ответ.
Hardryv

28
@ Натан: найти другое использование не проблема. Менять их все есть.
Грэм Перроу

22
@GraemePerrow необходимость менять их все является преимуществом, а не проблемой :( Что если бы у вас был код, который предполагал, что скорость может быть выше 100 (потому что, как вы знаете, до того, как вы разорвали контракт, это могло быть!) ( while(speed < 200) { do_something(); accelerate(); })
R. Мартиньо Фернандес

29
Это ОЧЕНЬ плохой пример! Кто-то должен позвонить: myCar.setSpeed(157);и после нескольких строк speed = myCar.getSpeed();И теперь ... Я желаю вам счастливой отладки, пытаясь понять, почему, speed==100когда это должно быть157
Петр Александр Chmielowski

53

В чистом объектно-ориентированном мире геттеры и сеттеры это страшный анти-паттерн . Прочитайте эту статью: Getters / Setters. Злой. Период . Короче говоря, они поощряют программистов думать об объектах как о структурах данных, и этот тип мышления является чисто процедурным (как в COBOL или C). В объектно-ориентированном языке нет структур данных, а есть только объекты, демонстрирующие поведение (не атрибуты / свойства!)

Вы можете найти больше о них в Разделе 3.5 « Элегантных объектов» (моя книга об объектно-ориентированном программировании).


7
Методы получения и установки предлагают модель анемичной области.
Raedwald

7
Интересная точка зрения. Но в большинстве контекстов программирования нам нужны структуры данных. Возьмем пример «Собаки» из связанной статьи. Да, вы не можете изменить вес реальной собаки, установив атрибут ... но это new Dog()не собака. Это объект, который содержит информацию о собаке. И для этого использования естественно иметь возможность исправить неправильно записанный вес.
Стивен С

3
Ну, я вам говорю, что большинству полезных программ не нужно моделировать / моделировать объекты реального мира. ИМО, это не совсем о языках программирования вообще. Речь идет о том, для чего мы пишем программы.
Стивен С

3
Реальный мир или нет, Егор совершенно прав. Если то, что у вас есть, действительно является «структурой» и вам не нужно писать какой-либо код, который ссылается на него по имени, поместите его в хеш-таблицу или другую структуру данных. Если вам нужно написать код для него, поместите его как член класса и поместите код, который управляет этой переменной, в тот же класс и пропустите setter & getter. PS. хотя я в основном разделяю точку зрения Егора, я пришел к выводу, что аннотированные bean-компоненты без кода являются несколько полезными структурами данных - также иногда нужны методы получения, установки никогда не должно быть.
Билл К

1
Я увлекся - весь этот ответ, хотя и правильный и актуальный, не касается вопроса напрямую. Возможно, в нем должно быть сказано: «И сеттеры / геттеры, и публичные переменные неверны» ... Чтобы быть абсолютно конкретными, сеттеры и общедоступные переменные, доступные для записи, никогда не должны использоваться, в то время как геттеры в значительной степени совпадают с публичными конечными переменными и иногда являются необходимым злом. но ни один не намного лучше чем другой.
Билл К

38

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

Например, если бы он fooбыл общедоступным, я мог бы легко установить его, nullа затем кто-то другой мог бы попытаться вызвать метод объекта. Но его больше нет! С помощью setFooметода я мог убедиться, что fooникогда не был установлен в null.

Средства доступа и мутаторы также допускают инкапсуляцию - если вы не должны видеть значение после его установки (возможно, оно установлено в конструкторе, а затем используется методами, но никогда не должно изменяться), оно никогда не будет никем замечено. Но если вы можете позволить другим классам видеть или изменять его, вы можете предоставить надлежащий метод доступа и / или мутатор.


28

Зависит от вашего языка. Вы пометили это как «объектно-ориентированный», а не «Java», поэтому я хотел бы отметить, что ответ ChssPly76 зависит от языка. Например, в Python нет причин использовать геттеры и сеттеры. Если вам нужно изменить поведение, вы можете использовать свойство, которое заключает в себе метод получения и установки базового доступа к атрибутам. Что-то вроде этого:

class Simple(object):
   def _get_value(self):
       return self._value -1

   def _set_value(self, new_value):
       self._value = new_value + 1

   def _del_value(self):
       self.old_values.append(self._value)
       del self._value

   value = property(_get_value, _set_value, _del_value)

2
Да, я сказал так же в комментарии ниже моего ответа. Java - не единственный язык, который использует геттеры / сеттеры в качестве опоры, точно так же, как Python - не единственный язык, способный определять свойства. Главное, однако, все еще остается - «собственность» - это не то же самое «публичное поле».
ChssPly76

1
@jcd - совсем нет. Вы определяете свой «интерфейс» (здесь лучше использовать публичный API), выставляя свои открытые поля. Как только это будет сделано, пути назад уже нет. Свойства НЕ являются полями, потому что они предоставляют вам механизм для перехвата попыток доступа к полям (путем направления их к методам, если они определены); это, однако, не более чем синтаксический сахар по сравнению с методами получения / установки. Это чрезвычайно удобно, но не меняет основную парадигму - раскрытие полей без контроля над ними нарушает принцип инкапсуляции.
ChssPly76

14
@ ChssPly76 - я не согласен. У меня такой же контроль, как если бы они были свойствами, потому что я могу сделать их свойствами, когда мне это нужно. Нет разницы между свойством, которое использует шаблонные методы получения и установки и необработанный атрибут, за исключением того, что необработанный атрибут является более быстрым, поскольку он использует базовый язык, а не вызывает методы. Функционально они идентичны. Единственный способ нарушить инкапсуляцию - это если вы думаете, что скобки ( obj.set_attr('foo')) по своей природе превосходят знаки равенства ( obj.attr = 'foo'). Публичный доступ - это публичный доступ.
Jcdyer

1
У @jcdyer такой же большой контроль, да, но не так много читабельности, другие часто ошибочно полагают, что obj.attr = 'foo'просто устанавливает переменную без чего-либо еще происходящего
Тимо Хуовинен

9
@TimoHuovinen Как это отличается от того, что пользователь в Java полагает, что obj.setAttr('foo')«просто устанавливает переменную без чего-либо еще происходящего»? Если это общедоступные методы, то это публичный метод. Если вы используете его для достижения какого-либо побочного эффекта, и он общедоступен, тогда вам лучше рассчитывать на все, что работает, как если бы только тот побочный эффект имел место (со всеми другими деталями реализации и другими побочными эффектами, использованием ресурсов, чем угодно , скрытый от забот пользователя). Это абсолютно не отличается от Python. Синтаксис Python для достижения эффекта просто проще.
Ely

25

Ну, я просто хочу добавить, что даже если иногда они необходимы для инкапсуляции и безопасности ваших переменных / объектов, если мы хотим закодировать реальную объектно-ориентированную программу, нам нужно ОСТАНОВИТЬ ПРЕОДОЛЕНИЕ АКСЕССОРОВ , потому что иногда мы сильно зависимы на них, когда это действительно не нужно, и это делает почти то же самое, как если бы мы сделали переменные общедоступными.


24

Спасибо, это действительно прояснило мое мышление. Теперь вот (почти) 10 (почти) веских причин НЕ использовать геттеры и сеттеры:

  1. Когда вы поймете, что вам нужно сделать больше, чем просто установить и получить значение, вы можете просто сделать поле приватным, что мгновенно сообщит вам, где вы непосредственно получили к нему доступ.
  2. Любая проверка, которую вы выполняете, может быть только контекстно-свободной, что редко применяется на практике.
  3. Вы можете изменить установленное значение - это абсолютный кошмар, когда звонящие передают вам значение, которое они [шок ужас] хотят, чтобы вы хранили как есть.
  4. Вы можете скрыть внутреннее представление - фантастика, поэтому вы уверены, что все эти операции симметричны, верно?
  5. Вы изолировали свой общедоступный интерфейс от изменений под листами - если вы проектировали интерфейс и не были уверены, что прямой доступ к чему-либо был в порядке, то вам следовало продолжить проектирование.
  6. Некоторые библиотеки ожидают этого, но не так много - отражение, сериализация, макеты объектов прекрасно работают с открытыми полями.
  7. Унаследовав этот класс, вы можете переопределить функциональность по умолчанию - другими словами, вы можете ДЕЙСТВИТЕЛЬНО сбить с толку вызывающих, не только скрывая реализацию, но и делая ее несовместимой.

Последние три я просто ухожу (N / A или D / C) ...


11
Я думаю, что ключевой аргумент заключается в том, что «если вы разрабатывали интерфейс и не были уверены, что прямой доступ к чему-либо был в порядке, то вы должны были продолжать проектировать». Это самая важная проблема с геттерами / сеттерами: они уменьшают класс до простого контейнера (более или менее) открытых полей. Однако в реальном ООП объект - это больше, чем контейнер полей данных. Он инкапсулирует состояние и алгоритмы для управления этим состоянием. Что важно в этом утверждении, так это то, что состояние должно быть инкапсулировано и управляться только алгоритмами, предоставляемыми объектом.
2012 г.

22

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

Я сделал небольшой тест производительности. Я написал класс "NumberHolder", который, ну, в общем, содержит целое число. Вы можете прочитать это Integer, используя метод getter, anInstance.getNumber()или напрямую получить доступ к номеру, используя anInstance.number. Моя программа читает число 1 000 000 000 раз обоими способами. Этот процесс повторяется пять раз, и время печатается. Я получил следующий результат:

Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms

(Время 1 - прямой путь, Время 2 - получатель)

Видите ли, геттер (почти) всегда немного быстрее. Затем я попробовал с разным количеством циклов. Вместо 1 миллиона я использовал 10 миллионов и 0,1 миллиона. Результаты:

10 миллионов циклов:

Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms

С 10 миллионами циклов времена почти одинаковы. Вот 100 тысяч (0,1 миллиона) циклов:

Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms

Также с разным количеством циклов геттер немного быстрее обычного. Я надеюсь, что это помогло вам.


3
Есть «заметные» накладные расходы, имеющие вызов функции для доступа к памяти вместо простой загрузки адреса объекта и добавления смещения для доступа к членам. Скорее всего, виртуальная машина все равно оптимизирует ваш геттер. Несмотря на это, указанные издержки не стоят того, чтобы терять все преимущества геттеров / сеттеров.
Алекс

16

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

Думайте просто, легко, добавляйте сложность, когда это необходимо.

Я бы не воспользовался незнанием владельцев бизнеса глубоких технических ноу-хау только потому, что я думаю, что это правильно, или мне нравится подход.

У меня есть огромная система, написанная без методов установки геттеров, только с модификаторами доступа и некоторыми методами для проверки логики выполнения biz. Если вам абсолютно необходимо. Используйте что угодно.


16

Мы используем геттеры и сеттеры:

  • для повторного использования
  • выполнить проверку на более поздних этапах программирования

Методы получения и установки являются открытыми интерфейсами для доступа к закрытым членам класса.


Инкапсуляционная мантра

Мантра инкапсуляции - сделать поля приватными, а методы - открытыми.

Методы получения: мы можем получить доступ к закрытым переменным.

Методы установки: мы можем изменять приватные поля.

Хотя методы getter и setter не добавляют новую функциональность, мы можем передумать вернуться позже, чтобы сделать этот метод

  • лучше;
  • безопаснее; а также
  • Быстрее.

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

int x = 1000 - 500

использование

int x = 1000 - class_name.getValue();

С точки зрения непрофессионала

Представление класса "Персона"

Предположим, нам нужно хранить детали этого Person. Это Personимеет поле name, ageи sex. Делать это предполагает создание методов name, ageи sex. Теперь , если нам нужно создать еще один человек, становится необходимым для создания методов name, age, sexснова и снова.

Вместо этого мы можем создать компонент class(Person)с помощью методов получения и установки. Поэтому завтра мы можем просто создавать объекты этого Бина class(Person class)всякий раз, когда нам нужно добавить нового человека (см. Рисунок). Таким образом, мы повторно используем поля и методы класса bean, что намного лучше.


15

Я потратил некоторое время на обдумывание этого случая с Java, и я считаю, что настоящие причины:

  1. Код для интерфейса, а не реализация
  2. Интерфейсы только указывают методы, а не поля

Другими словами, единственный способ указать поле в интерфейсе - это предоставить метод для записи нового значения и метод для чтения текущего значения.

Эти методы являются печально известными методами получения и установки ....


1
Хорошо, второй вопрос; в случае, когда это проект, когда вы никому не экспортируете источник, и у вас есть полный контроль над источником ... вы получаете что-нибудь с помощью геттеров и сеттеров?
декан J

2
В любом нетривиальном проекте Java вам нужно кодировать интерфейсы, чтобы сделать вещи управляемыми и тестируемыми (например, макеты и прокси-объекты). Если вы используете интерфейсы, вам нужны геттеры и сеттеры.
Турбьерн Равн Андерсен

15

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

У меня был класс базовой страницы в проекте, который мне передали, который загружал некоторые данные из пары разных вызовов веб-службы, но данные в этих вызовах веб-службы не всегда использовались на всех дочерних страницах. Веб-сервисы, несмотря на все преимущества, являются пионерами новых определений «медленных», поэтому вы не хотите делать вызовы веб-сервисов, если в этом нет необходимости.

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

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

    protected YourType _yourName = null;
    public YourType YourName{
      get
      {
        if (_yourName == null)
        {
          _yourName = new YourType();
          return _yourName;
        }
      }
    }

Так тогда получатель вызывает установщик?
icc97

Я добавил пример кода того, как я делал это в прошлом - по сути, вы сохраняете фактический класс в защищенном элементе, а затем возвращаете этот защищенный элемент в метод доступа get, инициализируя его, если он не инициализирован.
Quillbreaker


13

Один аспект, который я пропустил в ответах, - спецификация доступа:

  • для членов у вас есть только одна спецификация доступа для настройки и получения
  • для сеттеров и геттеров вы можете точно настроить его и определить отдельно

13

РЕДАКТИРОВАТЬ: Я ответил на этот вопрос, потому что есть множество людей, изучающих программирование, спрашивающих об этом, и большинство ответов очень технически компетентны, но их не так легко понять, если вы новичок. Мы все были новичками, поэтому я решил попробовать свои силы в более дружелюбном ответе новичка.

Двумя основными из них являются полиморфизм и валидация. Даже если это просто глупая структура данных.

Допустим, у нас есть этот простой класс:

public class Bottle {
  public int amountOfWaterMl;
  public int capacityMl;
}

Очень простой класс, который определяет, сколько в нем жидкости и какова ее емкость (в миллилитрах).

Что происходит, когда я делаю:

Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacityMl = 1000;

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

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

Мы бы получили что-то вроде:

public interface LiquidContainer {
  public int getAmountMl();
  public void setAmountMl(int amountMl);
  public int getCapacityMl();
}

Большой! И теперь мы просто изменим бутылку на это:

public class Bottle extends LiquidContainer {
  private int capacityMl;
  private int amountFilledMl;

  public Bottle(int capacityMl, int amountFilledMl) {
    this.capacityMl = capacityMl;
    this.amountFilledMl = amountFilledMl;
    checkNotOverFlow();
  }

  public int getAmountMl() {
    return amountFilledMl;
  }

  public void setAmountMl(int amountMl) {
     this.amountFilled = amountMl;
     checkNotOverFlow();
  }
  public int getCapacityMl() {
    return capacityMl;
  }

  private void checkNotOverFlow() {
    if(amountOfWaterMl > capacityMl) {
      throw new BottleOverflowException();
    }
}

Я оставлю определение BottleOverflowException в качестве упражнения для читателя.

Теперь обратите внимание, насколько это надежнее. Теперь мы можем иметь дело с любым типом контейнера в нашем коде, приняв LiquidContainer вместо Bottle. И то, как эти бутылки справляются с такими вещами, может отличаться. У вас могут быть бутылки, которые записывают свое состояние на диск при его изменении, или бутылки, которые сохраняются в базах данных SQL или GNU знает, что еще.

И все это может иметь разные способы справиться с различными возгласами. Бутылка просто проверяет, и если она переполнена, она генерирует исключение RuntimeException. Но это может быть неправильно. (Есть полезная дискуссия об обработке ошибок, но я намеренно держу ее здесь очень просто. Люди в комментариях, скорее всего, укажут на недостатки этого упрощенного подхода.;))

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

Обратите внимание также, что вы не можете изменить емкость бутылки. Это сейчас в камне. Вы можете сделать это с помощью int, объявив его окончательным. Но если бы это был список, вы могли бы очистить его, добавить в него новые вещи и так далее. Вы не можете ограничить доступ к прикосновению к внутренностям.

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


2
Спасибо за первое полуприличное объяснение интерфейсов, которые я прочитал, без каких-либо ссылок на «пульты дистанционного управления» или «автомобили»
djvs

1
«У вас могут быть бутылки, которые записывают свое состояние на диск при его изменении, или бутылки, которые сохраняются в базах данных SQL», - так я хохотал xD. Но в любом случае, хорошая идея представить это!
Xerus

10

В языках, которые не поддерживают «свойства» (C ++, Java) или требуют перекомпиляции клиентов при изменении полей на свойства (C #), использование методов get / set легче изменить. Например, добавление логики проверки в метод setFoo не потребует изменения открытого интерфейса класса.

В языках, которые поддерживают «реальные» свойства (Python, Ruby, может быть Smalltalk?), Нет смысла получать / устанавливать методы.


1
Re: C #. Если вы добавите функциональность в get / set, это не потребует перекомпиляции?
steamer25

@ Steamer25: извините, неправильно набрал. Я имел в виду, что клиенты класса должны будут перекомпилироваться.
Джон Милликин

5
Добавление логики проверки к методу setFoo не потребует изменения интерфейса класса на уровне языка , но это действительно изменяет фактический интерфейс , то есть контракт, потому что это изменяет предварительные условия. Почему нужно, чтобы компилятор не воспринимал это как критическое изменение, когда оно есть ?
Р. Мартиньо Фернандес

@ R.MartinhoFernandes как можно решить эту «сломанную» проблему? Компилятор не может сказать, сломался он или нет. Это только проблема, когда вы пишете библиотеки для других, но вы представляете это как универсальный zOMG, будьте драконами!
Фил

3
Как уже упоминалось в ответе, требование перекомпиляции - это один из способов, которым компилятор может предупредить вас о возможном критическом изменении. И почти все, что я пишу, фактически является «библиотекой для других», потому что я не работаю один. Я пишу код с интерфейсами, которые будут использовать другие люди в проекте. Какая разница? Черт, даже если я буду пользователем этих интерфейсов, почему я должен придерживаться своего кода для более низких стандартов качества? Мне не нравится работать с проблемными интерфейсами, даже если я их пишу.
Р. Мартиньо Фернандес

6

Один из основных принципов ОО дизайна: инкапсуляция!

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


23
Геттеры и сеттеры для инкапсуляции очень смешные. Смотрите здесь .
СБИ

Если ваш общедоступный интерфейс утверждает, что «foo» имеет тип «T» и может быть установлен на что угодно, вы никогда не сможете это изменить. В последнем случае вы не можете решить сделать его типом «Y», а также не можете навязывать правила, такие как ограничения размера. Таким образом, если у вас есть общедоступный метод get / set, который ничего не делает для установки / получения, вы не получаете ничего, что не будет предлагать публичное поле, что делает его более громоздким в использовании. Если у вас есть ограничение, например, объект может быть установлен в значение null или значение должно находиться в пределах диапазона, тогда да, потребуется публичный метод set, но вы все равно представляете контракт на установку этого значения, которое может ' t change
thecoshman

Почему контракт не может измениться?
Фил

5
Почему все должно продолжаться, если контракты меняются?
Р. Мартиньо Фернандес

5

Вы должны использовать геттеры и сеттеры, когда:

  • Вы имеете дело с чем-то, что концептуально является атрибутом, но:
    • У вашего языка нет свойств (или какого-либо подобного механизма, такого как переменные трассировки Tcl), или
    • Поддержка свойств вашего языка недостаточна для этого варианта использования, или
    • Идиоматические соглашения вашего языка (или иногда вашей платформы) поощряют геттеры или сеттеры для этого варианта использования.

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


С точки зрения теории ОО, геттеры и сеттеры бесполезны. Интерфейс вашего класса - это то, что он делает, а не его состояние. (Если нет, вы написали неправильный класс.) В очень простых случаях, когда то, что делает класс, это просто, например, представляет точку в прямоугольных координатах, * атрибуты являются частью интерфейса; геттеры и сеттеры просто заволакивают это. Но в любом другом случае, кроме очень простых, ни атрибуты, ни методы получения и установки не являются частью интерфейса.

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

* Даже для этого простого класса, вы не обязательно хотите , чтобы настройки xи yзначения. Если это действительно класс, разве не должно быть таких методов, как translate, rotateи т. Д.? Если это только класс, потому что ваш язык не имеет записей / структур / именованных кортежей, то это на самом деле не вопрос ОО…


Но никто никогда не делает общий дизайн ОО. Они занимаются дизайном и реализацией на определенном языке. А в некоторых языках геттеры и сеттеры далеко не бесполезны.

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

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

Что касается "что если я захочу изменить свою реализацию позже?" вопрос (который повторяется несколько раз в разных формулировках как в вопросе OP, так и в принятом ответе): если это действительно чистое изменение реализации, и вы начали с атрибута, вы можете изменить его на свойство, не затрагивая интерфейс. Если, конечно, ваш язык не поддерживает это. Так что это опять тот же случай.

Кроме того, важно следовать идиомам языка (или структуры), который вы используете. Если вы пишете красивый код в стиле Ruby на C #, любой опытный разработчик C #, кроме вас, будет испытывать трудности при его чтении, и это плохо. Некоторые языки имеют более сильные культуры в своих соглашениях, чем другие. И это может быть не совпадением, что Java и Python, которые находятся на разных концах спектра того, насколько идиоматическими получателями являются, имеют две из самых сильных культур.

Помимо читателей-людей, будут библиотеки и инструменты, которые ожидают, что вы будете следовать соглашениям, и, если вы этого не сделаете, сделаете вашу жизнь тяжелее. Привязка виджетов Interface Builder к чему угодно, кроме свойств ObjC, или использование определенных библиотек Java-макетов без геттеров только усложняет вашу жизнь. Если инструменты важны для вас, не боритесь с ними.


4

С точки зрения проектно-ориентированного проектирования обе альтернативы могут повредить обслуживанию кода, ослабляя инкапсуляцию классов. Для обсуждения вы можете заглянуть в эту прекрасную статью: http://typicalprogrammer.com/?p=23


3

Методы получения и установки являются методами доступа, что означает, что они, как правило, являются открытым интерфейсом для изменения закрытых членов класса. Вы используете методы getter и setter для определения свойства. Вы получаете доступ к методам получения и установки как к свойствам вне класса, даже если вы определяете их в классе как методы. Эти свойства вне класса могут иметь имя, отличное от имени свойства в классе.

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

Несмотря на то, что методы getter и setter полезны, вы должны быть осторожны, чтобы не использовать их чрезмерно, поскольку, в частности, они могут усложнить обслуживание кода в определенных ситуациях. Кроме того, они предоставляют доступ к реализации вашего класса, как публичные члены. Практика ООП препятствует прямому доступу к свойствам в классе.

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


3

Код развивается . privateотлично подходит, когда вам нужна защита членов данных . В конце концов, все классы должны быть своего рода «минипрограммами», которые имеют четко определенный интерфейс, который вы не можете просто испортить .

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

int getVar() const { return var ; }

Так что у тебя есть:

doSomething( obj->getVar() ) ;

Вместо

doSomething( obj->var ) ;

Это не только getVar()визуально шумно, но и создает иллюзию, которая gettingVar()является более сложным процессом, чем на самом деле. То, как вы (как писатель класса) относитесь к святости, varособенно сбивает с толку пользователя вашего класса, если у него есть промежуточный установщик - тогда похоже, что вы устанавливаете эти ворота, чтобы «защитить» то, на чем настаиваете, что-то ценное, (святость var), но, тем не менее, даже если вы признаете, varчто защита не стоит того, чтобы кто-то просто мог прийти и set varполучить какую-то ценность, даже если вы не взглянули на то, что они делают.

Поэтому я программирую следующим образом (предполагая подход «гибкого» типа - то есть когда я пишу код, не зная точно, что он будет делать / не имеет времени или опыта для планирования сложного набора интерфейсов стилей водопада):

1) Начните со всех открытых членов для основных объектов с данными и поведением. Вот почему во всем моем «примерном» коде на C ++ вы заметите, что я использую structвместо этого classвезде

2) Когда внутреннее поведение объекта для члена данных становится достаточно сложным (например, ему нравится сохранять внутреннее std::listв некотором порядке), пишутся функции типа средства доступа. Поскольку я сам программирую, я не всегда устанавливаю член privateсразу, но где-то вниз по эволюции класса член будет «повышен» до protectedили private.

3) Классы, которые полностью проработаны и имеют строгие правила в отношении своих внутренних элементов (то есть они точно знают, что они делают, и вы не должны «трахать» (технический термин) с его внутренними компонентами), получают classобозначение, частные члены по умолчанию, и только несколько избранных членов могут быть public.

Я считаю, что этот подход позволяет мне не сидеть и не религиозно писать геттеры / сеттеры, когда многие члены данных перемещаются, перемещаются и т. Д. На ранних этапах развития класса.


1
«... четко определенный интерфейс, который вы не можете просто испортить с внутренностями» и проверка в установщиках.
Agi Hammerthief

3

Есть веская причина рассмотреть использование аксессоров, если нет наследования свойств. Смотрите следующий пример:

public class TestPropertyOverride {
    public static class A {
        public int i = 0;

        public void add() {
            i++;
        }

        public int getI() {
            return i;
        }
    }

    public static class B extends A {
        public int i = 2;

        @Override
        public void add() {
            i = i + 2;
        }

        @Override
        public int getI() {
            return i;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}

Вывод:

0
0
4

3

Геттеры и сеттеры используются для реализации двух фундаментальных аспектов объектно-ориентированного программирования:

  1. абстракция
  2. Инкапсуляция

Предположим, у нас есть класс Employee:

package com.highmark.productConfig.types;

public class Employee {

    private String firstName;
    private String middleName;
    private String lastName;

    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
         this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(){
        return this.getFirstName() + this.getMiddleName() +  this.getLastName();
    }
 }

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


1
Для меня иметь тонны добытчиков и сеттеров, которые не делают ничего уникального, бесполезно. getFullName является исключением, потому что он делает что-то еще. Если у вас есть только три открытые переменные, то сохранение getFullName сделает программу более удобной для чтения, но при этом скрытое имя будет полностью скрыто. Как правило, я полностью согласен с геттерами и сеттерами, если. они делают что-то уникальное и / или б. у вас есть только один, да, вы могли бы иметь публичный финал и все такое, но нет
FacelessTiger

1
Преимущество этого состоит в том, что вы можете изменять внутренние компоненты класса, не меняя интерфейс. Скажем, вместо трех свойств у вас было одно - массив строк. Если вы использовали геттеры и сеттеры, вы можете внести это изменение, а затем обновить геттер / сеттеры, чтобы они знали, что names [0] - это имя, names [1] - это середина и т. Д. Но если вы просто использовали публичные свойства Кроме того, вам придется изменить каждого сотрудника, к которому обращался класс, поскольку используемого им свойства firstName больше не существует.
Эндрю

1
@ AndrewHows из того, что я видел в реальной жизни, когда люди меняют внутренности класса, они также меняют интерфейс и делают большой рефакторинг всего кода
Eildosa

2

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


Я бы никогда не ожидал, что метод получения или установки будет дорогостоящей операцией. В таких случаях лучше использовать фабрику: используйте все необходимые сеттеры, а затем вызывайте дорогой метод executeили buildметод.
Хьюберт Гжесковяк

2

Одно относительно современное преимущество методов получения / установки состоит в том, что он облегчает просмотр кода в редакторах теговых (индексированных) кодов. Например, если вы хотите увидеть, кто устанавливает участника, вы можете открыть иерархию вызовов установщика.

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


Вы можете сделать правый клик> найти использование на члене точно так же, как на получателе / ​​установщике
Eildosa

2

В объектно-ориентированном языке методы и их модификаторы доступа объявляют интерфейс для этого объекта. Между конструктором и методами доступа и мутатора разработчик может контролировать доступ к внутреннему состоянию объекта. Если переменные просто объявлены как public, то нет никакого способа регулировать этот доступ. И когда мы используем сеттеры, мы можем ограничить пользователя для ввода, который нам нужен. Означает, что канал для этой самой переменной будет проходить через правильный канал, и канал предопределен нами. Так что безопаснее использовать сеттеры.


1

Кроме того, это «будущее» вашего класса. В частности, переход от поля к свойству является разрывом ABI, поэтому, если позже вы решите, что вам нужно больше логики, чем просто «установить / получить поле», то вам нужно разбить ABI, что, конечно, создает проблемы для чего-либо еще уже скомпилировано против вашего класса.


2
Я полагаю, что изменение поведения геттера или сеттера не является серьезным изменением. </ sarcasm>
Р. Мартиньо Фернандес

@ R.MartinhoFernandes не всегда должен быть. TBYS
Фил,

1

Я просто хотел бы бросить идею аннотации: @getter и @setter. С @getter вы должны иметь возможность obj = class.field, но не class.field = obj. С @setter, наоборот. С @getter и @setter вы сможете сделать оба. Это сохранит инкапсуляцию и сократит время, не вызывая тривиальные методы во время выполнения.


1
Это будет реализовано во время выполнения с "тривиальными методами". На самом деле, наверное, нетривиально.
Фил

Сегодня это можно сделать с помощью препроцессора аннотации.
Торбьерн Равн Андерсен
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.