Как получить доступ к свойствам объекта из метода объекта?
Каков «пуристский» или «правильный» способ доступа к свойствам объекта из метода объекта, который не является методом получения / установки?
Я знаю, что извне объекта вы должны использовать геттер / сеттер, но изнутри вы бы просто сделали:
Джава:
String property = this.property;
PHP:
$property = $this->property;
или вы бы сделали:
Джава:
String property = this.getProperty();
PHP:
$property = $this->getProperty();
Простите меня, если моя Java немного не работает, прошел год с тех пор, как я программировал на Java ...
РЕДАКТИРОВАТЬ:
Кажется, люди предполагают, что я говорю только о частных или защищенных переменных / свойствах. Когда я изучал объектно-ориентированный подход, меня учили использовать геттеры / сеттеры для каждого отдельного свойства, даже если оно было общедоступным (и на самом деле мне сказали никогда не делать какие-либо переменные / свойство общедоступными). Итак, я могу исходить из ложного предположения с самого начала. Похоже, что люди, отвечающие на этот вопрос, возможно, говорят, что у вас должны быть общедоступные свойства и что им не нужны геттеры и сеттеры, что противоречит тому, чему меня учили и о чем я говорил, хотя, возможно, это следует обсудить как хорошо. Хотя, наверное, это хорошая тема для другого вопроса ...
Ответов (18)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->.
Я довольно удивлен, насколько это единодушное мнение, getters
а сеттеры хороши и хороши. Предлагаю зажигательную статью Аллена Голуба « Геттеры и сеттеры - зло ». Конечно, название предназначено для шокирующей ценности, но автор делает обоснованные выводы.
По сути, если у вас есть getters
и setters
для каждого частного поля, вы делаете эти поля такими же хорошими, как и общедоступные. Вам будет очень сложно изменить тип частного поля без эффектов пульсации для каждого класса, который это вызывает getter
.
Более того, с строго объектно-ориентированной точки зрения, объекты должны отвечать на сообщения (методы), которые соответствуют их (надеюсь) единственной ответственности. Подавляющее большинство getters
и setters
не имеют смысла для составляющих их объектов; Pen.dispenseInkOnto(Surface)
имеет для меня больше смысла, чем Pen.getColor()
.
Геттеры и сеттеры также побуждают пользователей класса запрашивать у объекта некоторые данные, выполнять вычисление, а затем устанавливать какое-то другое значение в объекте, что более известно как процедурное программирование. Лучше просто сказать объекту сделать то, что вы собирались делать в первую очередь; также известный как идиома информационного эксперта .
Однако геттеры и сеттеры - необходимое зло на границе слоев - пользовательский интерфейс, постоянство и так далее. Ограниченный доступ к внутренним компонентам класса, таким как ключевое слово friend в C++, защищенный доступ к пакетам Java, внутренний доступ .NET и шаблон Friend Class, могут помочь вам уменьшить видимость getters
и сеттеры только для тех, кто в них нуждается.
PHP предлагает множество способов справиться с этим, включая магические методы __get
и __set
, но я предпочитаю явные методы получения и установки. Вот почему:
- Проверка может быть помещена в сеттеры (и геттеры, если на то пошло)
- Intellisense работает с явными методами
- Нет сомнений в том, доступно ли свойство только для чтения, только для записи или для чтения и записи.
- Получение виртуальных свойств (т. Е. Вычисленных значений) выглядит так же, как и обычные свойства.
- Вы можете легко установить свойство объекта, которое на самом деле нигде не определяется, а затем становится недокументированным.
Лучше использовать методы доступа даже внутри объекта. Вот моменты, которые сразу приходят мне в голову:
Это должно быть сделано в интересах сохранения согласованности с доступом извне объекта.
В некоторых случаях эти методы доступа могут делать больше, чем просто получать доступ к полю; они могут выполнять некоторую дополнительную обработку (хотя это бывает редко). В этом случае прямой доступ к полю будет означать, что вам не хватает этой дополнительной обработки, и ваша программа может пойти не так, если эта обработка всегда будет выполняться во время этих обращений.