كيف يمكنك التحقق من صحة كائن الداخلية في الدولة ؟

StackOverflow https://stackoverflow.com/questions/343605

  •  19-08-2019
  •  | 
  •  

سؤال

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

الأساسي هو التركيز على C++, منذ ذلك الحين في C# الرسمي السائد هو رمي استثناء ، في C++ ليس هناك واحد فقط واحد طريقة للقيام بذلك (حسنا, ليس حقا في C# إما أنا أعرف ذلك).

علما أنني لا نتحدث عن وظيفة معلمة التحقق من صحة, ولكن أكثر مثل فئة ثابتة سلامة الشيكات.

على سبيل المثال, دعونا نقول أننا نريد Printer كائن إلى Queue مهمة طباعة بشكل غير متزامن.المستخدم من Printer, أن العملية لا يمكن أن تنجح إلا لأنه غير متزامن انتظار النتيجة مع ما يصل في وقت آخر.لذا لا توجد أي صلة رمز الخطأ أن ينقل إلى المتصل.

ولكن Printer وجوه هذه العملية يمكن أن تفشل إذا كانت الدولة الداخلية سيئة ، أي فئة ثابتة مكسورة ، وهو ما يعني أساسا:الخلل.هذه الحالة ليست بالضرورة من أي تهم المستخدم من Printer الكائن.

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

النمط الأول يمكنني استخدام أفضل تفشل في السيطرة عليها من البيانات الفاسدة:

void Printer::Queue(const PrintJob& job)
{
    // Validate the state in both release and debug builds.
    // Never proceed with the queuing in a bad state.
    if(!IsValidState())
    {
        throw InvalidOperationException();
    }

    // Continue with queuing, parameter checking, etc.
    // Internal state is guaranteed to be good.
}

النمط الثاني استخدام أفضل الحادث لا يمكن السيطرة عليها من البيانات الفاسدة:

void Printer::Queue(const PrintJob& job)
{
    // Validate the state in debug builds only.
    // Break into the debugger in debug builds.
    // Always proceed with the queuing, also in a bad state.
    DebugAssert(IsValidState());

    // Continue with queuing, parameter checking, etc.
    // Generally, behavior is now undefined, because of bad internal state.
    // But, specifically, this often means an access violation when
    // a NULL pointer is dereferenced, or something similar, and that crash will
    // generate a dump file that can be used to find the error cause during
    // testing before shipping the product.
}

النمط الثالث يمكنني استخدام أفضل بصمت و دفاعيا إنقاذ من البيانات الفاسدة:

void Printer::Queue(const PrintJob& job)
{
    // Validate the state in both release and debug builds.
    // Break into the debugger in debug builds.
    // Never proceed with the queuing in a bad state.
    // This object will likely never again succeed in queuing anything.
    if(!IsValidState())
    {
        DebugBreak();
        return;
    }

    // Continue with defenestration.
    // Internal state is guaranteed to be good.
}

ملاحظاتي على الأساليب:

  1. أعتقد أنني أفضل النمط الثاني ، حيث فشل ليست خفية ، شريطة أن حدوث انتهاك وصول في الواقع أسباب الحادث.
  2. إذا لم يكن مؤشر فارغة المشاركة في ثابتة ، ثم تميل إلى الانكفاء نحو النمط الأول.
  3. أنا حقا لا يروق النمط الثالث ، لأنه سوف إخفاء الكثير من الأخطاء, ولكن أنا أعلم الناس أن يفضل عليه في إنتاج البرمجية لأنه يخلق الوهم من البرامج القوية التي لا تعطل (ميزات مجرد التوقف عن العمل ، كما في الطابور على كسر Printer كائن).

هل تفضل أي من هذه أو هل لديك طرق أخرى لتحقيق هذا ؟

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

المحلول

السؤال هو الأفضل النظر في تركيبة مع كيف يمكنك اختبار البرنامج.

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

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

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

نصائح أخرى

يمكنك استخدام تقنية تسمى NVI (غير ظاهري-واجهة) جنبا إلى جنب مع template method نمط.ربما هذا هو كيف نفعل ذلك (بالطبع هذا فقط رأيي الشخصي ، الذي هو في الواقع قابلة للنقاش):

class Printer {
public:
    // checks invariant, and calls the actual queuing
    void Queue(const PrintJob&);
private:
    virtual void DoQueue(const PringJob&);
};


void Printer::Queue(const PrintJob& job) // not virtual
{
    // Validate the state in both release and debug builds.
    // Never proceed with the queuing in a bad state.
    if(!IsValidState()) {
        throw std::logic_error("Printer not ready");
    }

    // call virtual method DoQueue which does the job
    DoQueue(job);
}

void Printer::DoQueue(const PrintJob& job) // virtual
{
    // Do the actual Queuing. State is guaranteed to be valid.
}

لأن Queue هو غير ظاهري ، ثابتة لا يزال التحقق إذا فئة مشتقة يتجاوز DoQueue من أجل معالجة خاصة.


إلى الخيارات الخاصة بك:أعتقد أن ذلك يعتمد على حالة كنت تريد أن تحقق.

إذا كانت داخلية ثابتة

إذا كان هو غير ثابتة, فإنه لا ينبغي أن يمكن للمستخدم من الفئة الخاصة بك لمخالفة ذلك.الطبقة ينبغي العناية عن ثابتة في نفسها.لذلك ، أود أن assert(CheckInvariant()); في مثل هذه الحالة.

انها مجرد شرط من طريقة

إذا كان مجرد شرط أن مستخدم الفئة يجب أن ضمان (أقول الطباعة فقط بعد الطابعة جاهزة), وأود أن رمي std::logic_error كما هو مبين أعلاه.

أنا حقا تثبط من تحقق الشرط ، ولكن بعد ذلك لا تفعل شيئا.


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

إنه جيد جدا السؤال ذي الصلة.IMHO ، أي تطبيق العمارة ينبغي أن توفر استراتيجية التقرير كسر الثوابت.واحد يمكن أن ترغب في استخدام الاستثناءات ، 'خطأ التسجيل' الكائن أو صراحة تحقق نتيجة أي عمل.ربما بل هناك استراتيجيات أخرى - هذا ليس النقطة.

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

على NonVirtual واجهة الحل من litb هو أنيق طريقة للتحقق من الثوابت.

سؤال صعب هذا واحد :)

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

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

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

أعتقد أن ما أقوله هو أن imho هذا السؤال هو شيء يجب أن تحل على مستوى التصميم من التطبيق الخاص بك وليس على مستوى التنفيذ. و للأسف لا توجد حلول سحرية :(

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