প্রথমত, আমি এই উত্তরের জন্য আমি যে অনুমান করি তা ব্যাখ্যা করতে চাই। এটি সর্বদা সত্য নয়, তবে প্রায়শই:
ইন্টারফেস বিশেষণ; ক্লাস বিশেষ্য হয়।
(আসলে, এমন ইন্টারফেস রয়েছে যেগুলি বিশেষ্যও হয় তবে আমি এখানে সাধারণীকরণ করতে চাই))
সুতরাং, যেমন একটি ইন্টারফেস কিছু হতে পারে IDisposable
, IEnumerable
বা IPrintable
। একটি শ্রেণি হল এই ইন্টারফেসগুলির এক বা একাধিকের বাস্তব বাস্তবায়ন: List
বা Map
উভয়ই এর বাস্তবায়ন হতে পারে IEnumerable
।
বিষয়টি পেতে: প্রায়শই আপনার ক্লাসগুলি একে অপরের উপর নির্ভর করে। যেমন আপনার Database
ক্লাস থাকতে পারে যা আপনার ডাটাবেস অ্যাক্সেস করে (হাহ, অবাক! ;-)), তবে আপনি এই ক্লাসটিও ডেটাবেস অ্যাক্সেস সম্পর্কে লগিং করতে চান do মনে করুন আপনার অন্য একটি ক্লাস রয়েছে Logger
, তারপরে Database
নির্ভরতা রয়েছে Logger
।
এ পর্যন্ত সব ঠিকই.
আপনি এই Database
ক্লাসের মধ্যে নির্ভরতা নিম্নলিখিত লাইনের সাথে মডেল করতে পারেন :
var logger = new Logger();
এবং সবকিছু ঠিক আছে। এটি এখনও ঠিক আছে যখন আপনি বুঝতে পেরেছেন যে আপনার একগুচ্ছ লগার দরকার: কখনও কখনও আপনি কনসোলে লগ করতে চান, কখনও কখনও ফাইল সিস্টেমে, কখনও কখনও টিসিপি / আইপি এবং দূরবর্তী লগিং সার্ভার ব্যবহার করে ...
এবং অবশ্যই আপনি আপনার সমস্ত কোড পরিবর্তন করতে চান না (ইতিমধ্যে আপনার এটির গাজিলিয়ন রয়েছে) এবং সমস্ত লাইন প্রতিস্থাপন করতে চান
var logger = new Logger();
দ্বারা:
var logger = new TcpLogger();
প্রথমত, এটি কোনও মজাদার নয়। দ্বিতীয়ত, এটি ত্রুটি-প্রবণ। তৃতীয়ত, এটি প্রশিক্ষিত বানরের পক্ষে নির্বোধ এবং পুনরাবৃত্ত কাজ। তো তুমি কি কর?
স্পষ্টতই এটি একটি ইন্টারফেস ICanLog
(বা অনুরূপ) প্রবর্তন করা বেশ ভাল ধারণা যা সমস্ত বিভিন্ন লগার দ্বারা প্রয়োগ করা হয়। সুতরাং আপনার কোডের 1 পদক্ষেপটি হ'ল আপনি যা করছেন:
ICanLog logger = new Logger();
এখন টাইপ অনুমানটি আর কোনও ধরণের পরিবর্তন করে না, আপনি সর্বদা একটি একক ইন্টারফেসের বিরুদ্ধে বিকাশ করতে পারেন। পরবর্তী পদক্ষেপটি আপনি বার বার করতে চান না new Logger()
। সুতরাং আপনি একটি একক, কেন্দ্রীয় কারখানার শ্রেণিতে নতুন উদাহরণ তৈরি করার নির্ভরযোগ্যতা রেখেছেন এবং আপনি কোড পান যেমন:
ICanLog logger = LoggerFactory.Create();
কারখানাটি নিজেই সিদ্ধান্ত নেয় যে কোন ধরণের লগার তৈরি করা উচিত। আপনার কোডটির আর কোনও যত্ন নেই এবং আপনি যদি লগার ব্যবহারের ধরণটি পরিবর্তন করতে চান তবে আপনি একবারে এটি পরিবর্তন করুন : কারখানার অভ্যন্তরে।
এখন, অবশ্যই, আপনি এই কারখানাটি সাধারণীকরণ করতে পারেন এবং এটি যে কোনও ধরণের জন্য কাজ করতে পারেন:
ICanLog logger = TypeFactory.Create<ICanLog>();
কোথাও এই টাইপফ্যাক্টির জন্য কনফিগারেশন ডেটা প্রয়োজন যা প্রকৃত শ্রেণীর কোনও নির্দিষ্ট ইন্টারফেস প্রকারের জন্য অনুরোধ করা হলে তা ইনস্ট্যান্ট করতে হবে, সুতরাং আপনার ম্যাপিং দরকার need অবশ্যই আপনি নিজের কোডের ভিতরে এই ম্যাপিংটি করতে পারেন, তবে তারপরে একটি ধরণের পরিবর্তন মানে পুনরায় সংশোধন। তবে আপনি এই ম্যাপিংটি কোনও এক্সএমএল ফাইলের মধ্যেও রাখতে পারেন, যেমন। এটি আপনাকে কম্পাইল সময় (!) পরেও প্রকৃত ব্যবহৃত বর্গ পরিবর্তন করতে দেয়, এর অর্থ গতিময়ভাবে, পুনরায় ব্যয় না করে!
এর জন্য আপনাকে একটি দরকারী উদাহরণ দেওয়ার জন্য: এমন কোনও সফ্টওয়্যার সম্পর্কে ভাবুন যা সাধারণত লগ হয় না, তবে যখন আপনার গ্রাহক কল করে এবং সমস্যা আছে বলে তার কাছে সহায়তা চান, আপনি তার কাছে যা যা প্রেরণ করেছিলেন তা সবই একটি আপডেট হওয়া এক্সএমএল কনফিগারেশন ফাইল এবং এখন তার কাছে রয়েছে লগিং সক্ষম হয়েছে এবং আপনার সমর্থন আপনার গ্রাহককে সহায়তা করতে লগ ফাইলগুলি ব্যবহার করতে পারে।
এবং এখন, যখন আপনি নামের একটি সামান্য বিট প্রতিস্থাপন, আপনি আপ সহজ বাস্তবায়ন দিয়ে শেষ পরিষেবা লোকেটার , যার জন্য দুই রীতির এক কন্ট্রোল ইনভার্সান (যেহেতু আপনি কে instantiate কি সঠিক বর্গ সিদ্ধান্ত নেয় উপর নিয়ন্ত্রণ বিপরীতমুখী)।
সব মিলিয়ে আপনার কোডের নির্ভরতা হ্রাস করে তবে এখন আপনার সমস্ত কোডের কেন্দ্রীয়, একক পরিষেবা লোকেটারের উপর নির্ভরতা রয়েছে।
নির্ভরতা ইনজেকশন এখন এই লাইনের পরবর্তী পদক্ষেপ: কেবলমাত্র সার্ভিস লোকেটারের জন্য এই একক নির্ভরতা থেকে মুক্তি পান: নির্দিষ্ট ইন্টারফেসের জন্য প্রয়োগের জন্য পরিষেবা লোকেটারকে জিজ্ঞাসা করা বিভিন্ন শ্রেণীর পরিবর্তে, আপনি - আবারও - কে কী ইনস্ট্যান্ট করে তার উপর নিয়ন্ত্রণ ফিরিয়ে দিন again ।
নির্ভরতা ইনজেকশন সহ, আপনার Database
ক্লাসে এখন এমন একটি নির্মাণকারী রয়েছে যার জন্য টাইপের একটি প্যারামিটার প্রয়োজন ICanLog
:
public Database(ICanLog logger) { ... }
এখন আপনার ডেটাবেসটিতে সর্বদা ব্যবহার করার জন্য একটি লগার থাকে তবে এই লগারটি কোথা থেকে এসেছে তা আর কোনওরকম তা জানে না।
এবং এখানেই একটি ডিআই ফ্রেমওয়ার্ক কার্যকর হয়: আপনি আবার আপনার ম্যাপিংগুলি কনফিগার করুন এবং তারপরে আপনার ডিআই ফ্রেমওয়ার্কটি আপনার জন্য আপনার অ্যাপ্লিকেশনটি ইনস্ট্যান্ট করতে বলুন। Application
শ্রেণীর যেমন একটি ICanPersistData
বাস্তবায়ন প্রয়োজন , এর উদাহরণটি Database
ইনজেকশনের ব্যবস্থা করা হয় - তবে এর জন্য এটির জন্য প্রথমে কনফিগার করা ধরণের লগারের একটি উদাহরণ তৈরি করতে হবে ICanLog
। এবং আরও ...
সুতরাং, একটি দীর্ঘ গল্পের সংক্ষিপ্ত কাটা: আপনার কোডের নির্ভরতা কীভাবে সরিয়ে ফেলতে হয় তার মধ্যে দুটি উপায়গুলির মধ্যে একটি নির্ভরতা ইঞ্জেকশন। এটি সংকলন-সময় পরে কনফিগারেশন পরিবর্তনের জন্য খুব দরকারী, এবং ইউনিট পরীক্ষার জন্য এটি দুর্দান্ত জিনিস (কারণ এটি স্টাবগুলি এবং / বা উপহাসগুলি ইনজেক্ট করা খুব সহজ করে তোলে)।
অনুশীলনে, এমন কিছু জিনিস রয়েছে যা আপনি সার্ভিস লোকেটার ব্যতীত করতে পারবেন না (উদাহরণস্বরূপ, যদি আপনি নির্দিষ্ট ইন্টারফেসের জন্য প্রয়োজনীয় কতগুলি উদাহরণ আগেই জানেন না: একটি ডিআই ফ্রেমওয়ার্ক সর্বদা প্যারামিটারে কেবল একটি মাত্র ইনজেকশন দেয় তবে আপনি কল করতে পারেন অবশ্যই একটি লুপের ভিতরে একটি পরিষেবা লোকেটার), তাই প্রায়শই প্রতিটি ডিআই ফ্রেমওয়ার্ক একটি পরিষেবা লোকেটারও সরবরাহ করে।
তবে মূলত, এটি।
পিএস: আমি এখানে যা বর্ণনা করেছি তা কনস্ট্রাক্টর ইনজেকশন নামে পরিচিত একটি প্রযুক্তি , সেখানে প্রপার্টি ইনজেকশন রয়েছে যেখানে কনস্ট্রাক্টর প্যারামিটার নয়, তবে নির্ভরতা নির্ধারণ এবং সমাধানের জন্য বৈশিষ্ট্যগুলি ব্যবহার করা হচ্ছে। সম্পত্তি ইনজেকশনটিকে injচ্ছিক নির্ভরতা এবং কনস্ট্রাক্টর ইঞ্জেকশনটিকে বাধ্যতামূলক নির্ভরতা হিসাবে ভাবেন। তবে এ নিয়ে আলোচনা করা এই প্রশ্নের ক্ষেত্রের বাইরে।