2

假设我的项目中有以下类:

  • class Is //验证类
  • class Math //数字操作类

现在,如果我想验证给定数字的素数,那么插入我的 Prime() 方法的逻辑位置在哪里?我可以想到以下选项:

  • Is_Math ::素数()
  • Math_Is ::素数()

我讨厌这些模棱两可的东西,它们会减慢我的思维过程并经常导致我犯错误。更多示例:

  • 是::Image() 还是 Image::Is() ?
  • Is_Image::PNG() 还是 Image_Is::PNG() ?
  • Is_i18n_US::ZipCode() 或 i18n_Is_US::ZipCode() 或 i18n_US_Is::ZipCode() ?

在 Image 示例中,第一个选择对我来说更有意义,而在 i18n 示例中,我更喜欢最后一个。没有标准让我觉得整个代码库很乱。

是否有组织课程的圣杯解决方案?也许是不同的范式?

4

8 回答 8

10

对于数学示例,我会将检查数字是否为质数的实际功能放在Math类中。在您的Is课程中,您将放置一个在需要进行验证时调用的方法。然后你会Math::Prime()从那里使用。

使用Image,这是一个类型检查。除非您确保已上传有效的图像数据,否则您可能不需要为其创建方法。

方法PNG同上。Math将实际的 PNG 数据检查器算法放入Image并让您的验证器方法Is调用它。

邮政编码示例应该只在您的Is类中,因为它对字符串原语进行操作,并且可能只会使用正则表达式(阅读:它不会是一个复杂的方法,不像您的 PNG 检查器可能会这样)。

于 2009-10-05T20:31:05.380 回答
4

如果您想尊重 SRP ( http://en.wikipedia.org/wiki/Single_responsibility_principle ),请做以下小练习:

选择你的班级并尝试描述它可以做什么/可以做什么。如果您的描述中有“AND”,则必须将该方法移至其他类。

见第 36 页:http: //misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf

其他有助于组织课程的法律(还有更多):得墨忒耳法则(http://en.wikipedia.org/wiki/Law_of_Demeter)。

为了学到很多东西并帮助你做出正确的选择,我建议你米斯科的博客(谷歌传道者): http: //misko.hevery.com

希望这可以帮助。

于 2009-10-05T22:58:58.587 回答
3

处理验证本身的所有内容都适合您的Is-classes:

  • 它通过了吗?
  • 哪些部分没有通过?
  • 验证错误是否应该记录在某处?

Zend Framework 中的Zend_Validate提供了这样一种方法,也许你可以从中得到一些启发。由于这种方法会让您在所有验证类中实现相同的接口,因此您可以轻松地

  • 使用相同的语法进行验证,独立于验证哪些数据
  • 通过检查所有名为 的类Is_PrimeIs_Image而不是检查Math_Is,轻松识别您可用的验证规则Image_Is

编辑:
为什么不使用这样的语法:

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);
        }
    }
}
于 2009-10-10T15:39:42.070 回答
3

我不认为这是模棱两可的。“Is”应该在每个示例中都排在第一位,我会告诉你原因:“Is”是验证操作的超集,其中 Is::Math 是其中的一个成员。

在 Is::Math 的情况下,你在做什么?你在做数学运算吗?或者你在验证数学实体?显然是后者,否则它只是“数学”。

这两个操作中哪一个具有更大的范围?是?还是数学?显然,因为 Is 在概念上适用于许多非数学实体,而数学是特定于数学的。(同样,在 Math::Factor 的情况下,它不会是 Factor::Math,因为 Math 是 Factor 所属的超集。)

这种类型的 OOPing 的全部目的是以有意义的方式对事物进行分组。验证函数,即使它们适用于完全不同类型的实体(质数与 PNG 图像),它们彼此之间的相似性也比它们与所比较的事物的相似性要多。它们将返回相同类型的数据,它们在相同的情况下被调用。

于 2009-10-14T15:25:26.460 回答
1

我认为您所说的问题没有“正确答案”。有些人会将 Prime 放在 Is 中,而有些人会将 Prime 放在 Math 中。有歧义。否则你不会问这个问题。

现在,您必须以某种方式解决歧义。您可以考虑一些规则和约定,这将说明哪个类/方法在哪里。但这可能很脆弱,因为规则并不总是显而易见的,它们可能会变得非常复杂,到那时它们就不再有用了。

我建议您设计这些类,以便通过查看某些方法应该使用的名称来显而易见。

不要将您的验证包命名为。这个名字太笼统了,几乎所有东西都在那里。IsFile、IsImage、IsLocked、IsAvailable、IsFull - 听起来不太好,好吗?这种设计没有凝聚力

让验证组件在子系统边界(您必须执行安全和业务规则)过滤数据可能会更好,仅此而已。

做出这个决定后,你的例子就很明显了。Prime 属于数学。Is::Image 可能太笼统了。我更喜欢 Image::IsValid,因为您可能还会有其他方法对图像进行操作(更具凝聚力)。否则,正如我在开头所说的那样,“是”会成为一切的包袱。

于 2009-10-11T10:31:20.763 回答
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' );
于 2009-10-14T22:26:39.343 回答
0

是否有组织课程的圣杯解决方案?也许是不同的范式?

不,这是基于类的 oop 的一个基本缺陷。这是主观的。

函数式编程(不要与过程式编程混淆)在这方面的问题较少,主要是因为主要的构建块要小得多。无类 oop 也处理得更好,它是 oop 和各种函数式编程的混合体。

于 2009-10-05T21:06:52.943 回答
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
   }
}

这种方法的一个优点是您可以继续创建新的验证类型,并且您不会得到一个膨胀的 Is 类。

这种方法有更优雅的变化。这是一个简单的变化。语法可能需要清理。

于 2009-10-14T23:37:03.690 回答