2

プロジェクトに次のクラスがあるとします。

  • class Is //検証クラス
  • class Math //数値操作クラス

さて、与えられた数の素数を検証したい場合、Prime() メソッドを挿入する論理的な場所はどこでしょうか? 次のオプションを考えることができます。

  • Is_Math ::プライム()
  • Math_Is ::プライム()

私はこれらのあいまいさが嫌いで、思考プロセスが遅くなり、しばしばエラーを引き起こします。いくつかの例:

  • 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呼び出します。

zipコードの例は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 )。

多くのことを学び、正しい選択をするために、Misko のブログ (Google エバンジェリスト) をお勧めします: http://misko.hevery.com

お役に立てれば。

于 2009-10-05T22:58:58.587 に答える
3

検証自体の処理に関するすべては、Isクラスに適合します。

  • 合格しましたか?
  • どの部分が合格しませんでしたか?
  • 検証エラーはどこかに記録する必要がありますか?

Zend FrameworkのZend_Validateは、そのようなアプローチを提供します。おそらく、そこからインスピレーションを得ることができます。このアプローチでは、すべての検証クラスに同じインターフェイスを実装する必要があるため、簡単に実行できます。

  • どのデータが検証されるかに関係なく、検証に同じ構文を使用します
  • をチェックするのではなく、Is_Primeという名前のすべてのクラスをチェックすることで、使用可能な検証ルールを簡単に認識できます。Is_ImageMath_IsImage_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 の場合、何をしていますか? 数学演算をしていますか?それとも、数学的実体を検証していますか? 後者は明らかに、それ以外の場合は単に「数学」になります。

これら 2 つの操作のどちらがより大きな範囲を持っていますか? は?それとも数学?明らかに、Is は数学以外の多くのエンティティに概念的に適用できるため、Math は Math 固有です。(Math::Factor の場合も同様に、Factor::Math にはなりません。なぜなら、Math は Factor が属するスーパーセットだからです。)

このタイプの OOPing の全体的な目的は、意味のある方法で物事をグループ化することです。検証関数は、非常に異なる種類のエンティティ (素数と PNG 画像) に適用される場合でも、比較対象のものよりも相互に類似性があります。それらは同じタイプのデータを返し、同じ種類の状況で呼び出されます。

于 2009-10-14T15:25:26.460 に答える
1

「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' );
于 2009-10-14T22:26:39.343 に答える
1

あなたが述べた問題に対する「正解」はないと思います。Prime を Is に入れる人もいれば、Math に入れる人もいます。あいまいさがあります。そうでなければ、あなたはこの質問をしていないでしょう。

さて、どうにかしてあいまいさを解決する必要があります。どのクラス/メソッドがどこに行くかを示す、いくつかの規則と規則について考えることができます。しかし、ルールが常に明白であるとは限らず、非常に複雑になる可能性があるため、これは脆弱である可能性があり、その時点でそれらは役に立たなくなります。

クラスを設計することをお勧めします。メソッドの名前を見て、どこに行くべきかが明確になるようにすることです。

検証パッケージに Is という名前を付けないでください。それは非常に一般的な名前であるため、ほとんどすべてがそこにあります。IsFile、IsImage、IsLocked、IsAvailable、IsFull - 聞こえが悪いですね。あのデザインに統一感はありません。

おそらく、検証コンポーネントがサブシステムの境界 (セキュリティとビジネス ルールを適用する必要がある場所) でデータをフィルター処理するようにする方が良いでしょう。

その決定を下した後、あなたの例が明らかになります。プライムは数学に属します。Is::画像はおそらく一般的すぎます。Image::IsValid の方がいいと思います。なぜなら、おそらく画像に対して操作する他のメソッドもあるからです (よりまとまりがあります)。そうでなければ、最初に言ったように、「Is」はすべてのバッグになります。

于 2009-10-11T10:31:20.763 に答える
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
   }
}

このアプローチの利点の 1 つは、新しい検証型を作成し続けることができ、バルーニング Is クラスを取得しないことです。

このアプローチには、より洗練されたバリエーションがあります。これは単純なバリエーションです。構文をクリーンアップする必要がある場合があります。

于 2009-10-14T23:37:03.690 に答える
0

クラスを編成するための聖杯のソリューションはありますか? 多分別のパラダイム?

いいえ、それはクラスベースの oop の基本的な欠陥です。それは主観的です。

関数型プログラミング (手続き型プログラミングと混同しないでください) では、主なビルディング ブロックがはるかに小さいため、この問題はあまり問題になりません。また、クラスレス oop は、oop と関数型プログラミングのハイブリッドであり、より優れた処理を行います。

于 2009-10-05T21:06:52.943 に答える