কেন একজন নির্ভরতা ইনজেকশন ব্যবহার করে?


536

আমি নির্ভরতা ইনজেকশনগুলি (ডিআই) বোঝার চেষ্টা করছি এবং আবারও আমি ব্যর্থ হয়েছি। এটা ঠিক নির্বোধ মনে হচ্ছে। আমার কোড কখনই গোলযোগ নয়; আমি ভার্চুয়াল ফাংশন এবং ইন্টারফেসগুলি খুব কমই লিখি (যদিও আমি একবার নীল চাঁদে একবার করে ফেলেছি) এবং আমার সমস্ত কনফিগারেশনটি জেসোনেট নেট (কখনও কখনও এক্সএমএল সিরিয়ালাইজার ব্যবহার করে) জাদুকরীভাবে একটি শ্রেণিতে সিরিয়ালিত করা হয়।

আমি কী বুঝতে পারি না এটি কোন সমস্যার সমাধান করে। এটি বলার উপায়ের মতো দেখায়: "হাই you আপনি যখন এই ফাংশনটি চালাবেন তখন এই জাতীয় কোনও বস্তুটি ফিরিয়ে দিন এবং এই পরামিতিগুলি / ডেটা ব্যবহার করুন।"
তবে ... আমি কেন কখনও এটি ব্যবহার করব? দ্রষ্টব্য আমার objectপাশাপাশি কখনই ব্যবহার করার প্রয়োজন হয়নি , তবে আমি বুঝতে পারি এটি কী জন্য।

ওয়েবসাইট তৈরি বা ডেস্কটপ অ্যাপ্লিকেশন তৈরির ক্ষেত্রে এমন কোনও বাস্তব পরিস্থিতি কী যেখানে কোনও ডিআই ব্যবহার করবে? আমি কোনও খেলায় কেন ইন্টারফেস / ভার্চুয়াল ফাংশন ব্যবহার করতে চাইতে পারি তার জন্য খুব সহজেই আমি মামলাগুলি নিয়ে আসতে পারি, তবে এটি খেলা-বিহীন কোডটিতে ব্যবহার করার জন্য এটি অত্যন্ত বিরল (যথেষ্ট বিরল যে আমি একটি উদাহরণও মনে করতে পারি না)।


3
এটি দরকারী তথ্যও হতে পারে: martinfowler.com/articles/inication.html
ta.speot.is




5
ডিআই-এর আরও একটি সহজ সরল ব্যাখ্যা: কোডার্সেনটল.২০১৮
০৩

উত্তর:


840

প্রথমত, আমি এই উত্তরের জন্য আমি যে অনুমান করি তা ব্যাখ্যা করতে চাই। এটি সর্বদা সত্য নয়, তবে প্রায়শই:

ইন্টারফেস বিশেষণ; ক্লাস বিশেষ্য হয়।

(আসলে, এমন ইন্টারফেস রয়েছে যেগুলি বিশেষ্যও হয় তবে আমি এখানে সাধারণীকরণ করতে চাই))

সুতরাং, যেমন একটি ইন্টারফেস কিছু হতে পারে 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চ্ছিক নির্ভরতা এবং কনস্ট্রাক্টর ইঞ্জেকশনটিকে বাধ্যতামূলক নির্ভরতা হিসাবে ভাবেন। তবে এ নিয়ে আলোচনা করা এই প্রশ্নের ক্ষেত্রের বাইরে।


7
অবশ্যই আপনি এটিও এইভাবে করতে পারেন, তবে তারপরে আপনাকে এই যুক্তিটি প্রতিটি একক শ্রেণিতে প্রয়োগ করতে হবে যা বাস্তবায়নের বিনিময়যোগ্যতার জন্য সমর্থন সরবরাহ করবে। এর অর্থ প্রচুর অনুলিপিযুক্ত, রিডানড্যান্ট কোড এবং এর অর্থ হ'ল আপনাকে কোনও বিদ্যমান বর্গ স্পর্শ করতে হবে এবং এটি আংশিকভাবে পুনরায় লিখতে হবে, একবার সিদ্ধান্ত নেওয়ার পরে যে আপনার এখন এটি প্রয়োজন need ডিআই আপনাকে যেকোন স্বেচ্ছাসেবক শ্রেণিতে এটি ব্যবহার করতে দেয়, আপনাকে এগুলি বিশেষ পদ্ধতিতে লিখতে হবে না (কনস্ট্রাক্টরের প্যারামিটার হিসাবে নির্ভরতা নির্ধারণ করা ছাড়া)।
গোলো রোডেন

