محتويات الدورة
Ruby
الأساسيات: القيم والطرق والنص والكائنات الصالحة
العقود: الاستدعاء والتقييم والإخفاق ونماذج القيم
التكامل: البيانات والموارد وأدلة التنفيذ والثقة

Ruby / الأساسيات: القيم والطرق والنص والكائنات الصالحة / الدرس 6

بناء كائنات صالحة وضبط سطحها العام

استخدم initialize ومتغيرات المثيل والقراء وعمليات متحققة ومساعدات خاصة ومساحات أسماء دون جعل الرؤية ضمان أمان.

وقت القراءة التقريبي: 4 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • اجعل كل انتقال حالة عام متسقا مع قيد الكائن.
  • ميّز حالة المثيل وحالة الصنف والوراثة ورؤية الطرق.

هيّئ الحالة التي تعتمد عليها الطرق العامة

عند استدعاء Class#new الموروثة على صنف، مثل ArchiveCounter.new(1)، تُخصص عادة نسخة من ذلك الصنف وتُستدعى initialize لتهيئة حالتها. أما Class.new نفسها فتنشئ صنفاً مجهول الاسم. تخص متغيرات المثيل مثل @remaining المثيل الذي أُنشئ؛ وتعطي قراءة متغير مثيل غير مضبوط nil، فتؤجل عيب الإعداد لاستدعاء لاحق. فضّل معاملات منشئ مطلوبة وتحققاً صريحاً على كائن جزئي بخطوات يتذكرها العميل. تولّد attr_reader طريقة لقراءة قيمة العضو، وتضيف attr_accessor أيضاً طريقة لإسناد قيمته قد تتجاوز القيد. تعرف هذه الوسائل طرقا حقيقية؛ فراجع أثرها في الواجهة ولا تعدها حقولا بلا عواقب.

اعرض عملية بدلا من إسناد بلا قيود

لا يقبل عداد الأرشيف عند البناء إلا سعة موجبة من Integer، ويرفض الصفر والسالب والكسور مثل 0.5 والأنواع الأخرى. تستهلك كل عملية consume عادية وحدة واحدة فقط ما دامت وحدة كاملة باقية؛ لذلك يظل العدد المخزن Integer غير سالب ويمكن أن يصل إلى الصفر. ويوفر طريقة لقراءة الحالة دون طريقة إسناد مولدة. يثبت ذلك بروتوكولا محليا متتابعا، لا تخصيصا دائما أو معاملة آمنة للخيوط. ليست قدرات الانعكاس والرؤية في Ruby حدود أمان ضد شيفرة غير موثوقة في العملية. يشرح المثال واجهة ضيقة للمستدعي العادي؛ ويحتاج الدوام والتفويض والتزامن مالكين وأدلة منفصلة. يبقى المخرج غير منفذ لغياب Ruby.

ruby واجهة حالة محلية ضيقة
class ArchiveCounter
  attr_reader :remaining
  def initialize(count)
    unless count.is_a?(Integer) && count > 0
      raise ArgumentError, 'positive Integer capacity required'
    end
    @remaining = count
  end
  def consume
    return false if @remaining.zero?
    @remaining -= 1
    true
  end
end
counter = ArchiveCounter.new(1)
puts counter.consume
puts counter.consume
puts counter.remaining
الناتج المتوقع
true
false
0

المخرج المتوقع true ثم false ثم 0. لا يقبل البناء إلا سعة موجبة من Integer؛ ويرفض 0.5 والقيم غير الموجبة والأنواع الأخرى برفع ArgumentError وفق الشرط المعلن. وقد يصل العدد المتبقي إلى الصفر بعد الاستهلاك. هذا تحليل محلي متتابع، لا ضمان تزامن أو حفظ دائم. لم يُنفذ السكربت.

استخدم الرؤية لنقل قصد الواجهة

تؤثر public و private و protected في الاستدعاء العادي وفق التعاون المقصود. تعبر المساعدة الخاصة عن تفاصيل التنفيذ، وتدعم protected وصول أقران معينين في نموذج الوراثة. تهم قواعد المستقبل الدقيقة، فلا تقدم الرؤية كنظام تفويض للمستخدم الخارجي. قد يتجاوز صنف فرعي سلوكا، ويكشف استدعاء قابل للتجاوز أثناء البناء حالة قبل الجاهزية. فضّل التركيب عند مجرد استخدام قدرة، ووثّق مدخل الوراثة وردها وآثارها وهل يجوز إضعاف القيد.

سم المسؤوليات دون تصادمات عامة

توفّر Modules مساحات أسماء إلى جانب mixins. يضع المثال كائن تسمية داخل Archive ويحصر مساعد التنسيق. ينسخ النص الوارد فلا يغير تعديل الأصل لدى المستدعي النص المخزن. هذا نسخ ضيق لـ String لا سياسة استنساخ عميق لكل كائن. تختلف مستقبلات طرق الصنف مثل self.build عن طرق المثيل كـ display. تجنب متغيرات الصنف لحالة تخص مثيلا؛ فقد تفاجئ المشاركة والوراثة سلوكها.

ruby مساحة أسماء ومساعد تنفيذ خاص
module Archive
  class Label
    def initialize(text)
      @text = text.dup
    end
    def display
      format_text
    end
    private
    def format_text
      "[#{@text.upcase}]"
    end
  end
end
original = String.new('catalog')
label = Archive::Label.new(original)
original << '-changed'
puts label.display
الناتج المتوقع
[CATALOG]

المخرج المتوقع [CATALOG]. يعزل نسخ النص الإضافة اللاحقة إلى original. هذا مخرج محلل فقط؛ ولم يُنفذ مفسر أو اختبار رؤية.

افحص سطح التعديل العام كله

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

الأخطاء الشائعة وإصلاحها

يسمح كاتب مولد بعدد غير صالح.

لماذا يحدث؟
كشفت attr_accessor تعديلا خارج العملية المتحققة.
كيف تصلحه؟
استخدم قارئا وانتقالات متحققة حيث يقتضي القيد.
كيف تتجنب تكراره؟
راجع macros كجزء من الطرق العامة.

يسبب متغير مثيل غير مهيأ فشل nil لاحقا.

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

تُعرض الطرق الخاصة حماية من شيفرة عدائية في العملية.

لماذا يحدث؟
اختلطت رؤية الواجهة بعزل أمني.
كيف تصلحه؟
استخدم حدود ثقة وعملية مناسبة للتنفيذ غير الموثوق.
كيف تتجنب تكراره؟
افصل تغليف المطور عن تفويض المستخدم.

اختبر فهمك

1. لماذا قد تسرّب attr_reader حالة قابلة للتعديل؟

اعرض الحل المشروح

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

2. هل يثبت ArchiveCounter استحالة استهلاك مخزون حقيقي مرتين؟

اعرض الحل المشروح

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

أهم ما تعلمته

  • يجب أن يحفظ البناء وكل انتقال عام القيد نفسه.
  • التغليف والملكية والأمان والدوام مسؤوليات منفصلة.

المراجع الرسمية