انحصار انجیکشن (DI) کو سمجھنے کے لیے آسان تصور نہیں ہے، اور اسے نئی یا موجودہ ایپلی کیشنز پر لاگو کرنا اور بھی الجھا ہوا ہے۔ جیس سمتھ آپ کو دکھاتا ہے کہ سی # اور جاوا پروگرامنگ زبانوں میں انجیکشن کنٹینر کے بغیر انحصار انجیکشن کیسے کریں۔ اس مضمون میں، میں آپ کو .NET اور Java ایپلیکیشنز میں انحصار انجیکشن (DI) کو لاگو کرنے کا طریقہ دکھاؤں گا۔ انحصار انجیکشن کا تصور سب سے پہلے 2000 میں ڈویلپرز کی توجہ میں آیا، جب رابرٹ مارٹن نے مضمون "ڈیزائن کے اصول اور نمونے" لکھا (بعد میں مخفف
SOLID سے جانا جاتا ہے )۔ SOLID میں D سے مراد الٹا انحصار (DOI) ہے، جسے بعد میں انحصار انجکشن کے نام سے جانا گیا۔ اصل اور سب سے عام تعریف: انحصار کا الٹا جس طرح سے ایک بیس کلاس انحصار کو منظم کرتی ہے اس کا الٹا ہے۔
Copy
مارٹن کے اصل مضمون میں درج ذیل کوڈ کا استعمال ایک نچلے درجے کی کلاس پر کلاس کے انحصار کو واضح کرنے کے لیے کیا گیا ہے
WritePrinter
۔
void Copy()
{
int c;
while ((c = ReadKeyboard()) != EOF)
WritePrinter(c);
}
پہلا واضح مسئلہ یہ ہے کہ اگر آپ پیرامیٹر کی فہرست یا کسی طریقہ کی اقسام کو تبدیل کرتے ہیں
WritePrinter
، تو آپ کو اپ ڈیٹس کو نافذ کرنے کی ضرورت ہے جہاں بھی اس طریقہ پر انحصار ہو۔ یہ عمل دیکھ بھال کے اخراجات کو بڑھاتا ہے اور نئی غلطیوں کا ممکنہ ذریعہ ہے۔
جاوا کے بارے میں پڑھنے میں دلچسپی ہے؟ جاوا ڈیولپر گروپ میں شامل ہوں ! |
ایک اور مسئلہ: کاپی کلاس اب دوبارہ استعمال کے لیے ممکنہ امیدوار نہیں ہے۔ مثال کے طور پر، اگر آپ کو پرنٹر کی بجائے کی بورڈ سے فائل میں داخل کردہ حروف کو آؤٹ پٹ کرنے کی ضرورت ہو تو کیا ہوگا؟
Copy
ایسا کرنے کے لیے، آپ درج ذیل کلاس میں ترمیم کر سکتے ہیں (C++ زبان کا نحو):
void Copy(outputDevice dev)
{
int c;
while ((c = ReadKeyboard()) != EOF)
if (dev == printer)
WritePrinter(c);
else
WriteDisk(c);
}
ایک نئے انحصار کے متعارف ہونے کے باوجود
WriteDisk
، صورت حال بہتر نہیں ہوئی (بلکہ مزید بگڑ گئی) کیونکہ ایک اور اصول کی خلاف ورزی کی گئی تھی: "سافٹ ویئر اداروں، یعنی کلاسز، ماڈیولز، فنکشنز، اور اسی طرح، توسیع کے لیے کھلا ہونا چاہیے، لیکن اس کے لیے بند ترمیم۔" مارٹن وضاحت کرتا ہے کہ یہ نئے مشروط اگر/اور بیانات کوڈ کے استحکام اور لچک کو کم کرتے ہیں۔ حل یہ ہے کہ انحصار کو الٹ دیا جائے تاکہ لکھنے اور پڑھنے کے طریقے پر منحصر ہوں
Copy
۔ "پاپنگ" انحصار کے بجائے، وہ کنسٹرکٹر سے گزرے ہیں۔ ترمیم شدہ کوڈ اس طرح لگتا ہے:
class Reader
{
public:
virtual int Read() = 0;
};
class Writer
{
public:
virtual void Write(char) = 0;
};
void Copy(Reader& r, Writer& w)
{
int c;
while((c=r.Read()) != EOF)
w.Write(c);
}
اب کلاس کو
Copy
کلاس طریقوں کے مختلف نفاذ کے ساتھ آسانی سے دوبارہ استعمال کیا جا سکتا ہے
Reader
۔
Writer
کلاس کے
Copy
پاس اقسام کے اندرونی ڈھانچے کے بارے میں کوئی معلومات نہیں ہے
Reader
اور
Writer
، مختلف نفاذ کے ساتھ انہیں دوبارہ استعمال کرنا ممکن بناتا ہے۔ لیکن اگر یہ سب کچھ آپ کو کسی قسم کی گوبلڈیگوک کی طرح لگتا ہے، تو شاید جاوا اور C# میں درج ذیل مثالیں صورتحال کو واضح کردیں گی۔
جاوا اور C# میں مثال
انحصار کنٹینر کے بغیر انحصار انجیکشن کی آسانی کو واضح کرنے کے لیے، آئیے ایک سادہ مثال کے ساتھ شروع کرتے ہیں جسے
DI
صرف چند مراحل میں استعمال کے لیے اپنی مرضی کے مطابق بنایا جا سکتا ہے۔ ہم کہتے ہیں کہ ہمارے پاس ایک کلاس ہے
HtmlUserPresentation
جو، جب اس کے طریقوں کو کہا جاتا ہے، ایک HTML صارف انٹرفیس تیار کرتا ہے۔ یہاں ایک سادہ مثال ہے:
HtmlUserPresentation htmlUserPresentation = new HtmlUserPresentation();
String table = htmlUserPresentation.createTable(rowTableVals, "Login Error Status");
اس کلاس کوڈ کو استعمال کرنے والے کسی بھی پروجیکٹ کا کلاس پر انحصار ہوگا
HtmlUserPresentation
، جس کے نتیجے میں اوپر بیان کردہ قابل استعمال اور برقرار رکھنے کے مسائل پیدا ہوں گے۔ ایک بہتری فوری طور پر خود تجویز کرتی ہے: کلاس میں موجود تمام طریقوں کے دستخطوں کے ساتھ ایک انٹرفیس بنانا
HtmlUserPresentation
۔ یہاں اس انٹرفیس کی ایک مثال ہے:
public interface IHtmlUserPresentation {
String createTable(ArrayList rowVals, String caption);
String createTableRow(String tableCol);
}
انٹرفیس بنانے کے بعد، ہم
HtmlUserPresentation
اسے استعمال کرنے کے لیے کلاس میں ترمیم کرتے ہیں۔ قسم کو فوری کرنے کی طرف لوٹتے ہوئے
HtmlUserPresentation
، اب ہم بنیادی قسم کے بجائے انٹرفیس کی قسم استعمال کر سکتے ہیں:
IHtmlUserPresentation htmlUserPresentation = new HtmlUserPresentation();
String table = htmlUserPresentation.createTable(rowTableVals, "Login Error Status");
ایک انٹرفیس بنانا ہمیں آسانی سے دیگر نفاذات کو استعمال کرنے کی اجازت دیتا ہے
IHtmlUserPresentation
۔ مثال کے طور پر، اگر ہم اس قسم کی جانچ کرنا چاہتے ہیں، تو ہم آسانی سے بنیادی قسم کو
HtmlUserPresentation
کسی دوسری قسم کے ساتھ بدل سکتے ہیں
HtmlUserPresentationTest
۔ اب تک کی گئی تبدیلیاں کوڈ کو جانچنے، برقرار رکھنے اور اسکیل کرنے میں آسان بناتی ہیں، لیکن دوبارہ استعمال کے لیے کچھ نہیں کرتی ہیں کیونکہ
HtmlUserPresentation
قسم کا استعمال کرنے والی تمام کلاسیں اب بھی اس کے وجود سے واقف ہیں۔
IHtmlUserPresentation
اس براہ راست انحصار کو دور کرنے کے لیے، آپ اس کلاس یا طریقہ کار کے کنسٹرکٹر (یا طریقہ پیرامیٹرز کی فہرست) کو انٹرفیس کی قسم دے سکتے ہیں جو اسے استعمال کرے گا:
public UploadFile(IHtmlUserPresentation htmlUserPresentation)
کنسٹرکٹر کو
UploadFile
اب قسم کی تمام فعالیت تک رسائی حاصل ہے
IHtmlUserPresentation
، لیکن اس انٹرفیس کو نافذ کرنے والی کلاس کی اندرونی ساخت کے بارے میں کچھ نہیں جانتا۔ اس تناظر میں، ٹائپ انجیکشن اس وقت ہوتا ہے جب کلاس کی مثال بنائی جاتی ہے
UploadFile
۔ ایک انٹرفیس کی قسم
IHtmlUserPresentation
مختلف کلاسوں یا طریقوں کو مختلف نفاذ کو منتقل کرکے دوبارہ قابل استعمال بن جاتی ہے جس کے لئے مختلف فعالیت کی ضرورت ہوتی ہے۔
مواد کو مستحکم کرنے کے لیے نتیجہ اور سفارشات
آپ نے انحصار انجیکشن کے بارے میں سیکھا اور کہا جاتا ہے کہ کلاسیں براہ راست ایک دوسرے پر انحصار کرتی ہیں جب ان میں سے ایک دوسرے کو ٹارگٹ ٹائپ کی فعالیت تک رسائی حاصل کرنے کے لیے انسٹیٹیوٹ کرتا ہے۔ دو اقسام کے درمیان براہ راست انحصار کو دوگنا کرنے کے لیے، آپ کو ایک انٹرفیس بنانا چاہیے۔ ایک انٹرفیس ایک قسم کو مطلوبہ فعالیت کے سیاق و سباق کے لحاظ سے مختلف نفاذ کو شامل کرنے کی صلاحیت دیتا ہے۔ انٹرفیس کی قسم کو کلاس کنسٹرکٹر یا طریقہ کار کو منتقل کرنے سے، کلاس/طریقہ جس کو فعالیت کی ضرورت ہوتی ہے وہ انٹرفیس کو نافذ کرنے والی قسم کے بارے میں کوئی تفصیلات نہیں جانتا ہے۔ اس کی وجہ سے، انٹرفیس کی قسم کو مختلف کلاسوں میں دوبارہ استعمال کیا جا سکتا ہے جس کے لیے یکساں، لیکن یکساں نہیں، رویے کی ضرورت ہوتی ہے۔
- انحصار انجیکشن کے ساتھ تجربہ کرنے کے لیے، ایک یا زیادہ ایپلی کیشنز سے اپنے کوڈ کو دیکھیں اور بہت زیادہ استعمال شدہ بیس ٹائپ کو انٹرفیس میں تبدیل کرنے کی کوشش کریں۔
- اس نئی انٹرفیس قسم کو استعمال کرنے کے لیے ان کلاسز کو تبدیل کریں جو اس بیس ٹائپ کو براہ راست انسٹیٹیوٹ کرتے ہیں اور اسے اس کلاس کے طریقہ کار کے کنسٹرکٹر یا پیرامیٹر لسٹ سے گزرتے ہیں جو اسے استعمال کرے گا۔
- اس انٹرفیس کی قسم کو جانچنے کے لیے ایک ٹیسٹ عمل درآمد بنائیں۔ ایک بار جب آپ کا کوڈ ری فیکٹر ہو جائے گا،
DI
تو اسے لاگو کرنا آسان ہو جائے گا، اور آپ دیکھیں گے کہ آپ کی درخواست دوبارہ استعمال اور برقرار رکھنے کے لحاظ سے کتنی زیادہ لچکدار ہو جاتی ہے۔
GO TO FULL VERSION