136
এখানে জিনিস আমি দ্বি সম্পর্কে কখনোই পেতে: এটি স্থাপত্য তোলে অতি জটিল। এবং এখনও, আমি এটি দেখতে হিসাবে, ব্যবহার বেশ সীমাবদ্ধ pretty উদাহরণগুলি অবশ্যই সর্বদা এক রকম: বিনিময়যোগ্য লগার, বিনিময়যোগ্য মডেল / ডেটা অ্যাক্সেস। কখনও কখনও বিনিময়যোগ্য দৃশ্য। তবে এটা। এই কয়েকটি ক্ষেত্রে কি সত্যই আরও জটিল সফ্টওয়্যার আর্কিটেকচারকে ন্যায্যতা প্রমাণ করা হয়? - সম্পূর্ণ প্রকাশ: আমি ইতিমধ্যে দুর্দান্ত প্রভাবের জন্য ডিআই ব্যবহার করেছি, তবে এটি এমন একটি বিশেষ প্লাগ-ইন আর্কিটেকচারের জন্য ছিল যা আমি সাধারণীকরণ করব না।
কনরাড রুডলফ

17
@ গলোরোডেন, আপনি আইএলোগারের পরিবর্তে ইন্টারফেসটি আইকানলগ কেন বলছেন? আমি অন্য প্রোগ্রামার সাথে কাজ করেছি যিনি প্রায়শই এটি করতেন এবং আমি কখনই সম্মেলন বুঝতে পারি না? আমার কাছে এটি আইনিউমারেবল আইসিএনইউনমেট কল করার মতো?
ডার্মফ্রান্স

28
আমি এটিকে আইকানলগ বলেছি কারণ আমরা প্রায়শই শব্দ (বিশেষ্য) দিয়ে কাজ করি যার অর্থ কিছুই না। যেমন, দালাল কী? পরিচালক? এমনকি একটি সংগ্রহস্থল একটি অনন্য উপায়ে সংজ্ঞায়িত করা হয় না। এবং এই সমস্ত জিনিসকে বিশেষ্য হিসাবে রাখা ওও ভাষার একটি সাধারণ রোগ ( স্টিভ-yegge.blogspot.de/2006/03/… দেখুন )। আমি যা প্রকাশ করতে চাই তা হ'ল আমার কাছে এমন একটি উপাদান রয়েছে যা আমার জন্য লগিং করতে পারে - তবে কেন এটি সেভাবে কল করবেন না? অবশ্যই এটি প্রথম ব্যক্তি হিসাবে আই এর সাথে খেলছে, সুতরাং আইসানলগ (ফোর ইউ)।
গোলো রডেন

18
@ ডেভিড ইউনিট টেস্টিং ঠিক কাজ করে - সর্বোপরি, ইউনিট অন্যান্য জিনিস থেকে স্বতন্ত্র (অন্যথায় এটি ইউনিট নয়)। কি নেই দ্বি পাত্রে ছাড়া কাজ উপহাস পরীক্ষার হল। যথেষ্ট ন্যায়সঙ্গত, আমি আপত্তিজনক যে উপহাসের উপকারটি সমস্ত ক্ষেত্রে ডিআই কনটেইনার যুক্ত করার অতিরিক্ত জটিলতা ছাড়িয়ে যায়। আমি কঠোর ইউনিট টেস্টিং করি। আমি খুব কমই উপহাস করি।
কনরাড রুডলফ

499

আমি মনে করি নির্ভরতা ইনজেকশন এবং নির্ভরতা ইনজেকশন কাঠামোর (বা এটি একটি ধারক হিসাবে প্রায়শই বলা হয়) এর মধ্যে পার্থক্য সম্পর্কে লোকেরা অনেক সময় বিভ্রান্ত হয়।

নির্ভরতা ইনজেকশন একটি খুব সহজ ধারণা। এই কোডের পরিবর্তে:

public class A {
  private B b;

  public A() {
    this.b = new B(); // A *depends on* B
  }

  public void DoSomeStuff() {
    // Do something with B here
  }
}

public static void Main(string[] args) {
  A a = new A();
  a.DoSomeStuff();
}

আপনি কোড লিখুন:

public class A {
  private B b;

  public A(B b) { // A now takes its dependencies as arguments
    this.b = b; // look ma, no "new"!
  }

  public void DoSomeStuff() {
    // Do something with B here
  }
}

