Как получить доступ к свойствам объекта из метода объекта? [закрыто]


96

Каков «пуристический» или «правильный» способ доступа к свойствам объекта из метода объекта, который не является методом получения / установки?

Я знаю, что извне объекта вы должны использовать геттер / сеттер, но изнутри вы бы просто сделали:

Ява:

String property = this.property;

PHP:

$property = $this->property;

или вы бы сделали:

Ява:

String property = this.getProperty();

PHP:

$property = $this->getProperty();

Простите, если моя Java немного не работает, прошел год с тех пор, как я программировал на Java ...

РЕДАКТИРОВАТЬ:

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

Ответы:


62

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


ничего не делает в установщике, кроме установки значения свойства в качестве примера неправильного использования в Java.
euphoria83

1
@ euphoria83 Возможно, но это не мешает этому случиться.
Грег Хёрлман,

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

43

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

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


26

Я довольно удивлен, насколько это единодушное мнение, gettersа сеттеры хороши и хороши. Предлагаю зажигательную статью Аллена Голуба « Геттеры и сеттеры - зло ». Конечно, заголовок рассчитан на шокирующую ценность, но автор делает обоснованные выводы.

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

Более того, с строго объектно-ориентированной точки зрения, объекты должны отвечать на сообщения (методы), которые соответствуют их (надеюсь) единственной ответственности. Подавляющее большинство gettersи settersне имеют смысла для составляющих их объектов; Pen.dispenseInkOnto(Surface)имеет для меня больше смысла, чемPen.getColor() .

Геттеры и сеттеры также побуждают пользователей класса запрашивать у объекта некоторые данные, выполнять вычисление, а затем устанавливать какое-либо другое значение в объекте, что более известно как процедурное программирование. Лучше просто сказать объекту сделать то, что вы собирались делать в первую очередь; также известный как идиома информационного эксперта .

Однако геттеры и сеттеры - необходимое зло на границе слоев - пользовательский интерфейс, постоянство и так далее. Ограниченный доступ к внутренним компонентам класса, таким как ключевое слово friend в C ++, защищенный доступ к пакетам Java, внутренний доступ .NET и шаблон Friend Class, могут помочь вам уменьшить видимость gettersи сеттеры только для тех, кто в них нуждается.


19

Это зависит от того, как используется недвижимость. Например, предположим, что у вас есть объект ученика, у которого есть свойство name. Вы можете использовать свой метод Get для извлечения имени из базы данных, если оно еще не было получено. Таким образом вы сокращаете количество ненужных обращений к базе данных.

Теперь предположим, что у вас есть частный счетчик целых чисел в вашем объекте, который подсчитывает, сколько раз было вызвано имя. Вы можете не использовать метод Get изнутри объекта, потому что это приведет к неверному счету.


Если объект Student является бизнес-объектом или объектом домена, вы теперь смешиваете детали инфраструктуры. В идеале объекты бизнеса / домена должны быть связаны только с логикой бизнеса / домена.
moffdub

Что, если вы добавите к геттеру какое-то логическое значение, например: PHP: public function getName ($ outsideCall = true) {if ($ outsideCall) {$ this-> incrementNameCalled (); } вернуть $ this-> name; }, а затем из самого объекта, если вы вызвали get name, вы можете предотвратить его приращение: PHP: $ name = $ this-> getName (false); Я просто переборщил с этим?
cmcculloh

14

PHP предлагает множество способов справиться с этим, включая магические методы __getи __set, но я предпочитаю явные методы получения и установки. Вот почему:

  1. Проверка может быть помещена в сеттеры (и геттеры, если на то пошло)
  2. Intellisense работает с явными методами
  3. Нет сомнений в том, доступно ли свойство только для чтения, только для записи или для чтения и записи.
  4. Получение виртуальных свойств (т. Е. Вычисленных значений) выглядит так же, как и обычные свойства.
  5. Вы можете легко установить свойство объекта, которое на самом деле нигде не определяется, а затем становится недокументированным.

13

Я просто переборщил с этим?

Возможно;)

Другой подход заключался бы в использовании частного / защищенного метода для фактического получения (caching / db / etc) и общедоступной оболочки для него, которая увеличивает счетчик:

PHP:

public function getName() {
    $this->incrementNameCalled();
    return $this->_getName();
}

protected function _getName() {
    return $this->name;
}

а затем изнутри самого объекта:

PHP:

$name = $this->_getName();

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


12

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

Подводя итог этому, геттер должен вызвать геттер, который должен вызвать геттер.

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


Меня подтолкнуло то же самое, что вы должны были прокомментировать ... Плюс ответ не был закрыт;)
Egg Vans

8

Пуристский ОО-способ - избегать обоих и следовать Закону Деметры , используя « Говори, не спрашивай». подход .

Вместо получения значения свойства объекта, которое тесно связывает два класса, используйте объект в качестве параметра, например

  doSomethingWithProperty() {
     doSomethingWith( this.property ) ;
  }

Если свойство было собственным типом, например int, используйте метод доступа, назовите его для проблемной области, а не для области программирования.

  doSomethingWithProperty( this.daysPerWeek() ) ;

Это позволит вам поддерживать инкапсуляцию и любые пост-условия или зависимые инварианты. Вы также можете использовать метод setter для поддержки любых предварительных условий или зависимых инвариантов, однако не попадайтесь в ловушку именования их сеттеров, вернитесь к Голливудскому принципу для именования при использовании идиомы.


8

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

  1. Это должно быть сделано в интересах поддержания согласованности с доступом извне объекта.

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


8

Если вы имеете в виду «большую инкапсуляцию» под «пуристом», то я обычно объявляю все свои поля как частные, а затем использую «this.field» внутри самого класса. Для других классов, включая подклассы, я получаю доступ к состоянию экземпляра с помощью геттеров.


7

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


7

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

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



7

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


7

Если я не буду редактировать свойство, я буду использовать общедоступный метод, get_property()если это не особый случай, такой как объект MySQLi внутри другого объекта, и в этом случае я просто сделаю свойство общедоступным и назову его $obj->object_property.

Внутри объекта для меня всегда свойство $ this->.


5

Что ж, похоже, что с реализацией свойств C # 3.0 по умолчанию решение принимается за вас; вы ДОЛЖНЫ установить свойство, используя (возможно, частный) установщик свойств.

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


5

Мне нравится ответ cmcculloh , но кажется, что наиболее правильным является ответ Грега Херлмана . Всегда используйте геттер / сеттер, если вы начали использовать их с самого начала и / или привыкли с ними работать.

Кстати, я лично считаю, что использование геттера / сеттера упрощает чтение кода и его отладку в дальнейшем.


4

Как указано в некоторых комментариях: иногда нужно, иногда нет. Самое замечательное в частных переменных заключается в том, что вы можете видеть все места, где они используются, когда вы что-то меняете. Если ваш геттер / сеттер делает что-то, что вам нужно, используйте его. Если это не важно, решать вам.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.