Действительно ли разумно иметь изрядное количество общественных собственностей в классе?

Или в более определенных словах, это "в порядке" для не доверия методам set и методам get?

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

  • unitNumber
  • roomTypes (массив)
  • codeCorporate
  • codeGroup
  • numberKids
  • numberAdults
  • numberRooms
  • валюта
  • minRate
  • maxRate
  • soapServer
  • единицы (массив)
  • hotelId

И после того, как объект инстанцируют, те свойства установлены с $this-> в различных методах. Однако код, который имеет дело с объектом часто, устанавливает общественные собственности непосредственно вместо того, чтобы использовать метода get/методы установщика:

$object->something = 3;

foreach ($object->things as $thing ) { }

Если у меня есть время для рефакторинга этого класса..

  • Если я засовываю все эти свойства в массиве данных, это - частная собственность, и определить __set и __get методы?
  • Я должен сделать единственный метод получателя для каждого из свойств?
12
задан Gordon Gustafson 8 February 2010 в 22:11
поделиться

5 ответов

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

Setters/Getters - это путь, и очень маленький штраф за выступление, который вы платите за него, обычно либо оптимизируется, либо окупается элегантностью.

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

3
ответ дан 2 December 2019 в 22:22
поделиться

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

Хотя я предпочитаю определенные геттеры / сеттеры для каждого свойство (является ли это прокси для обобщенного get ($ name) или нет). Я предполагаю, что у вас уже есть другой код, который использует прямое присваивание, поэтому в этом случае я бы сказал, чтобы продолжить использовать магические методы __ get / __ set .

3
ответ дан 2 December 2019 в 22:22
поделиться

Я думаю, что большинство людей порекомендуют использовать сеттеры и геттеры. Прямо сейчас вы ограничены простой настройкой и получением свойства, но что, если вы хотите регистрировать доступ к этому свойству? Или, возможно, вы хотите сначала запустить значение с помощью функции проверки (электронная почта, номер телефона, почтовый индекс и т. Д.). Возможно, вам потребуется вызвать другую функцию или установить другое свойство. Я думаю, вы понимаете, к чему я клоню. Используя сеттеры и геттеры, вы добавляете к своим классам ценный уровень инкапсуляции, и в 99% случаев это стоит дополнительного набора текста, который вам понадобится;) Представьте, что вы пытаетесь выполнить приведенные выше примеры без сеттеров и геттеров. Это было бы, мягко говоря, большой головной болью.

Edit: Я забыл упомянуть Доктрину. Это преобразователь объектных отношений (ORM), который может автоматически настраивать сеттеры и получатели (среди прочего). Вы можете проверить это на http: //www.doctrine-project.org /

2
ответ дан 2 December 2019 в 22:22
поделиться

Я бы сделал шаг назад и задам несколько более общих вопросов:

  • Почему я должен раскрывать так много информации; что его использует и почему?
  • Действительно ли этот класс - просто структура данных без поведения, и в этом случае он должен быть частным классом для какого-то другого класса?
  • Этот класс служит единственной цели или находится в путь к монолитности?

Вы можете обнаружить, что можете создавать представления экземпляра класса для экспорта в базу данных, отображения в форме и т. д. Ознакомьтесь с шаблонами «Строитель» и «Ациклический посетитель», чтобы начнем с.

Что касается средств доступа, я не вижу необходимости использовать их для того, что вы описываете: получение свойств класса и информации о внутреннем состоянии, также известной как структура. Однако для атрибутов класса я мог видеть преимущества в некоторых случаях, но больше для получения атрибутов, а не для мутаций состояния вашего объекта.

1
ответ дан 2 December 2019 в 22:22
поделиться

Если позволите, несколько месяцев спустя я добавлю немного скептицизма:

Иметь общедоступные свойства - это очень не-ОО. Все должно быть инкапсулировано просто потому, что (среди прочего) использование прямого управления атрибутами не дает вам возможности легко реорганизовать или выполнить (больше) контрольных проверок, когда какой-либо внешний источник изменяет поле. Например, предположим, что у вас есть класс со многими полями, который используется в проекте несколько раз, и этот проект содержит несколько тысяч файлов; это проект, который работает и расширяется уже несколько лет. Допустим, компания меняет свою бизнес-модель или что проблема обнаружена с некоторыми типами данных поля и теперь требуется некоторая проверка; Вы продублируете эту проверку во всех тысячах исходных кодов, напрямую обращающихся к публичному члену? В PHP решение может быть простым, но не в большинстве языков программирования OO (например, Java).Дело в том, что объектно ориентированный объект основан на инкапсуляции. Короче говоря, инкапсуляция создает не только чистый код, но и хорошо обслуживаемый (не говоря уже о рентабельном и связном) коде.

Ваше предложение о том, чтобы __get / __set манипулировал закрытым членом (массивом), - это хорошо. Таким образом, если вам понадобится дополнительная проверка, просто создайте свой сеттер и / или получатель, и это будет конец. Некоторые могут поспорить, что это контрпродуктивно, поскольку завершение кода не может сработать на __get / __set. IMHO, полагаться на завершение кода - это просто ленивое кодирование. Но опять же, наличие у каждого члена своего собственного получателя и / или сеттера позволяет вам писать более полную документацию по API. Лично я обычно использую эту технику для внутренних классов или классов очень общего назначения. Если все ваши поля не требуют проверки или их, как вы сказали, несколько десятков, то использование магических методов, на мой взгляд, было бы приемлемым.

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

В заключение, в PHP, если у вас уже есть классы, которые не инкапсулируют свои поля, например, что-то вроде

class SomeObject {
   public $foo;
   public $bar;
   public $baz;
   //...
}

, вы можете просто исправить этот класс без необходимости реорганизовать что-либо с помощью чего-то вроде:

class SomeObject {
   private $_foo;   // having underscore as prefix helps to know what's private/protected
   private $_bar;   // inside the code.
   private $_baz;

   public function __get($name) {
      $methodName = 'get'.ucfirst($name);
      if (method_exists($this, $methodName)) {
         return $this->{$methodName}();
      } else {
         throw new Exception("Method '{$methodName}' does not exist");
      }
   }

   public function __set($name, $value) {
      $methodName = 'set'.ucfirst($name);
      if (method_exists($this, $methodName)) {
         $this->{$methodName}($value);
      } else {
         throw new Exception("Method '{$methodName}' does not exist");
      }
   }

   public function getFoo() { return $this->_foo; }
   public function setFoo($value) { $this->_foo = $value; }

   public function getBar() { return $this->_bar; }
   public function setBar($value) { $this->_bar = $value; }

   public function getBaz() { return $this->_baz; }
   public function setBaz($value) { $this->_baz = $value; }

}

А затем

$obj = new SomeObject();
$obj->foo = 'Hello world';    // legacy code support
$obj->setFoo('Hello world');  // same thing, but preferred

И вы удовлетворяете парадигме объектно-ориентированного подхода и имеете прямой доступ к атрибутам экземпляра.Вы также можете использовать __call () для проверки префикса 'get' или 'set' и вызвать __get () и __set () соответственно, но я бы не стал зайти так далеко, хотя это действительно позволило бы классам общего назначения получать доступ к своим частным членам через -> member и -> getMember () / -> setMember ()

1
ответ дан 2 December 2019 в 22:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: