سؤال

افترض أن لدي الفصول التالية في مشروعي:

  • صف دراسي يكون // فئة التحقق من الصحة
  • صف دراسي الرياضيات // رقم الفئة التلاعب

الآن، إذا كنت ترغب في التحقق من صحة رقم معين للبدادة، حيث سيكون المكان المنطقي لإدراج الطريقة الرئيسية ()؟ يمكنني التفكير في الخيارات التالية:

  • is_math.:: رئيس ()
  • math_is.:: رئيس ()

أنا أكره هذه الغموض، وإبطاء عملية تفكيري وغالبا ما تحفزني في الأخطاء. بعض الأمثلة الأخرى:

  • هو :: صورة () أو صورة :: هو ()؟
  • is_image :: PNG () أو Image_is :: PNG ()؟
  • is_i18n_us :: zipcode () أو i18n_is_us :: zipcode () أو i18n_us_is :: zipcode ()؟

في مثال الصورة، فإن الخيار الأول يجعلني أكثر معنى لي أثناء وجوده في مثال I18N أفضل آخر واحد. عدم وجود معيار يجعلني أشعر وكأن قاعدة الكود بأكملها فوضوي.

هل هناك حل من الجبال المقدسة لتنظيم الطبقات؟ ربما نموذج مختلف؟

هل كانت مفيدة؟

المحلول

لا أعتقد أنها غامضة على الإطلاق. "يجب أن يكون" "هو الأول في كل من هذه الأمثلة، وسأخبرك لماذا:" هو "هو استبعاد عمليات التحقق منها :: الرياضيات عضو.

في حالة :: الرياضيات، ماذا تفعل؟ هل تقوم بعمليات الرياضيات؟ أم أنك تتحقق من صحة الكيانات الرياضية؟ هذا الأخير، من الواضح، وإلا سيكون "الرياضيات" فقط.

أي من هاتين العمليات لديها نطاق أكبر؟ يكون؟ أو الرياضيات؟ من الواضح أن ذلك ينطبق من الناحية النظرية على العديد من الكيانات غير الرياضيات، في حين أن الرياضيات محددة للرياضيات. (وبالمثل في حالة الرياضيات :: عامل، لن يكون ذلك عامل :: الرياضيات، لأن الرياضيات هي الحلبة التي ينتمي إليها عامل.)

الغرض كله من هذا النوع من Ooping هو جماعة الأمور بطريقة منطقية. وظائف التحقق من الصحة، حتى عندما تنطبق على أنواع مختلفة من الكيانات (الأرقام الأولية مقابل صور PNG) لديها أوجه التشابهات الأخرى لبعضها البعض مما يفعلون في الأشياء التي يقارنونها. سيعودون نفس أنواع البيانات، يتم استدعاؤهم في نفس النوع من المواقف.

نصائح أخرى

مثال الرياضيات، سأضع الوظيفة الفعلية للتحقق مما إذا كان الرقم رئيسا في Math صف دراسي. في الخاص بك Is فئة كنت قد وضعت طريقة سيتم استدعاؤها عند حدوث التحقق من الصحة. سوف تستخدم بعد ذلك Math::Prime() من هناك.

مع Image, هذا هو التحقق من النوع. ربما لا تحتاج إلى إجراء طريقة لذلك إلا إذا كنت تتأكد من تحميل بيانات الصورة الصحيحة.

مع ال PNG الطريقة، نفس الشيء مع Math. وبعد ضع خوارزمية مدقق بيانات PNG الفعلي في Image وجعل طريقة التحقق من المدقق في Is نسميها.

يجب أن يكون مثال الرمز البريدي في Is فئة فقط لأنها تعمل على سلسلة بدائية وربما ستستخدم فقط RegExP (قراءة: لن تكون طريقة معقدة، على عكس مدقق PNG الخاص بك والتي ربما تكون).

