الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

الحلقة الثالثة : Observer Pattern

مغلق
بدأه الحسين في 19 يناير 2005 · 2 رد · 1,676 مشاهدة · في منتدى تطوير المواقع بـ PHP
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

بسم الله الرحمن الرحيم

كل عام وانتم بخير بمناسبة حلول عيد الأضحي المبارك وكل عام وانتم بخير واعاده الله علينا وعليكم بالخير واليمن والبركة

الحلقة الثالثة : Observer Pattern أو نمط المراقب

يعبر هذا النمط عن حالات المراقبه بحيث يمكننا وضع كائن ما تحت المراقبة ويكون هذا الكائن Observable Object اي كائن قابل للمراقبة من خلال

كائن أخر ( أو أكثر ) يلعب دور المراقب لذلك يطلق علي هذا الكائن Observer اي المراقب

لكن ما هي الحاجة لهذا النمط ؟

بكل صراحة لا أخفي عليكم قولا أن هذا النمط يكون تطبيقة أكثر فاعلية في برامج سطح المكتب desktop application

إلا أننا يمكننا إستخدامه في الحالات التالية :

- تدوين الأخطأ error reporting

- التغلب علي حالات فقد قاعدة بيانات MySQL لبعض الخصائص مثل المنبهات triggers

مثال تطبيقي بسيط لتوضيح فكرة هذا النمط

نريد رصد الأخطأ الناتجة من البرنامج بحيث يتم تدوينها في التالي :

- ملف متابعة log file

- وأيضا يتم إرسالها إلي البريد الإليكتروني الخاص بك

- وأيضا يتم تسجيل هذا الخطأ في جدول بقاعدة البيانات (اسم الجدول SolutionErrors)

- طباعة هذا الخطأ بالمتصفح

الحل:

تابع المخطط التالي

ObserverPatternExam1.gif

الجزء الأول : الكائن الذي يتم مراقبته Observable Object

من المخطط السابق يتضح لنا أننا قمنا بعمل فئة باسم Observable وهي بمثابة الفئة الأم للكائنات التي يتم وضعها تحت المراقبة

وتتميز الفئة Observable بالتالي :

- هي فئة مجردة abstract class

- تحتوي علي مصفوفة باسم observers تحمل الكائنات التي تقوم بمراقبة هذا الكائن

( وكل عنصر بهذه المصفوفة يعبر عن كائن من نوع الفئة الأم Observer كما سنري لاحقا )

- وظيفة باسم addObserver تمكننا من إضافة كائن للمراقبة (Observer Object) في المصفوفة observers

( وهي وظيفة داخلية internal or package method يتم إستدعائها من خلال كائنات المراقبة )

- وظيفة باسم notifyObservers تقوم باستدعاء الوظيفة update الخاص بكل كائن يقوم بمراقبة هذا الكائن (وهذه الكائنات هي محتوي المصفوفة observers )

( وهي وظيفة خاصة يتم توريثها protected method يتم إستدعائها من خلال الكائن الذي يتم مراقبته )

وهي كالتالي

<?php
/**
 *  Base Observerable class
 */
class Observable {
    /**
     * private
     * $observers an array of Observer objects to notify
     */
    var $observers = array();

    /**
     * addObserver
     *
     * Register the reference to an object object
     * @return void
     */ 
    function addObserver( &$observer ) {
        $this->observers[] = &$observer;
    }

    /**
     * notifyObservers
     *
     * Calls the update() function using the reference to each
     * registered observer - used by children of Observable
     * @return void
     */ 
    function notifyObservers() {
        $observersCount = count($this->observers);
  
        for($i=0; $i<$observersCount; $i++) {
            $this->observers[$i]->update();
        }
    }

}
?>

وكما يتضح من المخطط السابق أننا قمنا بعمل فئة باسم SolutionError ترث هذه الفئة من الفئة Observable

اي أننا يمكننا إجراء مراقبة لكائنات هذه الفئة

وتتميز الفئة SolutionError بالتالي :

- تحتوي علي متغير باسم message يتم تحميله بقيمة رسالة الخطأ

- تحتوي علي الوظيفة addError يتم من خلالها تحميل قيمة رسالة الخطأ , ثم يتم تبليغ الكائنات التي تراقب هذا الكائن

بأن هذا الكائن حدث به تغير ما من خلال إستدعاء الوظيفة notifyObservers

وهي كما يلي

<?php
/**
 *  Class SolutionError
 */
