Saturday, March 9, 2013

Dependency injection Principle DIP مبدأ التبعية

المقدمة

وهو نمط يدخل ضمن الأنماط الكائني المنحى OOP يستخدم لأجل تقليل الأقتران loosely coupled والأعتمادية مابين المكونات ,بحيث يجعلها أكثر مرونةواختبار, يركز هذا النمط في عمله على حذف الأكواد المتكررة والأعتمادية مابين المكونات بحيث يركز على حقن Inject الكائنات في Classes معينة من دون أن تقوم بخلق هذه الكائنات بنفسك مما يقلل الجهد على المطور ويجعل الأعتمادية تظهر في الوقت الحقيقي Run time ويكون الحقن بعدة طرق سوف نقوم بشرحها خلال البحث ,يستخدم DI بكثرة مع النمط Inversion of Control IOC وهو عبارة على وعاء يتحكم بالتدفق العام للبرنامج من خلال استخدام مبدأ حقن الأعتمادية DI.

المحتوى

لأجل فهم نمط DI يجب ان نقوم بأخذ مثال بسيط يشرح ستراتيجية الأعتمادية وأنعكاس الأعتمادية Dependency Inversion :

لنأخذ تطبيق بسيط يقوم بعملية أخبار Notification عبر أرسال رسالة معينة بأستخدام خدمة Email 

 من الرسم أعلاه نلاحظ أعتمادية الكلاس Notification  على كلاس Email بحيث يطلب الأول instance لأجل أرسال الرسالة عبر الأيميل , أذن كلاس Notification  يعرف مع من يتعامل وهذا بدوره يزيد من الأقتران مابين المكونين وهذ ما نشاهده في الكود التالي الذي يوضح مدى الأقتران مابين المكونين :
  نلاحظ أنه تم خلق كائن من نوع Email داخل كلاس Notification مما يزيد الأعتمادية في كتابة الكود , لكن توقع أن مديرك اراد أن ترسل الرسالة ليس فقط عبر الأيميل بل عبر SMS وايضا ترسل الى Databaase لأجل خزنها , أذن حسب الكود أعلاه يجب عليك أن تقوم بخلق ثلاث Instance داخل كلاس Notification ومن ثم أرسال الرسائل بالتسلسل مما يزيد الأقتران والجهد على المطور ويصعب الأختبار والتوسع.الحل هو بواسطة أستخدام نمط DI الذي يعمل على تقليل الأقتران من خلال خلق interface ندعوه IMessage يتم تنفيذه implement من قبل الخدمات المتوفرة للأرسال Email,Dbase,SMS . ويستخدمه using الكلاس Notification انظر الرسم التالي:
من الرسم أعلاه نلاحظ جميع الخدمات الأن تنفذ IMessageService وبهذه الهيكلية الجديدة يمكننا أن نطبق مبدأ DI وذلك من خلال حقن injection  الكلاس Notification بكائن بشرط ان كلاس Notification لا يخلق instance  في داخله وايضا لا يعرف أنتماءالكائن الذي سوف يحقن به لكن فقط يعرف انه من نوع IMessageService , وبهذا يمكننا أن نضيف اي خدمة أخرى في المستقبل من دون التأثير على الكلاس Notification.
عندما تريد تنفيذ النمط DI توجد عدة طرق كما مبينة في الرسم التالي :
أختيار الطريقة ألأفضل من هذه الطرق يعتمد على متطلبات وتعقيد العمليات الوظيفية أضافة الى وجود بعض المساوئ والمحاسن في الطرق المستخدمة , نأتي الأن الى شرح التطبيق و لأجل تنفيذ DI سوف نستخدم constructor injection وايضا Setter Injection.


1 - يتم خلق :
   * classes لأجل الخدمات Email,SMS,Dbase
   * interface لأجل تنفيذ العمليات التي تتشارك فيها الخدمات وسوف يحوي على عملية أرسال الرسالة SendMessage 
   * files لأجل تبيين الطريقتين أعلاه لتنفيذ مبدأ DI .
   * classes لأجل تنفيذ Notification 

الرسم التالي يوضح الملفات التي تم أنشائها :

2 - نقوم بكتابة الكود التابع IMessageService :

 3 - يتم تنفيذ IMessageService لأجل الخدمات الثلاثة :

  نلاحظ من الكود اعلاه انه تم تنفيذ SendMessage في كل الخدمات ,ومن خلال هذه العملية يتم طباعة message واظهارها على بيئة cmd .

4 - نأتي الأن الى نواة التطبيق وهو كلاس Notification  :

 * بأستخدم طريقة  constructor injection 
نلاحظ خلق instance من نوع IMessageservice وتم حقن الكلاس Notification عبر Constructor ومساواته بالكائن messageService_ , نلاحظ أن كلاس Notification لا يعرف أنتماء messageService_ هل هو Email ام SMS , هذه هو جوهر DI ان تحقيق الأعتمادية يتم في Run time

5 - لنأتي الى تنفيذ البرنامج عبر الكلاس Program
اولاً تم خلق instance من نوع IMessageService يؤشر على الكلاس SMS وبعدها تم خلق instance من نوع Notification وتم أرسال الكائن messageService1 عبر Constructor بمعنى تم الحقن , وبعدها يتم أستدعاء العملية PromotionalNotification والتي بدورها ترسل الرسالة الى الوجه المحددة بالأعتماد على حقن الأعتمادية الذي تم.

مخطط يشرح لك سريان التدفق المتسلسل الى أظهار النتيجة :

الخاتمة 

بالطبع نمط Dependency Injection موسع جدا وله الكثير من الوظائف التي لم نذكرها فتتواجد في جميع المكتبات والمكونات تقريبا , فنشاهدها في خاصية Data Binding وفي تقنية WPF, Silverlight وايضا نلاحظ حضورها الفعال في الأنماط المهمة لبناء تطبيقات معقدة , واذا كنت من مطوري Net. فيمكنك أستخدام Unity Dependency Injection,
Managed Extensibility Framework MEF.
يمكنكم تحميل الكود من الرابط التالي http://sdrv.ms/VTsBXK




   

10 comments:

  1. Nice post, and glad to see Arabic posts about such topics

    Keep the good work :)

    ReplyDelete
  2. جهد جبار , وشرح موسع ودقيق
    شكرا يامبدع

    ReplyDelete
  3. رائع شكراااااااااااا كتير بارك الله فيك

    ReplyDelete
  4. درس مهم جدا وشرح سهل ورائع
    بارك الله فيك

    ReplyDelete
  5. أشكركم جميعا وانا في خدمتكم

    ReplyDelete
  6. جزاك الله خيراً
    عندي سؤال لو سمحت
    رأيت في أحد الأمثلة على الانترنت استخدام مكتبة Ninject
    كان استخدام المكتبة لمحاولة عدم استخدام كلمة new لانشاء أوبجيكت واعطائه للانترفيس
    ما السبب في تفضيل عدم استخدام كلمة new مع الانترفيس؟

    ReplyDelete
  7. استمر جودة المحتوى ممتازه لاتت قف ابدل

    ReplyDelete
  8. روعه جزاك الله خيرا

    ReplyDelete
  9. جهودك مشكوره
    شرح بسيط و واضح

    ReplyDelete