التعدادات المتقدمة
التعدادات المتقدمة
في الدرسين السابقين تعرّفت على صياغة التعدادات وكيفية إرفاق الحقول والمُنشئات والدوال بالثوابت. يذهب هذا الدرس أبعد من ذلك في ثلاثة محاور تُميّز مبرمج Java المتوسط عن المبتدئ: أجسام الدوال الخاصة بكل ثابت، ومجموعتا EnumSet وEnumMap المتخصّصتان. وعلى طول الطريق ستفهم آلية عمل values() وvalueOf() من الداخل.
أجسام الدوال الخاصة بكل ثابت
يستطيع كل ثابت في التعداد أن يُعيد تعريف دالة مجرّدة (أو غير مجرّدة) مُعلَنة في جسم التعداد. تُسمّى هذه التقنية الجسم الخاص بكل ثابت، وتجعل كل ثابت يحمل تنفيذه الخاص بدلًا من تكرار عبارات switch الضخمة في أكواد الاستدعاء.
انظر مثال نظام معالجة الطلبات حيث تحسب كل شركة شحن تكلفتها بأسلوب مختلف:
الاستخدام واضح — المُستدعي لا يحتاج أن يعرف مع أي شركة شحن يتعامل:
switch على تعداد داخل دالة مساعدة هشّة: إضافة ثابت جديد يعني البحث عن كل switch وتحديثه. أما مع الأجسام الخاصة بالثوابت فتُضيف الثابت وتنفيذه معًا — يجبرك المترجم على توفير الدالة فلا يُنسى شيء.
يمكنك أيضًا إعادة تعريف دالة غير مجرّدة في بعض الثوابت فقط، وترك البقية تعتمد على التنفيذ الافتراضي:
values() و valueOf()
يُولّد المترجم بصمت دالتَين ثابتتَين على كل تعداد:
values()— تُعيد مصفوفة جديدة تحتوي جميع الثوابت بترتيب الإعلان. استخدمها للتكرار.valueOf(String name)— تجد ثابتًا باسمه الدقيق؛ تُطلقIllegalArgumentExceptionإن لم يتطابق الاسم.
valueOf حسّاس لحالة الأحرف. Carrier.valueOf("express") تُطلق IllegalArgumentException في وقت التشغيل. دائمًا حوّل المدخل أولًا: Carrier.valueOf(input.toUpperCase())، أو لفّ الاستدعاء في try-catch.
يرث كل تعداد أيضًا name() (تُعيد اسم الثابت المُعلَن كـ String) وordinal() (تُعيد موضعه بدءًا من الصفر). اعتمد على name() للعرض والتسلسل؛ وكن حذرًا مع ordinal() لأن إدراج ثابت في المنتصف يُغيّر جميع الأرقام التالية.
EnumSet — مجموعات البتات الفعّالة لثوابت التعداد
EnumSet<E extends Enum<E>> هو تنفيذ لواجهة Set محسَّن خصيصًا لثوابت التعداد. داخليًا يستخدم قناعًا بِتيًا من نوع long واحد (أو اثنين للتعدادات التي تتجاوز 64 ثابتًا)، ما يجعل كل عملية — add وcontains وremove — تحقيقًا بِتيًا بزمن O(1) بدلًا من بحث في جدول التشتيت.
EnumSet على HashSet متى كانت عناصر مجموعتك ثوابت تعداد. إنّه أسرع وأقل استهلاكًا للذاكرة، وخرج toString() يكون دائمًا بترتيب الإعلان مما يُسهّل تتبّع الأخطاء.
EnumMap — خريطة مرتّبة وسريعة مفاتيحها ثوابت تعداد
EnumMap<K extends Enum<K>, V> هو رفيق EnumSet. يخزّن القيم في مصفوفة داخلية مُفهرَسة بـ ordinal() لكل ثابت، مما يمنح وصولًا بزمن O(1) مع عبء يكاد يكون صفرًا ويكفل دائمًا التكرار بترتيب الإعلان.
نمط شائع في بيئات العمل الحقيقية هو الجمع بين EnumMap وأجسام الدوال الخاصة بالثوابت. خزّن استراتيجية (دالة lambda أو مرجع دالة) لكل ثابت، ثم اعمل التوزيع عبر الخريطة بدلًا من switch:
الخلاصة
التعدادات المتقدمة أكثر من مجرد ثوابت مسمّاة — إنّها نمط كائني الطابع خفيف الوزن. بالجمع بين أجسام الدوال الخاصة بالثوابت مع EnumSet وEnumMap، يمكنك نمذجة قواعد المجال بوضوح، وتجنّب عبارات switch الهشّة المبعثرة في قاعدة الكود، والاستفادة من خصائص الأداء في المجموعات المحسَّنة للتعدادات. في الدرس القادم ستتعرّف على Records، ميزة Java الحديثة الأخرى التي تُكمل التعدادات.