class SolutionError extends Observable {
     var $message;
  
    /**
     * addError
     *
     * add error and notifies observers
     * @return void
     */
    function addError($message) {
        $this->message = $message;

        // Call the parent function to notify all observers
        $this->notifyObservers();
    }
}
?>

الجزء الثاني : الكائنات المراقبة Observers Object

من المخطط السابق يتضح لنا أننا قمنا بعمل فئة باسم Observer وهي بمثابة الفئة الأم للكائنات التي تلعب دور المراقب

وتتميز الفئة Observer بالتالي :

- هي فئة مجردة abstract class

- تحتوي علي متغير باسم subject يعبر عن الكائن الذي يتم مراقبته

- الوظيفة update (وهي وظيفة مجردة abstract method اي يجب إعادة كتابتها في الفئات المشتقة من هذه الفئة )

يتم إستدعائها بشكل تلقائي من الكائن الذي يتم مراقبته ( من خلال إستدعاء الوظيفة notifyObservers )

وهي كما يلي

<?php
/**
 *  Base Observer class
 */
class Observer {
    /**
     * private
     * $subject a child of class Observable that we're observing
     */
    var $subject;

    /**
     * Constructs the Observer
     * @param $subject the object to observe
     */
    function Observer( &$subject ) {
        $this->subject = &$subject;

        // Register this object so subject can notify it
        $subject->addObserver($this);
    }

    /**
     * update
     * 
     * Abstract function implemented by children to respond to
     * changes in Observable subject
     * @return void
     */    
    function update() {
        trigger_error ('Update not implemented');
    }
}
?>

ومن بعد ذلك تمكننا من عمل فئات المراقبة المشتقة من الفئة Observer

وهم كالتالي :

1- BrowserObserver

وهذه الفئة خاصة بمراقبة الأخطاء , ثم في حالة وجود خطأ يتم تدوينها بالمتصفح

وهي كما يلي

<?php
/**
 *  Class BrowserObserver
 */
class BrowserObserver extends Observer {

    /**
     * Implement the parent update() method
     * write the error message into the browser
     * @return void
     */
    function update () {
        echo $this->subject->message;
    }

}
?>

2- EmailObserver

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

وهي كما يلي

<?php
/**
 *  Class EmailObserver
 */
class EmailObserver extends Observer {

    /**
     * Implement the parent update() method
     * send the error message into the administrator email
     * @return void
     */
    function update () {
        @mail("a_elhussein@hotmail.com", "email error observer", $this->subject->message );
    }

}
?>

3- LogFileObserver

وهذه الفئة خاصة بمراقبة الأخطاء , ثم في حالة وجود خطأ يتم تدوينها في ملف المتابعة باسم log.txt

وهي كما يلي

<?php
/**
 *  Class LogFileObserver
 */
class LogFileObserver extends Observer {

    /**
     * Implement the parent update() method
     * write the error message into the log file
     * @return void
     */
    function update () {
        $fp = @fopen("log.txt" , "ab+");

        fwrite($fp,  date("Y-m-d") . "\t" . $this->subject->message . "\r\n" );
    }

}
?>

4- DBObserver

وهذه الفئة خاصة بمراقبة الأخطاء , ثم في حالة وجود خطأ يتم تسجيله في جدول SolutionErrors الموجود بقاعدة البيانات test لمزود قاعدة البيانات mysql

وهي كما يلي

<?php
/**
 *  Class DBObserver
 */
class DBObserver extends Observer {

    /**
     * Implement the parent update() method
     * add new field into the database table [SolutionErrors]
     * @return void
     */
    function update () {
        // Connect into mysql database server
        $link = @mysql_pconnect("localhost" ,"root" ,"");
  
        if( is_resource($link) ) {
            // Activate database
            if( @mysql_select_db("test" ,$link) ) {
                $errMessage = str_replace("'", "''", $this->subject->message);
                $sql = "insert into SolutionErrors values(CURDATE(),'$errMessage')";

                mysql_query($sql , $link );
            }
        }

    }

}
?>

إلي اللقاء بإذن الله مع نمط جديد

وبالله التوفيق

والسلام عليكم ورحمة الله وبركاته

php error reporting.rar

29_5.gif

سورة العنكبوت

ـــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــ

مشروع Arabic PHP.NET

حلم طالما كان يراودني حتي قهرته بحمد الله ليكون حقيقة

ـــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــ

