2009-10-05 2 views
2

Пусть Я следующие классы в моем проекте:Организация классов в PHP

  • класс Является // класс валидации
  • класс Math // манипуляция номер класса

Теперь, если я хочу проверить заданное число для primality, где было бы логичным местом для вставки моего метода 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 я предпочитаю последний. Не имея стандарта, я чувствую, что вся база кода грязная.

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

ответ

3

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

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

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

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

+1

Черт, хороший ответ, вы пригвоздили ровно мой процесс мышления! –

10

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

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

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

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

+0

+1 - очень четкое объяснение, которое должно помочь ему в будущих проблемах. –

+0

На самом деле это в основном то же самое, что и я, но в обратном пути это еще больше смутило меня. –

+0

Я не уверен, что понимаю, что вы имеете в виду. Помог ли мой ответ или смутил вас? –

0

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

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

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

+0

Интересно, какой классный ооп ... Может быть, вам все равно, покажите нам пример? –

+0

Javascript, Lua, различные реализации схемы - чтобы назвать несколько - предоставить прототип объектной системы. В Ruby классы - это объекты времени выполнения, с которыми можно манипулировать. Это примеры того, что я бы назвал бесклассовой системой объектов. – troelskn

4

Если вы хотите уважать SRP (http://en.wikipedia.org/wiki/Single_responsibility_principle), сделайте маленький exercice:

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

Смотрите страницу 36: http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf

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

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

Надеется, что это помогает.

+0

Я предполагаю, что уже сделал это ... «класс Image выполняет несколько манипуляций с изображениями и несколько проверок изображений», то, с чем я борюсь, где хранить хранимые данные? В классе «Image_Validation extends Image» или в «Validation_Image extends Validation» один? –

+1

Никогда не забывайте: вы должны расширять только абстрактные классы. В противном случае вы должны использовать «инъекцию класса» (см. Болт Мишко). Ваш вопрос, переведенный, касается класса Dependency (снова: блог Misko - это ссылка). Честно говоря, невозможно ответить на ваш вопрос, не видя весь ваш код, ваши ограничения. И т. Д. Если все ваши классы могут пройти тест «НЕТ И», и если вы уважаете лучшие практики внедрения инъекций, ваши классы должны быть легко реорганизованы/реорганизованы в случае изменений требований. => Архитектура «зависимостей», которую вы выбрали, хороша. :) – Toto

3

Все о обработки проверки в себе будет вписываться в ваших Is -классах:

  • ли это пройти?
  • Какие детали не прошли?
  • Следует ли регистрировать ошибки проверки?

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

  • использовать тот же синтаксис для проверки, independantly которого данные проверяются
  • легко распознавать, какие проверки правил, которые вы имеете в наличии по проверка для всех классов с именем 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

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

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

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

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

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

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

+0

Мне нравится ваш ответ, но у меня есть что-то такое: Is :: Image ($ arg), Is :: Number ($ arg), а затем некоторые другие методы, организованные следующим образом: :: Image :: PNG ($ arg) и Is :: Number :: Float ($ arg) и Is :: Number :: Integer ($ arg) для основного метода, о котором я думал. :: Number :: Integer :: Prime ($ arg) Я думаю, что здесь сплоченность, я не прав? –

+0

@eyze Надеюсь, вы согласны с тем, что «Является» мешком для всего здесь. Если валидация - это * все * вы делаете , тогда все в порядке. Но тогда у вас не должно быть никаких сомнений относительно математики (нет места для этого). Если валидация - это не все, что вы делаете, я бы предложил вам найти лучшую архитектуру. Не могли бы вы привести пример, как вы планируете использовать Is :: Number :: Integer :: Prime? –

1

Я не думаю, что «есть» относится к именам классов вообще. Я думаю, это для методов.

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'); 
+0

Почему класс I18N_US_Validator не расширяет I18N_US? –

+0

Почему? Я думаю, что Satanicpuppy сказал, что лучше всего: «Функции валидации, даже если они применяются к совершенно разным типам сущностей (простые числа и изображения PNG), имеют больше сходства друг с другом, чем с теми, которые они сравнивают. те же типы данных, они называются в одном и том же виде ». –

0

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

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 
    } 
} 

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^