public static void Main(string[] args) {
  B b = new B(); // B is constructed here instead
  A a = new A(b);
  a.DoSomeStuff();
}

এবং এটাই. সিরিয়াসলি। এটি আপনাকে এক টন সুবিধা দেয়। দুটি গুরুত্বপূর্ণ বিষয় Main()হ'ল আপনার প্রোগ্রাম জুড়ে এটি ছড়িয়ে দেওয়ার পরিবর্তে কেন্দ্রীয় জায়গা ( ফাংশন) থেকে কার্যকারিতা নিয়ন্ত্রণ করার ক্ষমতা এবং প্রতিটি শ্রেণিকে আরও সহজেই বিচ্ছিন্নতার সাথে পরীক্ষা করার ক্ষমতা (কারণ আপনি এর পরিবর্তে মক বা অন্যান্য নকল বস্তুকে তার নির্মাত্রে পাস করতে পারেন) একটি বাস্তব মান)।

অপূর্ণতা অবশ্যই, আপনার কাছে এখন একটি মেগা ফাংশন রয়েছে যা আপনার প্রোগ্রাম দ্বারা ব্যবহৃত সমস্ত ক্লাস সম্পর্কে জানে। এটিই ডিআই ফ্রেমওয়ার্কগুলি সাহায্য করতে পারে। তবে কেন এই পদ্ধতির মূল্যবান তা বুঝতে যদি আপনার সমস্যা হয় তবে আমি প্রথমে ম্যানুয়াল নির্ভরতা ইনজেকশন দিয়ে শুরু করার পরামর্শ দেব, যাতে বিভিন্ন ফ্রেমওয়ার্ক আপনার জন্য কী করতে পারে তা আপনি আরও ভালভাবে উপলব্ধি করতে পারেন।


7
আমি কেন প্রথম কোডটির চেয়ে দ্বিতীয় কোডটি পছন্দ করব? প্রথমটির কাছে কেবল নতুন কীওয়ার্ড রয়েছে, এটি কীভাবে সহায়তা করে?
ব্যবহারকারী962206

17
@ ব্যবহারকারী 962206 আপনি কীভাবে বি
জে কে

66
@ ব্যবহারকারী 62২২২০6, এছাড়াও, বি এর নির্মাণকারীর কিছু প্যারামিটারের প্রয়োজন হলে কী হবে তা নিয়ে ভাবুন: এটি ইনস্ট্যান্ট করার জন্য এ-কে সেই পরামিতিগুলি সম্পর্কে জানতে হবে, যা এ এর ​​সাথে সম্পূর্ণ সম্পর্কযুক্ত নয় (এটি কেবল বি এর উপর নির্ভর করতে চায় , বি কি নির্ভর করে তার উপর নয়)। এ এর নির্মাণকারীর কাছে ইতিমধ্যে নির্মিত বি (বা কোনও সাবক্লাস বা বি এর বিদ্রূপ) পাস করা এটি সমাধান করে এবং
এটিকে

17
@ অ্যাসিডজম্বি ২৪: অনেকগুলি ডিজাইনের নিদর্শনগুলির মতো, ডিআই যদি আপনার কোডবেস সমস্যার জন্য সরল পদ্ধতির জন্য যথেষ্ট পরিমাণে বড় না হয় তবে সত্যই কার্যকর হয় না। আমার অন্ত্র অনুভূতি হ'ল ডিআই-র আসলে কোনও উন্নতি হবে না যতক্ষণ না আপনার অ্যাপ্লিকেশনটিতে প্রায় 20,000 লাইনের কোডের বেশি, এবং / বা অন্যান্য লাইব্রেরি বা ফ্রেমওয়ার্কগুলিতে 20 এর বেশি নির্ভরতা রয়েছে। আপনার অ্যাপ্লিকেশন যদি এর চেয়ে ছোট হয়, আপনি এখনও ডিআই শৈলীতে প্রোগ্রাম করতে পছন্দ করতে পারেন, তবে পার্থক্যটি প্রায় নাটকীয় হবে না।
ড্যানিয়েল প্রাইডেন

2
@ ড্যানিয়েলপ্রাইডেন আমি মনে করি না কোডের আকারটি আপনার কোডটি কতটা গতিশীল। আপনি যদি নিয়মিত একই ইন্টারফেসের সাথে মানানসই নতুন মডিউল যুক্ত করেন তবে আপনাকে নির্ভরশীল কোডটি প্রায়শই পরিবর্তন করতে হবে না।
ফিস্টঅফফুরি