سلسلة أنماط التصاميم البرمجية Desgin Patterns

سلسلة أنماط التصاميم البرمجية Desgin Patterns | كتيب هذه الدروس (إعداد أحمد غريب)

ـــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــ

كنترول ASP.NET DataGrid CheckBoxColumn

كنترول ProgressBar

كنترول UltraPanel

مشروع الكنترول الأنيق (إهداء للفريق العربي)

الورش الإلكترونية IT Workshops

تعقب الأخطاء error tracing

كنترول ColorPicker لمطوري الويب

RichTextBox Control لمطوري ال ASP.Net

حمل كتاب جافا سكربت عربي

#2

واو !

كنت فعلا احاول التفكير في نظام جيد لل error reporting !

عندي بعض التعليقات والاسئلة ..

- اعتقد ان استخدام الكائنات زائد عن اللازم في هذا النظام. فكان يمكن الاستغناء عن مصفوفة الكائنات ال observers. والكائنات الثلاثة ال observers.. وعمل كائن واحد لديه القدرة علي تبليغ الخطأ بالثلات وظائف.. log file - e-mail - db وذلك للحصول علي آداء أسرع.

ويمكن ضبط النوع المستخدم من خلال function مثلا اسمها SetLoggingType.. او من خلال ال constructor.

مثلا: ( كود سريع لتوضيح فكرة الاستغناء عن الثلات فئات. والكود غير مكتمل وغير جاهز للاستخدام)

class observer {
var $logging_type;

/* we will use the constructor to set the logging methods
** $logging_type = 1 means log to a file 
** $logging_type = 2 means log to e-mail
** $logging_type = 3 means log to a db
*/
function observer($logging_type)
{
	$this->loggin_type = $logging_type;
}

function log($what_to_log)
{
	if($logging_type == 1)
	{
  $fp = @fopen("log.txt" , "ab+");
       	 fwrite($fp,  date("Y-m-d") . "\t" . $what_to_log . "\r\n" );
	}
	else if($logging_type == 2)
	{
   @mail("a_elhussein@hotmail.com", "email error observer", $what_to_log);
	}
	else if($logging_type == 3)
	{
   // Connect into mysql database server
  $link = @mysql_pconnect("localhost" ,"root" ,"");

  if( is_resource($link) ) {
  // Activate database
  if( @mysql_select_db("test" ,$link) ) {
  $errMessage = str_replace("'", "''", $what_to_log);
  $sql = "insert into SolutionErrors values(CURDATE(),'$errMessage')";

   	 mysql_query($sql , $link );
  }
	}
}

}

كما تلاحظ.. الكائن يحمل المتغير Logging_type والذي دائما يحمل قيمة تشير الي طريقة ال logging.. سواء اكانت الي ملف او عن طريق الايميل او الي قاعدة بيانات.

- هل لديك فكرة عن إذا كان استخدام هذه الطريقة الخاصة اسرع ، ام استخدام الامكانيات التي توفرها PHP لنا للقيام بال error reporting..

الامكانيات المقصودة هنا هي دالة set_error_handler و trigger_error.. وغيرها من مجموعة الدوال المتاحة لهذه المهمة. وهي تلك الشروحة هنا : http://www.php.net/manual/en/ref.errorfunc.php

http://www.php.net/manual/en/function.set-error-handler.php

حيث اني دائما ما اقرأ ان الكائنات ابطأ من الطريقة الاجرائية العادية.

- من خلال فهمي المتواضع للنظام المشروح.. اعتقد ان هذا النظام لا يمكن استخدامه في بيئة اجرائية ؟!

بمعني آخر.. يجب ان يكون الجزء المراد عمل error reporting له OOP وذلك حتي استطيع استخدام كائن ال observer.

فهذا النظام (module) يقوم بعمل كائن observer لكل كائن مراد عمل error reporting له.. مما يسبب بتكرار نفس الكائن observer داخل عدة كيانات أخري.

فلم لا يستخدم كائن واحد لل error reporting.. يسمي reporter مثلا.. تقوم انت باستدعاءه سواء من خلال الكائنات او من الطريقة الاجرائية العادية ؟

وشكرا جزيلا وكل عام وانتم بخير

- عمرو

تم تعديل هذه المشاركة بواسطة Chaos في 24 يناير 2005 في 21:54

#3

بسم الله الرحمن الرحيم

أسف علي التأخير في الرد , وذلك نتيجة إنشغالي التام هذه الأيام

أخي الكريم عمرو مشكور جدا علي مجهودك الذي لاحظته بقسم php جعله الله لك في ميزان حسناتك , اللهم أمين

أخي الكريم أحب أن أوضح لك النقاط التالية :

- كما كنت قد أشرت من قبل في الدرس الأول بهذه السلسلة ان سلسلة Design patterns يتم تطبيقها من خلال مفاهيم object oriented

- اما بالنسبة لمثال تدوين الأخطأ error reporting

فهو مجرد مثال بسيط أقدمه لتوضيح فكرة وطريقة إستخدام نمط ال Observer

والأمثلة التطبيقية لهذا النمط كثيرة , وهذا لا يمنع أنه يمكننا التفكير في أمر تدوين الأخطأ باستخدام اي نمط أخر

- أما بالنسبة للمثال الذي قد أوردته أخي الكريم , فعلا تفكيرك صحيح , وهذا الفكر يتبع نمط Bridge (لم أشرحه بعد)

ولكن أخي الكريم , يمكننا فعلا إستخدام نمط الكوبري أو الجسر Bridge لعمل ذلك ولكن لا يفضل , ويفضل نمط المراقب Observer

للأسباب التالية :

+ يتميز نمط المراقب Observer بأنه Pluggable اي قابل للدمج والتركيب

حيث مثلا تخيل أننا نريد إضافة مراقب جديد للأخطأ وليكن هذا المراقب باسم SmsObserver وهو يقوم بإرسال الخطأ إلي جوالك الخاص

في هذه الحالة لن نقوم بتعديل نمط المراقب , بل سوف نقوم بإضافة فئة جديدة باسم SmsObserver ترث من الفئة الأم Observer

وبهذه الطريقة أنت تتعامل مع نظام متمدد extendible

كما يلي :

<?
/**
*  Class SmsObserver
*/
class SmsObserver extends Observer {

