Skip to content

4. حقن التبعية

يمكن اعتبار حقن التبعية نتيجةً لعكس التحكم. سنوضح ذلك من خلال مثال جديد. لنفترض وجود تطبيق ويب ثلاثي الطبقات كما يلي:

سنفترض أن الوصول إلى الطبقة DAO يتم التحكم فيه بواسطة الواجهة [IArticlesDao] التي درسناها سابقًا، وأن التطبيق بأكمله هو تطبيق ويب لشراء المنتجات عبر الإنترنت. والمنتجات هي تلك التي تديرها الطبقة [Dao]. ونفترض أن الوصول إلى الطبقة التشغيلية يتم التحكم فيه بواسطة الواجهة التالية:

Public Interface IArticlesDomain
     ' شراء سلة من المنتجات
    Sub acheter(ByVal panier As Panier)
     ' الحصول على قائمة المنتجات
    Function getAllArticles() As IList
     ' الحصول على منتج معين
    Function getArticleById(ByVal idArticle As Integer) As Article
     ' لتسجيل الأخطاء
    ReadOnly Property erreurs() As ArrayList
End Interface

لن نتطرق إلى معنى الطرق المختلفة. نكتفي بالإشارة إلى أن الطريقة [getAllArticles]، التي تهدف إلى الحصول على قائمة بجميع المنتجات المعروضة للبيع، تحتاج إلى الوصول إلى البيانات. وللحصول عليها، يجب أن تتواصل مع الواجهة [IArticlesDao]. قد يبدو الهيكل الأساسي لفئة تنفيذ الواجهة [IArticlesDomain] كما يلي:

Imports istia.st.articles.dao
...
Namespace istia.st.articles.domain
    Public Class AchatsArticles
        Implements IArticlesDomain

         'الحقول الخاصة
        Private _articlesDao As IArticlesDao
        Private _erreurs As ArrayList

         ' المنشئ
        Public Sub New(ByVal articlesDao As IArticlesDao)
            _articlesDao = articlesDao
        End Sub
...
    End Class
End Namespace

كما ذكرنا سابقًا، تحتاج بعض أساليب واجهة طبقة الأعمال إلى طلب البيانات من طبقة [Dao]. لذلك، تحتاج فئة التنفيذ [AchatsArticles] الخاصة بنا لواجهة [IArticlesDomain] إلى مرجع إلى تنفيذ لواجهة [IArticlesDao]. في المثال أعلاه، يمثل الحقل الخاص [_articlesDao] هذا المرجع. ويتم توفير هذا المرجع عند إنشاء كائن [AchatsArticles].

لنفترض أن الفئة [AchatsArticles] قد تمت كتابتها ونريد اختبارها باستخدام اختبار من النوع [Nunit]. لنقم بإنشاء هذا الاختبار بحيث يستخدم ملف تكوين Spring:

...
Imports Spring.Objects.Factory.Xml
Imports System.IO
...
    <TestFixture()> _
    Public Class NunitSpringTestArticlesDomain

         ' الكائن المراد اختباره
        Private articlesDomain As IArticlesDomain

        <SetUp()> _
        Public Sub init()
       ' استرداد مثيل من منشئ كائنات Spring
            Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-domain.xml", FileMode.Open))
       ' يُطلب إنشاء مثيل للكائن articles dao
            articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDao)
        End Sub
...
    End Class

ما هو محتوى ملف التكوين [spring-config-domain.xml] الخاص بـ Spring؟ قد يكون كما يلي:

<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE objects PUBLIC "-//SPRING//DTD OBJECT//EN"
"http://www.springframework.net/dtd/spring-objects.dtd">

<objects>
    <description>Gestion d'une table d'articles</description>

     <!-- فئة تنفيذ الواجهة IArticlesDao -->
    <object id="articlesdao" type="istia.st.articles.dao.ArticlesDaoPlainODBC, articlesdao">
      <constructor-arg index="0">
            <value>odbc-firebird-articles</value>
        </constructor-arg>
         <constructor-arg index="1">
            <value>SYSDBA</value>
        </constructor-arg>
         <constructor-arg index="2">
            <value>masterkey</value>
        </constructor-arg>
    </object>

     <!-- فئة تنفيذ واجهة IArticlesDomain -->
  <object id="articlesdomain" type="istia.st.articles.domain.AchatsArticles, articlesdomain">
      <constructor-arg index="0">
        <ref object="articlesdao" />
    </constructor-arg>
  </object>
</objects>

هذا الملف هو نفسه الذي تم استخدامه سابقًا لإنشاء مثيل للسينجلتون من النوع [IArticlesDao] من الطبقة [Dao]، حيث تمت إضافة الكود لإنشاء مثيل للسينجلتون من النوع [IArticlesDomain] من طبقة الأعمال. كيف سيتم إنشاء هذا السينجلتون؟

  • يطلب كود خارجي من Spring مرجعًا إلى الكائن الفردي المسمى "articlesdomain" في ملف التكوين. وهذا هو الحال بالنسبة للطريقة [init] في فئة الاختبار الخاصة بنا:
        <SetUp()> _
        Public Sub init()
       ' يتم استرداد مثيل من مُنشئ كائنات Spring
            Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-domain.xml", FileMode.Open))
       ' نطلب إنشاء مثيل لكائن DAO الخاص بالمقالات
            articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDao)
        End Sub
  • يجد Spring في ملف التكوين الخاص به تعريف الكائن الفردي المعني. ويكتشف أنه لإنشاء مثيل له، فإنه يحتاج إلى كائن فردي آخر يُسمى "articlesdao":
  <object name="articlesdomain" class="istia.st.articles.domain.AchatsArticles, articlesdomain">
      <constructor-arg index="0">
        <ref object="articlesdao" />
    </constructor-arg>
  </object>
  • سيقوم Spring بعد ذلك بإنشاء مثيل للسينغلتون "articlesdao". وقد سبق أن أوضحنا كيفية قيامه بذلك.
  • وبعد ذلك، يمكنه إنشاء مثيل للسينجلتون «articlesdomain» وتقديم مرجع إليه إلى الكود الذي طلبه.

يمكن توضيح هذه الآلية كما يلي:

نلاحظ أن Spring قد عالج التبعية التي كان يعتمد عليها الكائن الفريد "articlesdomain" تجاه الكائن الفريد "articlesdao". لاستخدام Spring بهذه الطريقة، كان علينا إنشاء فئة تحتوي على منشئ يقبل الكائن الفريد التابع كحجة:

Imports istia.st.articles.dao
...
Namespace istia.st.articles.domain
    Public Class AchatsArticles
        Implements IArticlesDomain

         'الحقول الخاصة
        Private _articlesDao As IArticlesDao

         ' منشئ
        Public Sub New(ByVal articlesDao As IArticlesDao)
            _articlesDao = articlesDao
        End Sub
...
    End Class
End Namespace

يشمل مصطلح "حقن التبعية" كلاً من:

  • الطريقة الخاصة لإنشاء الفئات المراد إنشاء مثيل لها بناءً على تبعياتها
  • الطريقة التي يتبعها Spring في إدارة هذه التبعيات عند إنشاء مثيلات لهذه الفئات