35

অন্যান্য উত্তর যেমনটি বলেছে, নির্ভরতা ইনজেকশন হ'ল এটি ব্যবহার করে এমন শ্রেণীর বাইরে আপনার নির্ভরতা তৈরি করার একটি উপায়। আপনি এগুলি বাইরে থেকে ইনজেকশন দিয়েছিলেন এবং আপনার শ্রেণীর অভ্যন্তর থেকে দূরে তাদের সৃষ্টি সম্পর্কে নিয়ন্ত্রণ পান। এই কারণেই নির্ভরতা ইনজেকশন হ'ল ইনভার্শন অফ কন্ট্রোল (আইওসি) নীতির উপলব্ধি ।

আইওসি হ'ল নীতি, যেখানে ডিআই হ'ল। আমার অভিজ্ঞতা যতদূর যেতে পারে আপনার "একাধিক লগার প্রয়োজন হতে পারে" তার কারণটি কখনই বাস্তবে দেখা যায় না, তবে আসল কারণটি হ'ল, যখনই আপনি কোনও কিছুর পরীক্ষা করেন you একটি উদাহরণ:

আমার বৈশিষ্ট্য:

আমি যখন কোনও অফারের দিকে নজর দিই, আমি চিহ্নিত করতে চাই যে আমি এটি স্বয়ংক্রিয়ভাবে দেখেছি যাতে আমি এটি করতে ভুলবেন না।

আপনি এটি পরীক্ষা করতে পারেন:

[Test]
public void ShouldUpdateTimeStamp
{
    // Arrange
    var formdata = { . . . }

    // System under Test
    var weasel = new OfferWeasel();

    // Act
    var offer = weasel.Create(formdata)

    // Assert
    offer.LastUpdated.Should().Be(new DateTime(2013,01,13,13,01,0,0));
}

সুতরাং কোথাও কোথাও OfferWeasel, এটি আপনাকে অফারের মতো বিষয় তৈরি করে:

public class OfferWeasel
{
    public Offer Create(Formdata formdata)
    {
        var offer = new Offer();
        offer.LastUpdated = DateTime.Now;
        return offer;
    }
}

এখানে সমস্যাটি হ'ল, এই পরীক্ষাটি সম্ভবত সর্বদা ব্যর্থ হয়, যেহেতু নির্ধারিত তারিখটি নির্ধারিত হওয়ার তারিখের চেয়ে আলাদা হবে, আপনি যদি কেবল DateTime.Nowপরীক্ষার কোডটি রেখে দেন তবে এটি কয়েক মিলিসেকেন্ডের দ্বারা বন্ধ থাকবে এবং তাই হবে সর্বদা ব্যর্থ এর থেকে আরও ভাল সমাধান হ'ল এটির জন্য একটি ইন্টারফেস তৈরি করা, যা আপনাকে কোন সময় নির্ধারণ করা হবে তা নিয়ন্ত্রণ করতে দেয়:

public interface IGotTheTime
{
    DateTime Now {get;}
}

public class CannedTime : IGotTheTime
{
    public DateTime Now {get; set;}
}

public class ActualTime : IGotTheTime
{
    public DateTime Now {get { return DateTime.Now; }}
}

public class OfferWeasel
{
    private readonly IGotTheTime _time;

    public OfferWeasel(IGotTheTime time)
    {
        _time = time;
    }

    public Offer Create(Formdata formdata)
    {
        var offer = new Offer();
        offer.LastUpdated = _time.Now;
        return offer;
    }
}

ইন্টারফেস বিমূর্ততা। একটি সত্যিকারের জিনিস, এবং অন্যটি আপনাকে যেখানে প্রয়োজন সেখানে কিছু সময় নকল করতে দেয়। পরীক্ষার পরে এইভাবে পরিবর্তন করা যেতে পারে:

[Test]
public void ShouldUpdateTimeStamp
{
    // Arrange
    var date = new DateTime(2013, 01, 13, 13, 01, 0, 0);
    var formdata = { . . . }

    var time = new CannedTime { Now = date };

    // System under test
    var weasel= new OfferWeasel(time);

    // Act
    var offer = weasel.Create(formdata)

    // Assert
    offer.LastUpdated.Should().Be(date);
}

