شعار ConstructiCat
CodeBust.
تصفح القسم ▾

فصل الاستعلام عن التعديل.

المشكلة

هل لديك دالة تعيد قيمة ولكنها تغير أيضًا شيئًا ما داخل الكائن؟

الحل

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

##مثال

قبل
String foundMiscreant(String[] people) {
  for (String person : people) {
    if (person.equals("Don") || person.equals("John")) {
      sendAlert();
      return person;
    }
  }
  return "";
}
بعد
void checkSecurity(String[] people) {
  sendAlert(people);
  String found = foundPerson(people);
  someLaterCode(found);
}
void sendAlert(String[] people) {
  if (!foundPerson(people).isEmpty()) notifySecurity();
}
String foundPerson(String[] people) {
  for (String person : people) {
    if (person.equals("Don") || person.equals("John")) return person;
  }
  return "";
}

##لماذا نعيد الهيكلة

تنفذ تقنية إعادة الهيكلة هذه مبدأ فصل الأوامر عن الاستعلامات (Command-Query Separation, CQS). يخبرنا هذا المبدأ بفصل الكود المسؤول عن جلب البيانات عن الكود الذي يغير شيئًا ما داخل الكائن.

يسمى كود جلب البيانات بـ الاستعلام (query). ويسمى كود تغيير الأشياء في الحالة المرئية (visible state) للكائن بـ التعديل (modifier). عندما يتم دمج الاستعلام و التعديل، فلن تكون لديك طريقة للحصول على البيانات دون إجراء تغييرات على حالتها. بعبارة أخرى، أنت تسأل سؤالاً ويمكنك تغيير الإجابة أثناء تلقيها. تصبح هذه المشكلة أكثر خطورة عندما لا يعرف الشخص الذي يستدعي الاستعلام بالآثار الجانبية للدالة، مما يؤدي غالبًا إلى أخطاء في وقت التشغيل.

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

##الفوائد

  • إذا كان لديك استعلام (query) لا يغير حالة البرنامج، فيمكنك استدعاؤه لعدد المرات التي تريدها دون الحاجة للقلق بشأن التغييرات غير المقصودة في النتيجة الناتجة عن مجرد استدعائك للدالة.

##كيفية إعادة الهيكلة

  1. أنشئ دالة استعلام (query method) جديدة لإرجاع ما كانت تفعله الدالة الأصلية.

  2. قم بتغيير الدالة الأصلية بحيث تعيد فقط نتيجة استدعاء دالة الاستعلام الجديدة.

  3. استبدل جميع الإشارات إلى الدالة الأصلية باستدعاء لـ دالة الاستعلام. وقبل هذا السطر مباشرةً، ضع استدعاءً لـ دالة التعديل (modifier method). سيحميك هذا من الآثار الجانبية في حالة استخدام الدالة الأصلية في شرط لمعامل شرطي أو حلقة تكرار.

  4. تخلص من كود إرجاع القيمة في الدالة الأصلية، والتي أصبحت الآن دالة تعديل حقيقية.