Menu
CoddyTech

نمط المراقب (Events)

جزء من قسم البرمجة كائنية التوجه في رحلة C# على Coddy. الدرس 54 من 70.

ينشئ نمط المراقب علاقة واحد إلى متعدد، حيث يُخطِر كائن واحد (الموضوع) عدة كائنات تابعة (مراقبين) عند تغيّر حالته. في C#، توفّر الأحداث طريقة مدمجة لتطبيق هذا النمط بأناقة.

يتضمن هذا النمط ناشرًا يطلق أحداثًا ومشتركين يستجيبون لها. إليك مثالًا عمليًا على مراقبة أسعار الأسهم:

public class Stock
{
    private decimal _price;
    
    public event Action<decimal> PriceChanged;
    
    public decimal Price
    {
        get => _price;
        set
        {
            _price = value;
            PriceChanged?.Invoke(_price);  // أبلغ جميع المراقبين
        }
    }
}

public class PriceAlert
{
    public void OnPriceChanged(decimal newPrice)
    {
        Console.WriteLine($"Alert: Price is now {newPrice}");
    }
}

public class PriceLogger
{
    public void OnPriceChanged(decimal newPrice)
    {
        Console.WriteLine($"Logged: {newPrice}");
    }
}

يربط المشتركون أساليبهم بالحدث باستخدام +=، ويمكنهم إلغاء ربطها باستخدام -=:

var stock = new Stock();
var alert = new PriceAlert();
var logger = new PriceLogger();

stock.PriceChanged += alert.OnPriceChanged;
stock.PriceChanged += logger.OnPriceChanged;

stock.Price = 150.50m;
// الإخراج:
// تنبيه: السعر الآن 150.50
// تم التسجيل: 150.50

stock.PriceChanged -= logger.OnPriceChanged;  // إلغاء الاشتراك
stock.Price = 155.00m;
// الإخراج: تنبيه: السعر الآن 155.00

يعزز نمط المراقب الاقترانَ الضعيف - فلا تحتاج الفئة Stock إلى معرفة أي شيء عن مراقبيها. يمكن للمراقبين الجدد الاشتراك دون تعديل الناشر، مما يجعل النظام سهل التوسيع والصيانة.

challenge icon

التحدي

سهل

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

ستنظم الكود في ثلاثة ملفات:

  • TemperatureSensor.cs: أنشئ صنف TemperatureSensor في مساحة الأسماء Monitoring. هذا هو الناشر لديك، أي الكائن الذي ستراقبه الكائنات الأخرى. ينبغي أن يحتوي المستشعر على:
    • حقل خاص لتخزين درجة الحرارة الحالية
    • حدث يُسمى TemperatureChanged ويستخدم Action<double> لإخطار المشتركين بدرجة الحرارة الجديدة
    • خاصية Temperature تُطلق الحدث كلما عُيّنت درجة الحرارة على قيمة جديدة
  • Observers.cs: أنشئ صنفي مراقبَين في مساحة الأسماء نفسها، ليشتركا في تلقي إشعارات تغيّر درجة الحرارة:
    • DisplayUnit - يحتوي على دالة OnTemperatureChanged(double temp) تطبع Display: {temp}C
    • AlarmSystem - يحتوي على دالة OnTemperatureChanged(double temp) تطبع Alarm Check: {temp}C
  • Program.cs: اجمع كل شيء بإنشاء مستشعر وكلا المراقبَين. اجعل كلا المراقبَين يشتركان في حدث المستشعر، ثم حدّث درجة الحرارة. بعد ذلك، ألغِ اشتراك نظام الإنذار وحدّث درجة الحرارة مرة أخرى لتوضيح أن وحدة العرض وحدها تتلقى الإشعار.

ستتلقى قيمتَي إدخال:

  • قراءة درجة الحرارة الأولى (مثل 22.5)
  • قراءة درجة الحرارة الثانية (مثل 28.0)

ينبغي أن ينفذ برنامجك ما يلي:

  1. إنشاء المستشعر وكلا المراقبَين
  2. جعل كلا المراقبَين يشتركان في حدث TemperatureChanged
  3. تعيين درجة حرارة المستشعر إلى قيمة الإدخال الأولى (ينبغي إخطار كلا المراقبَين)
  4. إلغاء اشتراك AlarmSystem في الحدث
  5. تعيين درجة حرارة المستشعر إلى قيمة الإدخال الثانية (ينبغي إخطار وحدة العرض وحدها)

على سبيل المثال، إذا كانت قيمتا الإدخال 22.5 و28.0، فينبغي أن يكون الناتج:

Display: 22.5C
Alarm Check: 22.5C
Display: 28C

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

جرّب بنفسك

using System;
using Monitoring;

class Program
{
    public static void Main(string[] args)
    {
        // اقرأ درجات الحرارة المُدخلة
        double temp1 = Convert.ToDouble(Console.ReadLine());
        double temp2 = Convert.ToDouble(Console.ReadLine());

        // TODO: أنشئ نسخة من TemperatureSensor

        // TODO: أنشئ نسختين من DisplayUnit وAlarmSystem

        // TODO: اشترك بكلا المراقبين في الحدث TemperatureChanged

        // TODO: اضبط درجة حرارة المستشعر على temp1 (يُخطَر كلا المراقبين)

        // TODO: ألغِ اشتراك AlarmSystem في الحدث

        // TODO: اضبط درجة حرارة المستشعر على temp2 (تُخطَر وحدة العرض فقط)
    }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم C# عبر الإنترنت