এটির মতো, আপনি নির্ভরতা (বর্তমান সময়টি) ইনজেকশনের মাধ্যমে "নিয়ন্ত্রণের বিপরীততা" নীতিটি প্রয়োগ করেছিলেন। এটি করার মূল কারণটি সহজ বিচ্ছিন্ন ইউনিট পরীক্ষার জন্য এটি করার অন্যান্য উপায় রয়েছে। উদাহরণস্বরূপ, একটি ইন্টারফেস এবং এখানে একটি শ্রেণি অপ্রয়োজনীয় যেহেতু সি # ফাংশনগুলিতে ভেরিয়েবল হিসাবে প্রায় পাস করা যায়, সুতরাং ইন্টারফেসের পরিবর্তে আপনি Func<DateTime>এটি অর্জন করতে একটি ব্যবহার করতে পারেন । অথবা, আপনি যদি একটি গতিশীল পদ্ধতির অবলম্বন করেন, আপনি কেবলমাত্র সমান পদ্ধতি ( হাঁসের টাইপিং ) রয়েছে এমন কোনও বস্তু পাস করেছেন এবং আপনার কোনও ইন্টারফেসের দরকার নেই।

আপনার খুব কমই একাধিক লগার প্রয়োজন হবে। তবুও, জাভা বা সি # এর মতো স্থিতিযুক্ত কোডের জন্য নির্ভরতা ইনজেকশন প্রয়োজনীয়।

এবং ... এটিও লক্ষ করা উচিত যে কোনও বস্তু রানটাইমের সময় কেবল তার উদ্দেশ্যটি সঠিকভাবে পূরণ করতে পারে, যদি তার সমস্ত নির্ভরতা উপলব্ধ থাকে, তাই সম্পত্তি ইনজেকশন স্থাপনে খুব বেশি ব্যবহার হয় না। আমার মতে, কনস্ট্রাক্টর যখন ডাকা হচ্ছে তখন সমস্ত নির্ভরতা সন্তুষ্ট হওয়া উচিত, সুতরাং কনস্ট্রাক্টর-ইনজেকশনটি সেই জিনিসটি যাওয়াই হবে।

আমি আশা করি যে সাহায্য করেছে।


4
এটি দেখতে ভয়ানক সমাধানের মতো লাগে। আমি স্পষ্টতই কোডটি ড্যানিয়েল প্রাইডেনের উত্তর মতোই লিখব তবে সেই নির্দিষ্ট ইউনিট পরীক্ষার জন্য আমি ফাংশনের আগে এবং পরে ডেটটাইম.এখন করব এবং সময়টি ঠিক আছে কিনা তা যাচাই করে নেব ? আরও ইন্টারফেস / কোডের অনেক বেশি লাইন যুক্ত করা আমার কাছে খারাপ ধারণা বলে মনে হচ্ছে।

3
আমি জেনেরিক এ (বি) উদাহরণ পছন্দ করি না এবং আমি কখনই অনুভব করিনি যে 100 টি বাস্তবায়ন হওয়াতে কোনও লগার প্রয়োজন। এটি একটি উদাহরণ যা আমি সম্প্রতি सामना করেছি এবং এটি সমাধানের জন্য এটি 5 টির একটি উপায়, যেখানে পোস্টশার্প ব্যবহার করে আসলে একটি অন্তর্ভুক্ত ছিল। এটি ক্লাসিক ক্লাস ভিত্তিক কর্টর ইঞ্জেকশন পদ্ধতির চিত্র তুলে ধরেছে। আপনি যেখানে ডিআই-র জন্য ভাল ব্যবহারের মুখোমুখি হয়েছিলেন তার আরও ভাল বাস্তব বিশ্বের উদাহরণ সরবরাহ করতে পারেন?
সিউর

2
আমি কখনই ডিআই এর জন্য ভাল ব্যবহার করতে দেখিনি। আমি কেন প্রশ্ন লিখলাম তা ঠিক।

2
আমি এটি সহায়ক বলে মনে করি না। আমার কোডটি সর্বদা পরীক্ষা করা সহজ। দেখা যাচ্ছে যে ডিআই খারাপ কোড সহ বড় কোড ঘাঁটির জন্য ভাল।

1
সচেতন থাকুন এমনকি ছোট ফাংশনাল প্রোগ্রামগুলিতে, যখনই আপনার f (x), g (f) থাকে আপনি ইতিমধ্যে নির্ভরতা ইনজেকশন ব্যবহার করছেন, সুতরাং জেএসে প্রতিটি ধারাবাহিকতা নির্ভরতা ইনজেকশন হিসাবে গণ্য হবে। আমার অনুমান যে আপনি ইতিমধ্যে এটি ব্যবহার করছেন;)
সিসার

