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

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

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

Джава:

String property = this.property;

PHP:

$property = $this->property;

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

Джава:

String property = this.getProperty();

PHP:

$property = $this->getProperty();

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

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

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

Ответов (18)

Решение

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

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

Это зависит. Это больше вопрос стиля, чем что-либо еще, и здесь нет жесткого правила.

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

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

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

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

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

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

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

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

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

  doSomethingWithProperty( this.daysPerWeek() ) ;

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

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

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

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

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

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

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

Я просто переборщу здесь?

Возможно ;)

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

PHP:

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

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

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

PHP:

$name = $this->_getName();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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