   /**
    * Implement the parent update() method
    * write the error message into sms mobile
    * @return void
    */
   function update () {
       // DO some thing ...
   }

}
?>

+ أما في حالة نمط الكوبري Bridge فلعمل هذا سوف نلجأ للتعديل في الفئة الحاوية لهذا النمط وهذا التصميم غير مفضل من الناحية التصميمية

_______________________________________________________

أما بالنسبة للدوال set_error_handler و trigger_error

فهي لا تتبع حديثنا علي الإطلاق عن تدوين الأخطأ

حيث أن وظيفة هذه الدوال هي كالتالي

set_error_handler : تعريف دالة خاصة لإمساك حالات الخطأ

trigger_error : تقوم بعمل ما يسمي Exception Throwing اي تقوم بتحفيذ إحداث خطأ بشكل يدوي manually

كما نلاحظ أن وظيفتهما هي إمساك الخطأ وإحداث خطأ ما اي تقتصر في عملية تتبع الأخطأ error tracing وليس لهم علاقة بطريقة تدوين هذا الخطأ

ولكننا بالطبع أخي الكريم يمكننا الإستفادة من الدالة set_error_handler لإمساك الأخطأ ثم من بعد ذلك نقوم باستخدام نمط المراقب لتدوين الأخطأ

أرجو منك متابعة هذا المقال ربما يعجبك

تعقب الأخطاء error tracing

اقتباس
حيث اني دائما ما اقرأ ان الكائنات ابطأ من الطريقة الاجرائية العادية

أرجو متابعه هذا المقال

مقدمه المكاتب التنفيذيه Business Objects

والسلام عليكم

29_5.gif

سورة العنكبوت

ـــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــ

مشروع Arabic PHP.NET

حلم طالما كان يراودني حتي قهرته بحمد الله ليكون حقيقة

ـــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــ

سلسلة أنماط التصاميم البرمجية Desgin Patterns

سلسلة أنماط التصاميم البرمجية Desgin Patterns | كتيب هذه الدروس (إعداد أحمد غريب)

ـــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــــ

كنترول ASP.NET DataGrid CheckBoxColumn

كنترول ProgressBar

كنترول UltraPanel

مشروع الكنترول الأنيق (إهداء للفريق العربي)

الورش الإلكترونية IT Workshops

تعقب الأخطاء error tracing

كنترول ColorPicker لمطوري الويب

RichTextBox Control لمطوري ال ASP.Net

حمل كتاب جافا سكربت عربي

هذا الموضوع مغلق.

مواضيع مشابهة