15

আমি মনে করি ক্লাসিক উত্তরটি একটি আরও decoupled অ্যাপ্লিকেশন তৈরি করা, যা রানটাইম সময় কোন বাস্তবায়ন ব্যবহার করা হবে তার কোন জ্ঞান নেই।

উদাহরণস্বরূপ, আমরা একটি কেন্দ্রীয় অর্থ প্রদানের সরবরাহকারী, বিশ্বজুড়ে অনেক অর্থ প্রদানের সরবরাহকারীর সাথে কাজ করছি। যাইহোক, যখন একটি অনুরোধ করা হয়, তখন আমি কোন পেমেন্ট প্রসেসর কল করতে যাচ্ছি তা আমার কোনও ধারণা নেই। আমি এক টন সুইচ কেস সহ একটি ক্লাসে প্রোগ্রাম করতে পারি, যেমন:

class PaymentProcessor{

    private String type;

    public PaymentProcessor(String type){
        this.type = type;
    }

    public void authorize(){
        if (type.equals(Consts.PAYPAL)){
            // Do this;
        }
        else if(type.equals(Consts.OTHER_PROCESSOR)){
            // Do that;
        }
    }
}

এখন কল্পনা করুন যে এখন আপনাকে এই সমস্ত কোডটি একটি একক শ্রেণিতে বজায় রাখতে হবে কারণ এটি সঠিকভাবে ডিকপলড হয়নি, আপনি কল্পনা করতে পারেন যে প্রতিটি নতুন প্রসেসরের আপনি সমর্থন করবেন তার জন্য আপনাকে নতুন একটি তৈরি করতে হবে যদি // সুইচ কেস প্রতিটি পদ্ধতিতে, এটি কেবল আরও জটিল হয়ে ওঠে, তবে নির্ভরতা ইনজেকশন (বা নিয়ন্ত্রণের বিপরীতে - যেমন এটি কখনও কখনও বলা হয়, যার অর্থ এই যে প্রোগ্রামটি সঞ্চালন নিয়ন্ত্রণ করে সে কেবল রানটাইমের সময়ই পরিচিত, এবং জটিলতা নয়) আপনি কিছু অর্জন করতে পারেন খুব ঝরঝরে এবং রক্ষণাবেক্ষণযোগ্য।

class PaypalProcessor implements PaymentProcessor{

    public void authorize(){
        // Do PayPal authorization
    }
}

class OtherProcessor implements PaymentProcessor{

    public void authorize(){
        // Do other processor authorization
    }
}

class PaymentFactory{

    public static PaymentProcessor create(String type){

        switch(type){
            case Consts.PAYPAL;
                return new PaypalProcessor();

            case Consts.OTHER_PROCESSOR;
                return new OtherProcessor();
        }
    }
}

interface PaymentProcessor{
    void authorize();
}

** কোডটি সংকলন করবে না, আমি জানি :)


+1 কারণ মনে হচ্ছে আপনি বলছেন যে আপনি যেখানে ভার্চুয়াল পদ্ধতি / ইন্টারফেস ব্যবহার করেন সেখানে এটি দরকার। তবে এখনও বিরল। আমি new ThatProcessor()তারপরে এটির পরিবর্তে এখনও একটি ফ্রেমওয়ার্ক ব্যবহার করব

@ আইটাইস আপনি ক্লাস কারখানার নকশা ধাঁচের সাহায্যে অগণিত স্যুইচগুলি এড়াতে পারবেন। প্রতিবিম্ব সিস্টেমটি ব্যবহার করুন.নির্ধারণ করুন.অ্যাস্পেসমেন্ট.গেটএক্সেকিউটিংঅ্যাস্পাব্যাশন ()। ক্রিয়েটইনস্ট্যান্স ()
ডোমেনিকার

টুইটারে তবে আমি এটি একটি সরল উদাহরণে ব্যাখ্যা করতে চেয়েছিলাম
Itai Sagi

