Организация занятий в PHP - PullRequest
       25

Организация занятий в PHP

2 голосов
/ 06 октября 2009

Предположим, у меня есть следующие классы в моем проекте:

  • класс Is // класс проверки
  • класс математика // класс манипулирования числами

Теперь, если я хочу проверить заданное число на простоту, где будет логическое место для вставки моего метода Prime ()? Я могу думать о следующих вариантах:

  • Is_Math :: Prime ()
  • Math_Is :: Prime ()

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

  • Is :: Image () или Image :: Is ()?
  • Is_Image :: PNG () или Image_Is :: PNG ()?
  • Is_i18n_US :: ZipCode () или i18n_Is_US :: ZipCode () или i18n_US_Is :: ZipCode ()?

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

Есть ли решение по организации Святого Грааля для организации занятий? Может быть, другая парадигма?

Ответы [ 8 ]

10 голосов
/ 06 октября 2009

Для примера по математике я бы поставил фактическую функциональность проверки, является ли число простым в классе Math. В вашем классе Is вы бы поместили метод, который будет вызываться, когда необходимо выполнить проверку. Затем вы бы использовали Math::Prime() оттуда.

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

С помощью метода PNG, то же самое с Math. Поместите фактический алгоритм проверки данных PNG в Image, а метод валидатора в Is вызовите его.

Пример почтового индекса должен быть только в вашем классе Is, поскольку он работает со строковым примитивом и, вероятно, просто использует регулярное выражение (читай: это не будет сложный метод, в отличие от вашей проверки PNG, которая, вероятно, ).

4 голосов
/ 06 октября 2009

Если вы хотите соблюдать SRP (http://en.wikipedia.org/wiki/Single_responsibility_principle),, выполните небольшое упражнение:

Выберите свой класс и попробуйте описать, что он делает / может делать. Если в вашем описании есть «И», вы должны переместить метод в другой класс.

См. Стр. 36: http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf

Другой закон (есть еще много), который поможет вам организовать ваши занятия: Закон Деметры (http://en.wikipedia.org/wiki/Law_of_Demeter).

)

Чтобы многому научиться и помочь сделать правильный выбор, я советую вам блог Миско (евангелист Google): http://misko.hevery.com

Надеюсь, это поможет.

3 голосов
/ 14 октября 2009

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

В случае Is :: Math, что вы делаете? Вы делаете математические операции? Или вы проверяете математические объекты? Последнее, очевидно, иначе это был бы просто «Математика».

Какая из этих двух операций имеет большую область? Является? Или математика? Очевидно, что Is является концептуально применимым ко многим нематематическим сущностям, в то время как Math специфично для Math. (Аналогично в случае Math :: Factor это не будет Factor :: Math, потому что Math - это надмножество, к которому принадлежит Factor.)

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

3 голосов
/ 10 октября 2009

Все, что связано с обработкой проверки само по себе будет соответствовать вашим Is -классам:

  • Это прошло?
  • Какие части не прошли?
  • Должны ли ошибки проверки где-нибудь регистрироваться?

Zend_Validate в Zend Framework предоставляет такой подход, возможно, вы можете получить от него вдохновение. Поскольку при таком подходе вы реализуете один и тот же интерфейс во всех классах валидации, вы можете легко

  • использует тот же синтаксис для проверки, независимо от того, какие данные проверяются
  • легко распознает, какие правила проверки у вас есть, проверяя все классы с именами Is_Prime, Is_Image вместо проверки на Math_Is, Image_Is повсюду.

Edit:
Почему бы не использовать такой синтаксис:

class Math {
    public function isPrime() {
        $validation_rule = new Is_Prime();
        return (bool) $validation_rule->validates($this->getValue());
    }
}

и тем самым также разрешить

class Problem {
    public function solveProblem(Math $math) {
        $validation_rule = new Is_Prime();
        if($validation_rule->validates($math->getValue())) {
            return $this->handlePrime($math);
        } else {
            return $this->handleNonPrime($math);
        }
    }
}
1 голос
/ 15 октября 2009

Я не думаю, что "is" принадлежит именам классов вообще. Я думаю, что это для методов.

abstract class Validator {}

class Math_Validator extends Validator
{
  public static function isPrime( $number )
  {
    // whatever
  }
}

class I18N_US_Validator extends Validator
{
  public static function isZipCode( $input )
  {
    // whatever
  }
}

class Image_Validator extends Validator
{
  public static function isPng( $path )
  {
    // whatever
  }
}

Math_Validator::isPrime( 1 );
I18N_US_Validator::isZipCode( '90210' );
Image_Validator::isPng( '/path/to/image.png' );
1 голос
/ 11 октября 2009

Я думаю, что нет "Правильного ответа" на проблему, которую вы указали. Некоторые люди ставят Prime в Is, а некоторые в Math. Существует двусмысленность. В противном случае вы бы не задавали этот вопрос.

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

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

Не называйте свой пакет проверки Is. Это настолько общее название, что почти все идет туда. IsFile, IsImage, IsLocked, IsAvailable, IsFull - плохо звучит, хорошо? Нет сплоченности с этим дизайном.

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

После принятия этого решения ваш пример становится очевидным. Прайм принадлежит математике. Is :: Image, вероятно, слишком общий. Я бы предпочел Image :: IsValid, потому что у вас, вероятно, также будут другие методы, работающие с изображением (больше согласованности). В противном случае «Есть» становится сумкой для всего , как я сказал в начале.

0 голосов
/ 15 октября 2009

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

abstract class ValidatingType 
{
  protected $val;
  public function __construct($val)
  {
     if(!self::isValid($val))
     {  // complain, perhaps by throwing exception
        throw new Exception("No, you can't do that!");
     }
     $this->val = $val;

  }
  abstract static protected function isValid($val);
}

Мы расширяем ValidatingType для создания проверяющего типа. Это обязывает нас создавать метод isValid.

class ValidatingNumber extends ValidatingType
{
   ...
   static protected function isValid($val)
   {
      return is_numeric($val);
   }
}

class ValidatingPrimeNumber extends ValidatingNumber
{
   /*
    * If your PHP doesn't have late-binding statics, then don't make the abstract 
    * or overridden methods isValid() static.
    */
   static protected function isValid($val)
   {
      return parent::isValid($val) 
             or self::isPrime($val); // defined separately
   }
}

class ValidatingImage extends ValidatingType
{
   ...
   static protected function isValid($val)
   {
      // figure it out, return boolean
   }
}

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

Есть более элегантные варианты этого подхода. Это простой вариант. Синтаксис может потребовать очистки.

0 голосов
/ 06 октября 2009

Есть ли решение Святого Грааля для организации занятий? Может быть, другая парадигма?

Нет, это основной недостаток классового упа. Это субъективно.

Функциональное программирование (не путать с процедурным программированием) имеет меньше проблем с этим вопросом, в основном потому, что основные строительные блоки намного меньше. Бесклассовое управление также работает лучше, будучи своего рода гибридом функционального и функционального программирования.

...