كيف يمكنني تجنب استخدام الاستثناءات على التحكم في التدفق?

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

سؤال

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

public CustomObject get(String key, Date ifModifiedSince)

في الأساس طريقة من المفترض أن يعود CustomObject المرتبطة key إذا و فقط إذا كان الكائن قد تم تعديله بعد ifModifiedSince.إن نظام التخزين لا يحتوي على key ثم طريقة يجب أن تعود فارغة.

مشكلتي هي هذه:

كيف يمكنني التعامل مع السيناريو حيث المفتاح موجود ولكن الجسم لا تم تعديل?

هذا أمر مهم لأن بعض التطبيقات التي تستخدم هذه الفئة سوف تكون خدمات الويب و تطبيقات الويب.هذه التطبيقات سوف تحتاج إلى معرفة ما إذا كان 404 (غير موجود), 304 (غير معدلة) ، أو 200 (حسنا, ها هي البيانات).

الحلول أنا وزنها هي:

  1. رمي استثناء مخصصة عندما نظام التخزين لا يحتوي على key
  2. رمي استثناء مخصصة عندما ifModifiedSince يفشل.
  3. إضافة خاصية حالة إلى CustomObject.تتطلب المتصل للتحقق من الملكية.

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

ومع ذلك, أنا يميل نحو الخيار 3.

هل هناك خيار أنا لا يفكرون ؟ هل من أحد لديه مشاعر قوية حول أي من هذه الخيارات ؟


الإجابات على هذا السؤال ، اقتبس:

  1. توفر contains طريقة تتطلب المتصل أن نسميها قبل استدعاء get(key, ifModifiedSince), رمي الاستثناء إذا كان المفتاح غير موجود ، العودة فارغة إذا كان كائن لم تعديل.
  2. التفاف استجابة البيانات (إن وجدت) في مركب الكائن.
  3. استخدام محدد مسبقا المستمر للدلالة على بعض الدول (UNMODIFIED, KEY_DOES_NOT_EXIST).
  4. المتصل بتنفيذ تكون واجهة تستخدم الاسترجاعات.
  5. تصميم سيء.

لماذا أنا لا يمكن أن تختار الإجابة #1

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

إذا لم يكن لهذا التقييد ، وهذا من شأنه أن يكون أفضل نهج.

(وأنا أدرك أنني لم أذكر هذا العنصر الهام في السؤال, ولكن كنت أحاول أن اختصر الأمر.من الواضح أنه كان ذات الصلة.)


الخلاصة:

بعد قراءة كل الردود لقد جئت إلى استنتاج مفاده أن المجمع هو النهج الأفضل في هذه الحالة.أساسا سوف تحاكي HTTP, مع البيانات الوصفية (رؤوس) بما في ذلك رمز الاستجابة و محتوى الجسم (رسالة).

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

المحلول

يبدو أنك فعلا تريد العودة إلى بندين:رد رمز الكائن وجدت.قد تفكر في إنشاء خفيفة الوزن المجمع الذي يحمل كل والعودة معا.

public class Pair<K,V>{
  public K first;
  public V second;
}

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

أيضا ، إذا كانت البيانات لم تنته ، بإمكانك العودة ، 303 رمز ليعرفوا أن ذلك هو دون تغيير.4xx سلسلة من شأنه أن يقترن null.

نصائح أخرى

مع شرط لا يمكنك أن تفعل هذا.

إذا كنت مصممة العقد, ثم إضافة شرط وجعل المتصل الاحتجاج

exists(key): bool

خدمة تنفيذ تبدو مثل هذا:

if (exists(key)) {
    CustomObject o = get(key, ifModifiedSince);
    if (o == null) { 
      setResponseCode(302);
    } else {
      setResponseCode(200);
      push(o);
   }

} else {
      setResponseCode(400);
}

العميل لم يتغير و لم تلاحظ كنت قد التحقق من صحة مقدما.

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

ثم عليك أن تلتزم المواصفات و المضي قدما في مثل هذا:

 CustomObject o = get(key, ifModifiedSince);

 if (o != null) {
     setResponseCode(200);
     push(o);
  } else {
     setResponseCode(404); // either not found or not modified.
  }

حسنا, أنت لست إرسال 302 في هذه الحالة, ولكن ربما هذه هي الطريقة التي صمم بها.

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

لذلك لا تقلق بشأن ذلك.التحدث مع مديرك و أعلمه أن هذا القرار.التعليق رمز مع هذا القرار أيضا.و إذا كان لديك مهندس في اليد تأكيد الأساس المنطقي وراء هذا غريب قيود.

وهناك احتمالات أنها لم أتوقع هذا و يمكن تعديل العقد بعد اقتراحكم.

في بعض الأحيان في حين أن الرغبة في المضي قدما الحق نشرع خاطئة تمس الأمن من التطبيق لدينا.

التواصل مع فريق العمل الخاص بك.

يمكنك إنشاء الخاصة النهائي CustomObject بأنه "علامة" تشير إلى دون تغيير:

static public final CustomObject UNCHANGED=new CustomObject();

و اختبار مباراة مع "==" بدلا من .يساوي().

أنها قد تعمل أيضا على العودة فارغة على حالها و رمي استثناء على غير موجود ؟ إذا كان لي أن تختار واحدة من 3 ، سأختار 1 لأن الذي يبدو الأكثر حالة استثنائية.

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

public bool exists( String key ) { ... }

المتصل يمكن القيام به:

if (exists(key)) {
   CustomObject modified = get(key,DateTime.Today.AddDays(-1));
   if (modified != null) { ... }
}

or

try {
    CustomObject modified = get(key,DateTime.Today.AddDays(-1));
}
catch (NotFoundException) { ... }

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

لا أعتقد أن "السيناريو حيث المفتاح موجود ولكن الهدف لم يعدل" استثنائية واحدة ، وبالتأكيد ليس غير طبيعية واحدة.

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

كيف صارمة شرط أن طريقة التوقيع ؟

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

أود مناقشته مع المشرف الخاص بك إذا كان هذا هو الخيار.

كنت لا تزال العودة فارغة.

القصد من الممتلكات هو العودة الكائن الذي تم تعديل بعد التاريخ المحدد.إذا تعود فارغة لا يوجد كائن على ما يرام, فمن المؤكد عودته null معدلة كائن طيب جدا.

أنا شخصيا العودة فارغة غير تعديل الكائن رمي استثناء غير كائن موجود.الذي يبدو أكثر طبيعية.

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

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

هذا يعطيك خيار التالية

  • العودة فارغة إذا كان المفتاح غير موجود.

  • عودة CustomObject.فارغة إذا كان المفتاح موجود ولكن الهدف لم يتم تعديلها.

العيب هو أن المستهلك بحاجة إلى معرفة الفرق بين null قيمة الإرجاع و CustomObject.فارغة قيمة الإرجاع.

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

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

تقديم رد والحجة حيث رد الدرجة يمكن أن تكون أما الحدث مدفوعة ، أو واضع مدفوعة.

لديك الدرجة واجهة تعريف مختلف الأخطاء التي يمكن أن تحدث ، ويمر في CustomObject كما المعلمة الحدث ، إذا لزم الأمر.

public interface Callback {
  public void keyDoesNotExist();
  public void notModified(CustomObject c);
  public void isNewlyModified(CustomObject c);
  .
  .
  .
}

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

إذا كان مقبولا ، قد يعود تضخيم CustomObject (مجمع) الذي يتضمن القيم التي تمثل موضوع تعديل الدولة ، إن وجدت ، وما إلى ذلك.

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