আমি কারখানার শ্রেণির প্রয়োজন বাদে উপরের ব্যাখ্যার সাথে একমত। যে মুহুর্তে আমরা কারখানার শ্রেণিটি প্রয়োগ করি এটির কেবল একটি অশোধিত নির্বাচন। ব্রোস এরকেলের পায়োমরফিজমের অধ্যায় এবং ভার্চুয়াল ফাংশনটির উপরে আমি এর সর্বোত্তম ব্যাখ্যা পেয়েছি। সত্য ডিআইটি নির্বাচন থেকে মুক্ত হওয়া উচিত এবং স্বয়ংক্রিয়ভাবে ইন্টারফেসের মাধ্যমে রান-টাইমে অবজেক্টের ধরণের সিদ্ধান্ত নেওয়া উচিত। সত্য পলিমারফিক আচরণও এটাই।
অরবিন্দ ক্রমার

উদাহরণস্বরূপ (সি ++ অনুযায়ী) আমাদের একটি সাধারণ ইন্টারফেস রয়েছে যা কেবল বেস ক্লাসের রেফারেন্স নেয় এবং নির্বাচন ছাড়াই এর ডেরিভ ক্লাসের আচরণ প্রয়োগ করে। শূন্য সুর (যন্ত্র ও i)। i.play (মিডলসি); main int main () {বায়ু বাঁশি; সুর (বাঁশি); Ru উপকরণটি বেস শ্রেণি, বায়ু এটি থেকে উদ্ভূত হয়। সি ++ অনুসারে ভার্চুয়াল ফাংশন সাধারণ ইন্টারফেসের মাধ্যমে উদ্ভূত শ্রেণীর আচরণ বাস্তবায়িত করে তোলে।
অরবিন্দ ক্রমার

6

ডিআই ব্যবহারের মূল কারণ হ'ল আপনি যেখানে জ্ঞান সেখানে প্রয়োগের জ্ঞানের দায়িত্ব রাখতে চান। ইন্টারফেস দ্বারা এনক্যাপসুলেশন এবং ডিজাইনের সাথে ডিআই-এর ধারণাটি অনেকটা ইনলাইন। যদি সামনের প্রান্তটি কিছু উপাত্তের জন্য পিছনের প্রান্ত থেকে জিজ্ঞাসা করে, তবে পিছনের প্রান্তটি কীভাবে প্রশ্নটি সমাধান করে তা সামনের দিকের জন্য গুরুত্বপূর্ণ নয়। এটি অনুরোধহীনারের উপর নির্ভর করে।

এটি দীর্ঘ সময়ের জন্য ওওপিতে ইতিমধ্যে সাধারণ। অনেক সময় কোড পিস তৈরি করে:

I_Dosomething x = new Impl_Dosomething();

অসুবিধাটি হ'ল বাস্তবায়নকারী ক্লাসটি এখনও হার্ডকোডযুক্ত, তাই এর প্রান্তে জ্ঞান রয়েছে যা বাস্তবায়ন ব্যবহৃত হয়। ডিআই ইন্টারফেসের মাধ্যমে ডিজাইনটিকে আরও একধাপ এগিয়ে নিয়ে যায়, যে সামনের অংশটি কেবলমাত্র ইন্টারফেসের জ্ঞান know ডিওয়াইআই এবং ডিআই-র মধ্যে একটি সার্ভিস লোকেটারের প্যাটার্ন হ'ল, কারণ এর অনুরোধটি সমাধান হওয়ার জন্য সামনের প্রান্তটি একটি কী (পরিষেবা লোকেটারের রেজিস্ট্রিতে উপস্থিত) সরবরাহ করতে হবে। পরিষেবা লোকেটার উদাহরণ:

I_Dosomething x = ServiceLocator.returnDoing(String pKey);

ডিআই উদাহরণ:

I_Dosomething x = DIContainer.returnThat();

ডিআই-এর একটি প্রয়োজনীয়তা হ'ল কনটেইনারটি অবশ্যই কোন শ্রেণিটি কোন ইন্টারফেসের প্রয়োগের তা নির্ধারণ করতে সক্ষম হতে হবে। সুতরাং একটি ডিআই কনটেইনারকে দৃ interface়ভাবে টাইপ করা ডিজাইন এবং একই সাথে প্রতিটি ইন্টারফেসের জন্য কেবলমাত্র একটি প্রয়োগকরণ প্রয়োজন। আপনার যদি একই সাথে কোনও ইন্টারফেসের আরও বাস্তবায়ন প্রয়োজন হয় (যেমন একটি ক্যালকুলেটর), আপনার প্রয়োজন সার্ভিস লোকেটার বা কারখানার নকশার প্যাটার্ন।

ডি (খ) আই: ইন্টারফেস দ্বারা নির্ভরতা ইনজেকশন এবং ডিজাইন। যদিও এই সীমাবদ্ধতা খুব বড় ব্যবহারিক সমস্যা নয়। ডি (বি) ব্যবহার করার সুবিধাটি হ'ল এটি ক্লায়েন্ট এবং সরবরাহকারীর মধ্যে যোগাযোগ করে। একটি ইন্টারফেস একটি বস্তুর বা আচরণের একটি সেট একটি দৃষ্টিভঙ্গি হয়। দ্বিতীয়টি এখানে গুরুত্বপূর্ণ is

আমি কোডিংয়ে ডি (খ) এর সাথে একসাথে পরিষেবা চুক্তির প্রশাসনের পছন্দ করি। তাদের একসাথে যাওয়া উচিত। পরিষেবা চুক্তির সাংগঠনিক প্রশাসন ব্যতীত প্রযুক্তিগত সমাধান হিসাবে আমি ডি (খ) I এর ব্যবহারটি আমার দৃষ্টিকোণে খুব উপকারী নয়, কারণ ডিআই তখন এনক্যাপসুলেশনের কেবল একটি অতিরিক্ত স্তর। কিন্তু আপনি যখন এটি সাংগঠনিক প্রশাসনের সাথে একসাথে ব্যবহার করতে পারবেন আপনি সত্যিকার অর্থে অর্গানাইজিং নীতিটি ডি (খ) এর অফারটি ব্যবহার করতে পারেন। এটি আপনাকে পরীক্ষার, সংস্করণকরণ এবং বিকল্পগুলির বিকাশ হিসাবে বিষয়গুলিতে ক্লায়েন্ট এবং অন্যান্য প্রযুক্তিগত বিভাগগুলির সাথে যোগাযোগের কাঠামোয় দীর্ঘমেয়াদে সহায়তা করতে পারে। আপনি যখন হার্ডকোডযুক্ত শ্রেণীর মতো একটি অন্তর্নিহিত ইন্টারফেস রাখেন, তখন যখন আপনি ডি (খ) আই ব্যবহার করে এটি স্পষ্ট করে তুলেন তখন সময়ের সাথে এটি কি কম যোগাযোগযোগ্য হয়? এটি সমস্ত রক্ষণাবেক্ষণে ফোটে, যা সময়ের সাথে সাথে একসাথে নয়। :-)