إذا كنت ترغب في احترام SRP (http://en.wikipedia.org/wiki/single_reponibonivity_principle.)، هل التمرين الصغير:

حدد صفك وحاول وصف ما يفعله / يمكن القيام به. إذا كان لديك "و" في وصفك، يجب عليك نقل الطريقة إلى فئة أخرى.

انظر الصفحة 36: http://misko.hevery.com/attachments/guide-writing٪20testable٪20code.pdf.

قانون آخر (هناك الكثير) من شأنه أن يساعدك في تنظيم فصولك: قانون demeter (http://en.wikipedia.org/wiki/law_of_demeter.).

لتعلم الكثير ومساعدتك في اتخاذ الاختيار الصحيح، وأنا نصيحة لك مدونة misko (مبشر جوجل): http://misko.hevery.com.

أتمنى أن يساعدك هذا.

كل شيء عن التعامل مع التحقق من الصحة في حد ذاته سوف يصلح في الخاص بك Is-الطبقات:

  • هل تمر؟
  • ما الأجزاء التي لم تمر؟
  • يجب تسجيل أخطاء التحقق من الصحة في مكان ما؟

zend_validate. في ZEND Framage يوفر هذا النهج، ربما يمكنك الحصول على بعض الإلهام منه. نظرا لأن هذا النهج سيكون لديك نفس الواجهة في جميع فئات التحقق من الصحة، فيمكنك بسهولة

  • استخدم بناء الجملة نفسه للتحقق من الصحة، بشكل مستقل يتم التحقق من صحة البيانات
  • يمكنك التعرف بسهولة على قواعد التحقق من الصحة التي تتوفر بها عن طريق التحقق من جميع الفئات المسماة Is_Prime, Is_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);
        }
    }
}

أعتقد أنه لا يوجد "الإجابة الصحيحة" للمشكلة التي ذكرتها. بعض الناس سوف يضعون رئيسي في الرياضيات. هناك غموض. وإلا فلن تطرح هذا السؤال.

الآن، عليك حل الغموض بطريقة أو بأخرى. يمكنك التفكير في بعض القواعد والاتفاقيات، والتي سيقول أي فئة / طريقة تذهب إلى أين. ولكن قد يكون هذا هشا، حيث أن القواعد ليست واضحة دائما، وقد تصبح معقدة للغاية، وفي تلك المرحلة لم تعد مفيدة.

أقترح عليك تصميم الفصول بحيث من الواضح عن طريق النظر إلى الأسماء التي يجب أن تذهب فيها بعض الطريقة.

لا تسميت حزمة التحقق من الصحة. إنه اسم عام للغاية أن كل شيء تقريبا يذهب هناك. ISFile، IsIsage، Islocked، Isavailable، Isfoll - لا يبدو جيدا، حسنا؟ لا يوجد تماسك مع هذا التصميم.

من الأفضل أن تجعل بيانات تصفية مكون التحقق من الصحة في حدود النظم الفرعية (حيث يتعين عليك تطبيق قواعد الأمان والأعمال)، أي شيء آخر.

بعد اتخاذ هذا القرار، يصبح مثالك واضحا. رئيس الوزراء ينتمي في الرياضيات. هو :: الصورة ربما تكون عامة جدا. أفضل الصورة :: Isvalid، لأنك ربما تحتوي أيضا على طرق أخرى تعمل على صورة (المزيد من التماسك). خلاف ذلك "هو" يصبح حقيبة لكل شيء, ، كما قلت في البداية.

لا أعتقد أن "هو" ينتمي إلى أسماء الطبقة على الإطلاق. أعتقد أن هذا للطرق.

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

هل هناك حل من الجبال المقدسة لتنظيم الطبقات؟ ربما نموذج مختلف؟

لا، هذا هو عيب أساسي من OOP على أساس الفصل. انها ذاتية.

البرمجة الوظيفية (عدم الخلط بين البرمجة الإجرائية) لديها مشاكل أقل في هذه المسألة، ومعظمها لأن كتل المبنى الأساسية أصغر بكثير. صفقات OOP Classless أيضا أفضل، كونها هجينة من OOP البرمجة الوظيفية للفردين.

يمكن اعتبار الطبقات أن تكون أنواعا خيالية تفعل الأشياء، مثل التحقق من صحة أنفسهم.

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

نحن تمديد التحقق من الصحة لإنشاء نوع التحقق من الصحة. هذا يلزمنا بإنشاء طريقة ISVALL.

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

ميزة واحدة من هذا النهج هي أنه يمكنك الاستمرار في إنشاء أنواع التحقق من صحة جديدة، ولا تحصل على اتصال بالون.

هناك اختلافات أكثر أناقة في هذا النهج. هذا هو اختلاف بسيط. قد يتطلب بناء الجملة التنظيف.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top