4. حقن التبعية
يمكن اعتبار حقن التبعية نتيجة لانعكاس التحكم. سنوضح ذلك بمثال جديد. لنفكر في تطبيق الويب ذي الطبقات الثلاث التالي:
![]() |
سنفترض أن الوصول إلى طبقة DAO يتم التحكم فيه بواسطة واجهة [IArticlesDao] التي تمت مناقشتها سابقًا وأن التطبيق بأكمله هو تطبيق تسوق قائم على الويب. العناصر هي تلك التي تديرها طبقة [Dao]. نفترض أن الوصول إلى طبقة الأعمال يتم التحكم فيه بواسطة الواجهة التالية:
Public Interface IArticlesDomain
Public Interface IArticlesDomain
' buy a basket of items
Sub acheter(ByVal panier As Panier)
' get the list of articles
Function getAllArticles() As IList
' get a specific item
Function getArticleById(ByVal idArticle As Integer) As Article
' to record errors
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 fields
Private _articlesDao As IArticlesDao
Private _erreurs As ArrayList
' manufacturer
Public Sub New(ByVal articlesDao As IArticlesDao)
_articlesDao = articlesDao
End Sub
...
End Class
End Namespace
كما ذكرنا سابقًا، تحتاج بعض طرق واجهة طبقة الأعمال إلى طلب البيانات من طبقة [Dao]. ولذلك، تحتاج فئة التنفيذ [AchatsArticles] الخاصة بنا لواجهة [IArticlesDomain] إلى مرجع إلى أحد تطبيقات واجهة [IArticlesDao]. وفي المثال أعلاه، يعمل الحقل الخاص [_articlesDao] بمثابة هذا المرجع. ويتم توفير هذا المرجع عند إنشاء كائن [AchatsArticles].
لنفترض أن فئة [ItemPurchases] قد تمت كتابتها ونريد اختبارها باستخدام اختبار [Nunit]. لنقم بإنشاء هذا الاختبار بحيث يستخدم ملف تكوين Spring:
...
Imports Spring.Objects.Factory.Xml
Imports System.IO
...
<TestFixture()> _
Public Class NunitSpringTestArticlesDomain
' the test object
Private articlesDomain As IArticlesDomain
<SetUp()> _
Public Sub init()
' retrieve an instance of the Spring object manufacturer
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-domain.xml", FileMode.Open))
' request instantiation of the articles dao object
articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDao)
End Sub
...
End Class
ماذا سيكون محتوى ملف تكوين Spring [spring-config-domain.xml]؟ قد يكون كما يلي:
<?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>
<!-- the IArticlesDao interface implementation class -->
<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>
<!-- the IArticlesDomain interface implementation class -->
<object id="articlesdomain" type="istia.st.articles.domain.AchatsArticles, articlesdomain">
<constructor-arg index="0">
<ref object="articlesdao" />
</constructor-arg>
</object>
</objects>
هذا الملف هو الملف الذي تم استخدامه بالفعل لإنشاء مثيل [IArticlesDao] من طبقة [Dao]، والذي أضفنا إليه الكود لإنشاء مثيل [IArticlesDomain] من طبقة الأعمال. كيف سيتم إنشاء هذا؟
- يطلب الكود الخارجي مرجعًا إلى الكائن الفردي المسمى "articlesdomain" من Spring في ملف التكوين. وهذا هو الحال مع طريقة [init] لفئة الاختبار لدينا:
<SetUp()> _
Public Sub init()
' retrieve an instance of the Spring object manufacturer
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-domain.xml", FileMode.Open))
' request instantiation of the articles dao object
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 fields
Private _articlesDao As IArticlesDao
' manufacturer
Public Sub New(ByVal articlesDao As IArticlesDao)
_articlesDao = articlesDao
End Sub
...
End Class
End Namespace
يشمل مصطلح "حقن التبعية" كلا الأمرين:
- الطريقة المحددة لإنشاء الفئات التي سيتم إنشاء مثيل لها بناءً على تبعياتها
- الطريقة التي يدير بها Spring هذه التبعيات عند إنشاء مثيلات لهذه الفئات