1
"অসুবিধাটি হ'ল বাস্তবায়ন শ্রেণিটি এখনও হার্ডকোডযুক্ত" <- বেশিরভাগ সময় কেবলমাত্র একটি বাস্তবায়ন থাকে এবং যেমন আমি বলেছিলাম যে আমি নংগেম কোডটি ভাবতে পারি না যার জন্য এমন একটি ইন্টারফেস দরকার যা ইতিমধ্যে অন্তর্নির্মিত হয়নি (। নেট) )।

@ অ্যাসিডজম্বি ২৪ হতে পারে ... তবে আপনার ইন্টারফেসের প্রয়োজন হলে পরে ডিআই-র মাধ্যমে একটি নন-ডিআই সমাধান পরিবর্তন করার প্রয়াসের সাথে শুরু করে ডিআই ব্যবহার করে একটি সমাধান বাস্তবায়নের প্রচেষ্টাটির সাথে তুলনা করুন। আমি প্রায় সবসময় প্রথম বিকল্পের সাথে যেতে চাই। আগামীকাল 100.000 pay দেওয়ার পরিবর্তে এখন 100 ডলার প্রদান করা ভাল।
গোলো রডেন

1
@ গোলরোডেন প্রকৃতপক্ষে, ডি (খ) আই এর মতো কৌশলগুলি ব্যবহার করে রক্ষণাবেক্ষণই মূল সমস্যা। এটি একটি অ্যাপ্লিকেশন ব্যয়ের 80%। একটি নকশা যাতে শুরু থেকে ইন্টারফেস ব্যবহার করে প্রয়োজনীয় আচরণটি স্পষ্টভাবে তৈরি করা হয় পরে পরে অনেক সময় এবং অর্থের সংস্থান সংরক্ষণ করে।
লোকে বার্গম্যান

আমি এটি পরিশোধ না করা অবধি সত্যই বুঝতে পারছি না কারণ এখন পর্যন্ত আমি I 0 প্রদান করেছি এবং এখনও পর্যন্ত আমার কেবল $ 0 প্রদান করতে হবে। তবে আমি প্রতিটি লাইন বা ফাংশন পরিষ্কার রাখতে $ 0.05 দিতে পারি।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.