নির্ভরতা বিপরীত নীতিটি কী এবং এটি কেন গুরুত্বপূর্ণ?
নির্ভরতা বিপরীত নীতিটি কী এবং এটি কেন গুরুত্বপূর্ণ?
উত্তর:
এই দস্তাবেজটি দেখুন: নির্ভরতা বিপরীতমুখী মূলনীতি ।
এটি মূলত বলে:
সংক্ষেপে এটি কেন গুরুত্বপূর্ণ, তা পরিবর্তনগুলি ঝুঁকিপূর্ণ এবং বাস্তবায়নের পরিবর্তে কোনও ধারণার উপর নির্ভর করে আপনি কল সাইটগুলিতে পরিবর্তনের প্রয়োজনীয়তা হ্রাস করেন।
কার্যকরভাবে, ডিআইপি কোডের বিভিন্ন অংশের মধ্যে সংযোগকে হ্রাস করে। ধারণাটি হ'ল লগিং সুবিধা বাস্তবায়নের অনেকগুলি উপায় থাকলেও আপনি যেভাবে এটি ব্যবহার করবেন তা সময় মতো তুলনামূলকভাবে স্থিতিশীল হওয়া উচিত। আপনি যদি লগিংয়ের ধারণার প্রতিনিধিত্ব করে এমন একটি ইন্টারফেস বের করতে পারেন তবে এই ইন্টারফেসটি বাস্তবায়নের চেয়ে সময়ের মধ্যে অনেক বেশি স্থিতিশীল হওয়া উচিত এবং লগিংয়ের ব্যবস্থাটি বজায় রাখার সময় বা প্রসারিত করার সময় আপনি যে পরিবর্তনগুলি করেছিলেন সেগুলি দ্বারা কল সাইটগুলি খুব কম প্রভাবিত হওয়া উচিত।
বাস্তবায়নটিকে একটি ইন্টারফেসের উপর নির্ভর করেও, আপনি রান-টাইমে চয়ন করার সম্ভাবনা পাবেন যা বাস্তবায়ন আপনার নির্দিষ্ট পরিবেশের জন্য আরও উপযুক্ত। কেসগুলির উপর নির্ভর করে এটি আকর্ষণীয়ও হতে পারে।
Agile সফ্টওয়্যার ডেভলপমেন্ট, নীতিমালা, প্যাটার্নস এবং সি # তে অনুশীলন এবং চতুর নীতি, প্যাটার্নস এবং অনুশীলন বইগুলি নির্ভরতা বিপরীত নীতিটির পিছনে মূল লক্ষ্যগুলি এবং অনুপ্রেরণাগুলি সম্পূর্ণরূপে বোঝার জন্য সেরা উত্স। "ডিপেন্ডেন্সি ইনভার্সন প্রিন্সিপাল" নিবন্ধটিও একটি ভাল সংস্থান, তবে এটি একটি খসড়ার একটি ঘনীভূত সংস্করণ যা অবশেষে পূর্বে উল্লিখিত বইগুলিতে প্রবেশ করেছে, কারণ এটি একটি ধারণার উপর কিছু গুরুত্বপূর্ণ আলোচনা ছেড়ে দেয় প্যাকেজ এবং ইন্টারফেসের মালিকানা যা ডিজাইন প্যাটার্নস (গামা, এট। আল) বইয়ের মধ্যে পাওয়া যায় "সাধারণভাবে এই প্রোগ্রামটিকে একটি ইন্টারফেসে, কোনও প্রয়োগকরণ নয়" থেকে এই নীতিটিকে আলাদা করার পরামর্শ দেয়।
একটি সংক্ষিপ্তসার সরবরাহের জন্য, নির্ভরতা বিপরীত নীতিটি মূলত "উচ্চ স্তরের" উপাদানগুলি থেকে "নিম্ন স্তরের" উপাদানগুলিতে নির্ভরশীলতার প্রচলিত দিককে পরিবর্তিত করার বিষয়ে যেমন "নিম্ন স্তরের" উপাদানগুলি "উচ্চ স্তরের" উপাদানগুলির মালিকানাধীন ইন্টারফেসের উপর নির্ভরশীল । (দ্রষ্টব্য: "উচ্চ স্তরের" উপাদানটি এখানে বাহ্যিক নির্ভরতা / পরিষেবাদিগুলির জন্য প্রয়োজনীয় উপাদানটিকে বোঝায়, প্রয়োজনীয় স্তরযুক্ত আর্কিটেকচারের মধ্যে এর ধারণাগত অবস্থানটি নয়)) এটি করার ক্ষেত্রে, যুগল তাত্ত্বিকভাবে উপাদানগুলি থেকে স্থানান্তরিত হওয়ার কারণে এতটা হ্রাস হয়নি isn't তাত্ত্বিকভাবে আরও মূল্যবান এমন উপাদানগুলির কাছে কম মূল্যবান।
এটি এমন উপাদানগুলি ডিজাইনের মাধ্যমে অর্জন করা হয়েছে যার বাহ্যিক নির্ভরতা একটি ইন্টারফেসের ক্ষেত্রে প্রকাশ করা হয় যার জন্য উপাদানটির গ্রাহক দ্বারা একটি প্রয়োগকরণ সরবরাহ করতে হবে। অন্য কথায়, সংজ্ঞায়িত ইন্টারফেসগুলি উপাদানটির কী প্রয়োজন তা প্রকাশ করে, আপনি কীভাবে উপাদানটি ব্যবহার করেন না (যেমন "আইএনইডসোমিংথিং" নয় "আইডোসোমিংথিং")।
ডিপেন্ডেন্সি ইনভার্সন নীতিটি যা উল্লেখ করে না তা হ'ল ইন্টারফেসের (যেমন মাই সার্ভিস → [আইলোগার ⇐ লগার]) ব্যবহারের মাধ্যমে নির্ভরতা বিমূ .় করার সহজ অনুশীলন। যদিও নির্ভরতার নির্দিষ্ট প্রয়োগের বিশদ থেকে এটি কোনও উপাদানকে ডিকুপল করে, এটি গ্রাহক এবং নির্ভরতার মধ্যে সম্পর্ককে উল্টে দেয় না (উদাঃ [মাই সার্ভিস → আইএমআই সার্ভিস লোগার] ger লগার)।
নির্ভরতা বিপরীতমূলক নীতির গুরুত্ব নির্ধারণ করা যেতে পারে সফ্টওয়্যার উপাদানগুলি পুনরায় ব্যবহার করতে সক্ষম হওয়ার একক লক্ষ্যে যা তাদের কার্যকারিতার একটি অংশের জন্য (লগিং, বৈধকরণ ইত্যাদি) বাহ্যিক নির্ভরতার উপর নির্ভর করে re
পুনরায় ব্যবহারের এই সাধারণ লক্ষ্যের মধ্যে আমরা দুটি উপ-প্রকার পুনঃব্যবহারের বর্ণনা করতে পারি:
উপ-নির্ভরতা বাস্তবায়ন সহ একাধিক অ্যাপ্লিকেশনগুলির মধ্যে একটি সফ্টওয়্যার উপাদান ব্যবহার করা (যেমন আপনি একটি ডিআই কনটেইনার তৈরি করেছেন এবং লগিং সরবরাহ করতে চান, তবে আপনার ধারকটিকে একটি নির্দিষ্ট লগারের সাথে জোড়া দিতে চান না যেমন আপনার ধারক ব্যবহারকারী প্রত্যেককেও করতে হবে আপনার নির্বাচিত লগিং লাইব্রেরি ব্যবহার করুন)।
একটি বিকশিত প্রসঙ্গের মধ্যে সফ্টওয়্যার উপাদান ব্যবহার করে (যেমন আপনি ব্যবসায়-যুক্তিযুক্ত উপাদানগুলি বিকাশ করেছেন যা প্রয়োগের বিশদগুলি যেখানে বিকশিত হচ্ছে এমন একাধিক সংস্করণ জুড়ে একই থাকে) across
একাধিক অ্যাপ্লিকেশন জুড়ে উপাদানগুলি পুনঃব্যবহারের প্রথম ক্ষেত্রে যেমন একটি অবকাঠামো লাইব্রেরির সাথে লক্ষ্য হ'ল আপনার গ্রাহকদের আপনার নিজস্ব লাইব্রেরির উপ-নির্ভরতার সাথে সংযুক্ত না করে আপনার গ্রাহকদের একটি মূল অবকাঠামোগত প্রয়োজনীয়তা সরবরাহ করা কারণ এ জাতীয় নির্ভরতার উপর নির্ভরশীলতা গ্রহণ করা আপনার প্রয়োজন ভোক্তাদের একই নির্ভরতাও প্রয়োজন। আপনার লাইব্রেরির গ্রাহকরা যখন একই অবকাঠামোগত প্রয়োজনের জন্য আলাদা লাইব্রেরি ব্যবহার করতে পছন্দ করেন (যেমন এনএলগ বনাম লগ 4 নেট), বা যদি তারা প্রয়োজনীয় লাইব্রেরির পরবর্তী সংস্করণ ব্যবহার করেন যা সংস্করণের সাথে সামঞ্জস্যপূর্ণ নয় তবে এটি সমস্যাযুক্ত হতে পারে আপনার গ্রন্থাগার দ্বারা প্রয়োজনীয়
ব্যবসায়-যুক্তিযুক্ত উপাদানগুলি পুনরায় ব্যবহারের দ্বিতীয় ক্ষেত্রে (অর্থাত্ "উচ্চ-স্তরের উপাদানগুলি"), লক্ষ্যটি হ'ল আপনার প্রয়োগের মূল ডোমেন বাস্তবায়নকে আপনার প্রয়োগের বিশদগুলির পরিবর্তনের প্রয়োজনগুলি (যেমন পরিবর্তন / আপগ্রেডিং অধ্যবসায় গ্রন্থাগারগুলি, বার্তাগুলি গ্রন্থাগারগুলি) থেকে বিচ্ছিন্ন করা to , এনক্রিপশন কৌশল ইত্যাদি)। আদর্শভাবে, কোনও প্রয়োগের প্রয়োগের বিশদ পরিবর্তন করে অ্যাপ্লিকেশনটির ব্যবসায়িক যুক্তি সংযুক্তকারী উপাদানগুলি ভাঙা উচিত নয়।
দ্রষ্টব্য: কেউ কেউ এই দ্বিতীয় কেসটিকে প্রকৃত পুনঃব্যবহার হিসাবে বর্ণনা করতে আপত্তি জানাতে পারে, এমন যুক্তি দিয়ে যে কোনও একক বিবর্তিত অ্যাপ্লিকেশনের মধ্যে ব্যবহৃত ব্যবসায়-যুক্তিযুক্ত উপাদানগুলির মতো উপাদানগুলি কেবল একটি একক ব্যবহারকে উপস্থাপন করে। তবে এখানে ধারণাটি হ'ল অ্যাপ্লিকেশনটির বাস্তবায়নের বিশদগুলিতে প্রতিটি পরিবর্তন একটি নতুন প্রসঙ্গ এবং তাই আলাদা ব্যবহারের ক্ষেত্রে রেন্ডার করে, যদিও চূড়ান্ত লক্ষ্যগুলি বিচ্ছিন্নতা বনাম বহনযোগ্যতা হিসাবে চিহ্নিত করা যেতে পারে।
এই দ্বিতীয় ক্ষেত্রে নির্ভরতা বিপর্যয় নীতি অনুসরণ করার সময় কিছু সুবিধা দিতে পারে, তবে এটি লক্ষ করা উচিত যে জাভা এবং সি # এর মতো আধুনিক ভাষাগুলিতে প্রয়োগ করা এর মান অনেকটা হ্রাস পেয়েছে, সম্ভবত এটি অপ্রাসঙ্গিক হওয়ার কারণে। যেমন পূর্বে আলোচনা হয়েছে, ডিআইপি বাস্তবায়ন বিবরণ সম্পূর্ণ পৃথক প্যাকেজগুলিতে পৃথক করে জড়িত। বিবর্তিত অ্যাপ্লিকেশনটির ক্ষেত্রে, তবে কেবল ব্যবসায়ের ডোমেনের ক্ষেত্রে সংজ্ঞায়িত ইন্টারফেসগুলি ব্যবহারের ফলে প্রয়োগের বিশদ উপাদানগুলির পরিবর্তনের প্রয়োজনীয়তার কারণে উচ্চ-স্তরের উপাদানগুলি সংশোধন করার প্রয়োজনীয়তা থেকে রক্ষা করবে, এমনকি বাস্তবায়নের বিবরণ চূড়ান্তভাবে একই প্যাকেজের মধ্যে থাকতে পারে এমন কি? । নীতিটির এই অংশটি সেই দিকগুলিকে প্রতিফলিত করে যে ভাষাগুলির সাথে প্রাসঙ্গিক ছিল যখন নীতিটি কোডিং হয়েছিল (যেমন সি ++) যা নতুন ভাষার সাথে প্রাসঙ্গিক নয়। বলেছিল,
এই নীতিটির দীর্ঘতর আলোচনা হিসাবে এটি ইন্টারফেসের সহজ ব্যবহারের সাথে সম্পর্কিত, নির্ভরতা ইনজেকশন এবং পৃথক ইন্টারফেস প্যাটার্নটি এখানে পাওয়া যাবে । অতিরিক্তভাবে, জাভাস্ক্রিপ্টের মতো নীতিগতভাবে টাইপযুক্ত ভাষার সাথে কীভাবে সম্পর্কিত তা নিয়ে একটি আলোচনা এখানে পাওয়া যাবে ।
যখন আমরা সফ্টওয়্যার অ্যাপ্লিকেশনগুলি ডিজাইন করি আমরা নিম্ন স্তরের ক্লাসগুলিকে বিবেচনা করতে পারি যা ক্লাসগুলি মৌলিক এবং প্রাথমিক ক্রিয়াকলাপগুলি প্রয়োগ করে (ডিস্ক অ্যাক্সেস, নেটওয়ার্ক প্রোটোকল, ...) এবং উচ্চ স্তরের শ্রেণিগুলি যে ক্লাসগুলি জটিল যুক্তি (ব্যবসায় প্রবাহ, ...) সজ্জিত করে।
শেষগুলি নিম্ন স্তরের শ্রেণিতে নির্ভর করে। এই জাতীয় কাঠামো বাস্তবায়নের একটি প্রাকৃতিক উপায় হ'ল নিম্ন স্তরের ক্লাসগুলি লিখতে হবে এবং একবার আমাদের সেগুলি জটিল উচ্চ স্তরের ক্লাসগুলি লিখতে হবে। যেহেতু উচ্চ স্তরের শ্রেণিগুলি অন্যের নিরিখে সংজ্ঞায়িত করা হয় এটি এটি করার যৌক্তিক উপায় বলে মনে হয়। তবে এটি নমনীয় নকশা নয়। আমাদের যদি একটি নিম্ন স্তরের শ্রেণি প্রতিস্থাপনের প্রয়োজন হয় তবে কী হবে?
নির্ভরতা বিপর্যয় নীতিতে বলা হয়েছে যে:
এই নীতিটি প্রচলিত ধারণাটিকে "বিপরীত" করতে চায় যে সফ্টওয়্যারটিতে উচ্চ স্তরের মডিউলগুলি নিম্ন স্তরের মডিউলগুলির উপর নির্ভর করে। এখানে উচ্চ স্তরের মডিউলগুলি বিমূর্তির মালিক (উদাহরণস্বরূপ, ইন্টারফেসের পদ্ধতিগুলি সিদ্ধান্ত নেওয়া) যা নিম্ন স্তরের মডিউলগুলি দ্বারা প্রয়োগ করা হয়। সুতরাং উচ্চ স্তরের মডিউলগুলির উপর নির্ভর করে নিম্ন স্তরের মডিউলগুলি তৈরি করা।
নির্ভরতা বিপর্যয় ভালভাবে প্রয়োগ করা আপনার অ্যাপ্লিকেশনটির পুরো আর্কিটেকচারের স্তরে নমনীয়তা এবং স্থায়িত্ব দেয়। এটি আপনার অ্যাপ্লিকেশনটিকে আরও সুরক্ষিত এবং স্থিতিশীলভাবে বিকশিত হতে দেবে।
Ditionতিহ্যগতভাবে একটি স্তরযুক্ত আর্কিটেকচার ইউআই ব্যবসায়ের স্তরের উপর নির্ভরশীল এবং এটি পরিবর্তিতভাবে ডেটা অ্যাক্সেস স্তরের উপর নির্ভরশীল।
আপনাকে স্তর, প্যাকেজ বা লাইব্রেরি বুঝতে হবে। কোডটি কেমন হবে তা দেখুন।
আমাদের ডেটা অ্যাক্সেস লেয়ারের জন্য একটি গ্রন্থাগার বা প্যাকেজ থাকবে।
// DataAccessLayer.dll
public class ProductDAO {
}
এবং অন্য একটি লাইব্রেরি বা প্যাকেজ স্তর ব্যবসায়িক যুক্তি যা ডেটা অ্যাক্সেস লেয়ারের উপর নির্ভর করে।
// BusinessLogicLayer.dll
using DataAccessLayer;
public class ProductBO {
private ProductDAO productDAO;
}
নির্ভরতা বিপর্যয় নিম্নলিখিতটি নির্দেশ করে:
উচ্চ-স্তরের মডিউলগুলি নিম্ন-স্তরের মডিউলগুলির উপর নির্ভর করে না। উভয়ের বিমূর্ততা উপর নির্ভর করা উচিত।
বিমূর্ততা বিশদ উপর নির্ভর করবে না। বিবরণ বিমূর্ততা উপর নির্ভর করা উচিত।
উচ্চ-স্তরের মডিউল এবং নিম্ন স্তরের কী কী? গ্রন্থাগার বা প্যাকেজগুলির মতো চিন্তাভাবনা মডিউলগুলি, উচ্চ-স্তরের মডিউলগুলি হ'ল traditionতিহ্যগতভাবে নির্ভরতা এবং নিম্ন স্তরের যার উপর তারা নির্ভর করে।
অন্য কথায়, মডিউল উচ্চ স্তরটি যেখানে ক্রিয়াটি চালিত হয় এবং নিম্ন স্তরের যেখানে কর্ম সঞ্চালিত হয়।
এই নীতিটি থেকে একটি যুক্তিসঙ্গত উপসংহার টানতে হবে যে কনক্র্যাশনগুলির মধ্যে কোনও নির্ভরতা থাকা উচিত নয়, তবে একটি বিমূর্ততার উপর নির্ভরতা থাকতে হবে। তবে আমরা যে পদ্ধতি গ্রহণ করি সে অনুসারে আমরা বিনিয়োগের উপর নির্ভরশীলতা নির্ভর করতে পারি, তবে একটি বিমূর্ততা।
কল্পনা করুন যে আমরা আমাদের কোডটি নিম্নরূপে গ্রহণ করেছি:
আমাদের ডেটা অ্যাক্সেস লেয়ারের জন্য একটি গ্রন্থাগার বা প্যাকেজ থাকবে যা বিমূর্তি সংজ্ঞায়িত করে।
// DataAccessLayer.dll
public interface IProductDAO
public class ProductDAO : IProductDAO{
}
এবং অন্য একটি লাইব্রেরি বা প্যাকেজ স্তর ব্যবসায়িক যুক্তি যা ডেটা অ্যাক্সেস লেয়ারের উপর নির্ভর করে।
// BusinessLogicLayer.dll
using DataAccessLayer;
public class ProductBO {
private IProductDAO productDAO;
}
যদিও আমরা ব্যবসায় এবং ডেটা অ্যাক্সেসের মধ্যে কোনও বিমূর্ততা নির্ভরতার উপর নির্ভরশীল।
নির্ভরতা বিপর্যয় পেতে, দৃistence়তা ইন্টারফেসটি মডিউল বা প্যাকেজে সংজ্ঞায়িত করতে হবে যেখানে এই উচ্চ স্তরের যুক্তি বা ডোমেনটি নিম্ন-স্তরের মডিউলটিতে নয়।
প্রথমে ডোমেন স্তরটি কী তা নির্ধারণ করুন এবং এর যোগাযোগের বিমূর্ততা দৃistence়তা সংজ্ঞায়িত করা হয়েছে।
// Domain.dll
public interface IProductRepository;
using DataAccessLayer;
public class ProductBO {
private IProductRepository productRepository;
}
অধ্যবসায় স্তর ডোমেনের উপর নির্ভর করে, যদি কোনও নির্ভরতা সংজ্ঞায়িত করা হয় তবে এখনই উল্টে যাবে।
// Persistence.dll
public class ProductDAO : IProductRepository{
}
(সূত্র: xurxodev.com )
উদ্দেশ্যটি এবং সুবিধার গভীরতর করে ধারণাটি ভালভাবে সংযুক্ত করা গুরুত্বপূর্ণ। আমরা যদি যান্ত্রিকভাবে থাকি এবং সাধারণ কেস সংগ্রহস্থলটি শিখি তবে আমরা নির্ভর করতে পারি যে আমরা নির্ভরতার নীতিটি কোথায় প্রয়োগ করতে পারি।
কিন্তু কেন আমরা একটি নির্ভরতা উল্টে না? নির্দিষ্ট উদাহরণের বাইরে মূল উদ্দেশ্য কী?
যেমন সাধারণত এগুলি সবচেয়ে স্থিতিশীল জিনিসগুলিকে, যা কম স্থিতিশীল জিনিসের উপর নির্ভর করে না, আরও ঘন ঘন পরিবর্তনের অনুমতি দেয়।
অধ্যবসায়ের ধরণের পরিবর্তন করা সহজ, ডোমেন যুক্তি বা অধ্যবসায়ের সাথে যোগাযোগের জন্য ডিজাইন করা ক্রিয়াগুলির চেয়ে একই ডাটাবেস অ্যাক্সেস করা ডাটাবেস বা প্রযুক্তি। এর কারণে, নির্ভরতা বিপরীত হয় কারণ এই পরিবর্তনটি ঘটে যদি অধ্যবসায় পরিবর্তন করা সহজ হয়। এইভাবে আমাদের ডোমেন পরিবর্তন করতে হবে না। ডোমেন স্তরটি সবার মধ্যে সবচেয়ে স্থিতিশীল, তাই এটি কোনও কিছুর উপর নির্ভর করে না।
তবে কেবল এই সংগ্রহস্থলের উদাহরণ নেই। এমন অনেক পরিস্থিতি রয়েছে যেখানে এই নীতিটি প্রয়োগ হয় এবং এই নীতি ভিত্তিক আর্কিটেকচার রয়েছে।
এমন আর্কিটেকচার রয়েছে যেখানে নির্ভরতা বিবর্তন তার সংজ্ঞার মূল চাবিকাঠি। সমস্ত ডোমেনে এটি সর্বাধিক গুরুত্বপূর্ণ এবং এটি বিমূর্ততা যা ডোমেনের মধ্যে যোগাযোগ প্রোটোকল এবং বাকী প্যাকেজ বা লাইব্রেরি সংজ্ঞায়িত করবে।
ইন ক্লিন স্থাপত্য ডোমেইন কেন্দ্রে অবস্থিত এবং যদি আপনি তীর নির্ভরতা ইঙ্গিত দিক তাকান, এটা স্পষ্ট কি সবচেয়ে গুরুত্বপূর্ণ এবং স্থিতিশীল স্তর আছে। বাহ্যিক স্তরগুলি অস্থির সরঞ্জাম হিসাবে বিবেচিত হয় তাই তাদের উপর নির্ভর করে এড়ানো উচিত।
(সূত্র: অষ্টম আলো ডটকম )
এটি ষড়ভুজ আর্কিটেকচারের সাথে একইভাবে ঘটে, যেখানে ডোমেনটি কেন্দ্রীয় অংশেও অবস্থিত এবং বন্দরগুলি ডোমিনো থেকে বাহ্যিক যোগাযোগের বিমূর্ততা। এখানে আবার স্পষ্ট যে ডোমেনটি সবচেয়ে স্থিতিশীল এবং traditionalতিহ্যগত নির্ভরতা উল্টে আছে।
আমার কাছে, নির্ভরশীলতা উল্টে দেওয়া নীতিমালা, যেমন অফিশিয়াল নিবন্ধে বর্ণিত হয়েছে , প্রকৃতপক্ষে কম পুনরায় ব্যবহারযোগ্য মডিউলগুলির পুনঃব্যবহারযোগ্যতা বৃদ্ধি করার পাশাপাশি সি ++ ভাষায় কোনও সমস্যা সমাধানের উপায় work
সি ++ এ সমস্যাটি হ'ল হেডার ফাইলগুলিতে সাধারণত ব্যক্তিগত ক্ষেত্র এবং পদ্ধতিগুলির ঘোষণা থাকে। সুতরাং, যদি উচ্চ-স্তরের সি ++ মডিউলটিতে নিম্ন-স্তরের মডিউলটির জন্য শিরোনাম ফাইল অন্তর্ভুক্ত থাকে তবে এটি বাস্তব বাস্তবায়নের উপর নির্ভর করবে সেই মডিউলটির বিশদের । এবং এটি, অবশ্যই, একটি ভাল জিনিস নয়। তবে আজকের দিনে সাধারণভাবে ব্যবহৃত আধুনিক ভাষাগুলিতে এটি কোনও সমস্যা নয়।
উচ্চ-স্তরের মডিউলগুলি নিম্ন-স্তরের মডিউলগুলির তুলনায় সহজাতভাবে কম পুনরায় ব্যবহারযোগ্য কারণ পূর্ববর্তীগুলির তুলনায় সাধারণত সাধারণত অ্যাপ্লিকেশন / প্রসঙ্গ নির্দিষ্ট specific উদাহরণস্বরূপ, একটি উপাদান যা একটি ইউআই স্ক্রিন প্রয়োগ করে তা হ'ল উচ্চ-স্তরের এবং অ্যাপ্লিকেশনটির জন্য খুব (সম্পূর্ণ?) নির্দিষ্ট। কোনও আলাদা অ্যাপ্লিকেশনে এ জাতীয় উপাদানটি পুনরায় ব্যবহার করার চেষ্টাটি প্রতি-উত্পাদনশীল, এবং কেবলমাত্র ওভার ইঞ্জিনিয়ারিংয়ের দিকে নিয়ে যেতে পারে।
সুতরাং, উপাদান A এর একটি একই স্তরের পৃথক বিমূর্ততা তৈরি করা যা একটি উপাদান বিয়ের উপর নির্ভর করে (যা A এর উপর নির্ভর করে না) কেবল তখনই করা যেতে পারে যখন উপাদান A বিভিন্ন অ্যাপ্লিকেশন বা প্রসঙ্গে পুনরায় ব্যবহারের জন্য কার্যকর হবে be যদি এটি না হয়, তবে ডিআইপি প্রয়োগ করা খারাপ নকশা হবে।
মূলত এটি বলে:
শ্রেণীর বিমূর্তকরণের উপর নির্ভর করা উচিত (উদাহরণস্বরূপ ইন্টারফেস, বিমূর্ত শ্রেণি), নির্দিষ্ট বিবরণ নয় (বাস্তবায়ন)।
ভাল উত্তর এবং ভাল উদাহরণ ইতিমধ্যে অন্যদের দ্বারা এখানে দেওয়া হয়েছে।
কারন চোবান গুরুত্বপূর্ণ কারণ এটি OO যেমন পণ্য-নীতি "ঢিলেঢালাভাবে মিলিত নকশা" নিশ্চিত করে হয়।
আপনার সফ্টওয়্যারটির অবজেক্টগুলি এমন স্তরবিন্যাসে প্রবেশ করা উচিত নয় যেখানে কয়েকটি অবজেক্ট নিম্ন-স্তরের বস্তুর উপর নির্ভরশীল শীর্ষ স্তরের হয়। নিম্ন-স্তরের অবজেক্টের পরিবর্তনগুলি তখন আপনার শীর্ষ-স্তরের অবজেক্টগুলিতে ছড়িয়ে পড়বে যা সফ্টওয়্যারটিকে পরিবর্তনের জন্য খুব ভঙ্গুর করে তুলেছে।
আপনি চান যে আপনার 'শীর্ষ-স্তরের' অবজেক্টগুলি খুব স্থিতিশীল এবং পরিবর্তনের জন্য ভঙ্গুর না হওয়ার জন্য, তাই আপনার নির্ভরতাগুলি উল্টাতে হবে।
নির্ভরতা বিপরীতমুখী মূলনীতিটি বর্ণনা করার আরও সুস্পষ্ট উপায় হ'ল:
জটিল ব্যবসার যুক্তি সজ্জিত করে এমন আপনার মডিউলগুলি সরাসরি অন্যান্য মডিউলের উপর নির্ভর করবে না যা ব্যবসায়িক যুক্তি সজ্জিত করে। পরিবর্তে, তাদের কেবলমাত্র সহজ ডেটাতে ইন্টারফেসের উপর নির্ভর করা উচিত।
অর্থ্যাৎ Logic
লোকেরা সাধারণত যেমন করে আপনার ক্লাস বাস্তবায়নের পরিবর্তে :
class Dependency { ... }
class Logic {
private Dependency dep;
int doSomething() {
// Business logic using dep here
}
}
আপনার কিছু করা উচিত:
class Dependency { ... }
interface Data { ... }
class DataFromDependency implements Data {
private Dependency dep;
...
}
class Logic {
int doSomething(Data data) {
// compute something with data
}
}
Data
এবং DataFromDependency
একই মডিউলে থাকা উচিত Logic
, সাথে নয়Dependency
।
কেন এমন করবেন?
Dependency
পরিবর্তন হয়, আপনার পরিবর্তন করার প্রয়োজন হয় নাLogic
।Logic
তা বোঝা খুব সহজ কাজ: এটি কেবল এটিডিটির মতো দেখায় likeLogic
এখন আরও সহজে পরীক্ষা করা যায়। আপনি এখন Data
নকল ডেটা দিয়ে সরাসরি ইনস্ট্যান্ট করতে পারেন এবং এতে পাস করতে পারেন m নকল বা জটিল পরীক্ষার স্ক্যাফোল্ডিংয়ের প্রয়োজন নেই।DataFromDependency
, যা সরাসরি উল্লেখ করে Dependency
, একই মডিউলে থাকে Logic
তবে Logic
মডিউলটি এখনও Dependency
সংকলনের সময় মডিউলটির উপর সরাসরি নির্ভর করে । পের আঙ্কেল বব নীতি সম্পর্কে ব্যাখ্যা , এড়ানো এটাই ডিআইপি-র পুরো বিষয়। বরং, চোবান উপভোগ করতে চান, Data
হিসাবে একই মডিউল হওয়া উচিত Logic
, কিন্তু DataFromDependency
হিসাবে একই মডিউল হওয়া উচিত Dependency
।
ইনভার্শন অফ কন্ট্রোল (আইওসি) এমন একটি নকশার প্যাটার্ন যেখানে কোনও বিষয় তার নির্ভরতার জন্য কাঠামো জিজ্ঞাসা না করে বাইরের কাঠামোর দ্বারা তার নির্ভরতা হস্তান্তর করে।
Traditionalতিহ্যবাহী চেহারা ব্যবহার করে সিউডোকোড উদাহরণ:
class Service {
Database database;
init() {
database = FrameworkSingleton.getService("database");
}
}
আইওসি ব্যবহার করে অনুরূপ কোড:
class Service {
Database database;
init(database) {
this.database = database;
}
}
আইওসির সুবিধাগুলি হ'ল:
নির্ভরতা বিপরীতকরণের বিষয়টি হ'ল পুনরায় ব্যবহারযোগ্য সফ্টওয়্যার তৈরি করা।
ধারণাটি হ'ল একে অপরের উপর নির্ভর করে দুটি টুকরো কোডের পরিবর্তে তারা কিছু বিমূর্ত ইন্টারফেসের উপর নির্ভর করে। তারপরে আপনি অন্যটি ছাড়াই উভয় অংশ পুনরায় ব্যবহার করতে পারেন।
এটি জাভাতে বসন্তের মতো নিয়ন্ত্রণের বিপরীতকরণ (আইওসি) কনটেইনার মাধ্যমে সর্বাধিক সাধারণভাবে অর্জিত হয়। এই মডেলটিতে, বস্তুগুলির বৈশিষ্ট্যগুলি এক্সএমএল কনফিগারেশনের মাধ্যমে অবজেক্টগুলি বাইরে যেতে এবং তার নির্ভরতা খুঁজে পাওয়ার পরিবর্তে সেট আপ করা হয়।
এই সিউডোকোডটি কল্পনা করুন ...
public class MyClass
{
public Service myService = ServiceLocator.service;
}
মাইক্র্লাস সরাসরি সার্ভিস ক্লাস এবং সার্ভিসলোকেটার ক্লাস উভয়ের উপরই নির্ভর করে। আপনি যদি এটি অন্য অ্যাপ্লিকেশনটিতে ব্যবহার করতে চান তবে তাদের উভয়েরই প্রয়োজন। এখন এটি কল্পনা করুন ...
public class MyClass
{
public IService myService;
}
এখন, মাইক্লাস একটি একক ইন্টারফেস, আইএসএসআর ইন্টারফেসের উপর নির্ভর করে। আমরা আইওসি পাত্রে আসলে সেই ভেরিয়েবলের মান সেট করতে দেব।
সুতরাং এখন, মাইক্লাস সহজেই অন্যান্য প্রকল্পগুলিতে এটির সাথে অন্য দুটি শ্রেণির নির্ভরতা না আনাই সহজেই পুনরায় ব্যবহার করা যেতে পারে।
আরও ভাল, আপনাকে মাই সার্ভিসের নির্ভরতা এবং সেই নির্ভরতাগুলির নির্ভরতা এবং ... ঠিক আছে, আপনাকে টেনে আনতে হবে না।
যদি আমরা এটি প্রদত্ত হিসাবে গ্রহণ করতে পারি যে কর্পোরেশনে একজন "উচ্চ স্তরের" কর্মচারীকে তাদের পরিকল্পনাগুলি কার্যকর করার জন্য অর্থ প্রদান করা হয় এবং এই পরিকল্পনাগুলি অনেকগুলি "নিম্ন স্তরের" কর্মচারীর পরিকল্পনার সামগ্রিক সম্পাদনের মাধ্যমে সরবরাহ করা হয়, তবে আমরা বলতে পারি উচ্চতর স্তরের কর্মচারীর পরিকল্পনার যে কোনও উপায়ে যে কোনও উপায়ে নিম্ন স্তরের কর্মচারীর নির্দিষ্ট পরিকল্পনার সাথে মিলিত হলে এটি সাধারণত একটি ভয়ানক পরিকল্পনা।
যদি কোনও উচ্চ স্তরের কার্যনির্বাহী "ডেলিভারির সময় উন্নত করার" পরিকল্পনা করে এবং নির্দেশ করে যে শিপিং লাইনের একজন কর্মচারীকে অবশ্যই অবশ্যই কফি খাওয়া উচিত এবং প্রতিদিন সকালে প্রসারিত করা উচিত, তবে সেই পরিকল্পনাটি খুব মিলিত এবং কম সংযুক্তি রয়েছে। তবে যদি পরিকল্পনার কোনও নির্দিষ্ট কর্মচারীর কথা উল্লেখ না করা হয় এবং বাস্তবে কেবল "এমন একটি সত্তা যা কাজ করতে পারে তার জন্য কাজ করার জন্য প্রস্তুত করা হয়" প্রয়োজন হয়, তবে পরিকল্পনাটি আলগাভাবে মিলিত হয় এবং আরও সম্মিলিত হয়: পরিকল্পনাগুলি ওভারল্যাপ হয় না এবং সহজেই প্রতিস্থাপিত হতে পারে । ঠিকাদার বা রোবটগুলি সহজেই কর্মচারীদের প্রতিস্থাপন করতে পারে এবং উচ্চ স্তরের পরিকল্পনা অপরিবর্তিত রয়েছে।
নির্ভরতা বিপরীত নীতির "উচ্চ স্তরের" অর্থ "আরও গুরুত্বপূর্ণ"।
আমি দেখতে পাচ্ছি উপরের উত্তরগুলিতে ভাল ব্যাখ্যা দেওয়া হয়েছে। তবে আমি সাধারণ উদাহরণ সহ কিছু সহজ ব্যাখ্যা দিতে চাই।
নির্ভরতা বিপরীকরণ নীতি প্রোগ্রামারটিকে হার্ডকোডযুক্ত নির্ভরতাগুলি সরাতে দেয় যাতে অ্যাপ্লিকেশনটি আলগাভাবে মিলিত হয় এবং প্রসারিত হয় able
এটি কীভাবে অর্জন করবেন: বিমূর্ততার মাধ্যমে
নির্ভরতা বিপরীত ছাড়াই:
class Student {
private Address address;
public Student() {
this.address = new Address();
}
}
class Address{
private String perminentAddress;
private String currentAdrress;
public Address() {
}
}
উপরের কোড স্নিপেটে, ঠিকানা অবজেক্টটি হার্ড-কোডড। পরিবর্তে যদি আমরা নির্ভরতা বিপরীতমুখী ব্যবহার করতে পারি এবং কনস্ট্রাক্টর বা সেটার পদ্ধতির মধ্য দিয়ে অ্যাড্রেস অবজেক্টটি ইনজেক্ট করতে পারি। দেখা যাক.
নির্ভরতা বিপরীতে:
class Student{
private Address address;
public Student(Address address) {
this.address = address;
}
//or
public void setAddress(Address address) {
this.address = address;
}
}
নির্ভরতা বিপরীতমুখী: সংক্ষেপে নয়, বিমূর্ততার উপর নির্ভর করে।
নিয়ন্ত্রণের বিপরীতে: প্রধান বনাম বিমূর্তি এবং কীভাবে প্রধান সিস্টেমগুলির আঠালো।
এটি সম্পর্কে ভাল কথা পোস্ট করা হয়:
https://coderstower.com/2019/03/26/dependency-inversion-why-you-shouldnt-avoid-it/
https://coderstower.com/2019/04/02/main-and-abstraction-the-decoupled-peers/
https://coderstower.com/2019/04/09/inversion-of-control-putting-all-together/
ধরা যাক যে আমাদের দুটি শ্রেণি রয়েছে: Engineer
এবংProgrammer
:
ক্লাস ইঞ্জিনিয়ারের প্রোগ্রামার ক্লাসের উপর নির্ভরতা থাকে, নীচের মতো:
class Engineer () {
fun startWork(programmer: Programmer){
programmer.work()
}
}
class Programmer {
fun work(){
//TODO Do some work here!
}
}
এই উদাহরণে শ্রেণীর Engineer
আমাদের Programmer
ক্লাসের উপর নির্ভরতা রয়েছে । আমার যদি পরিবর্তন করতে হয় তবে কী হবেProgrammer
?
অবশ্যই আমারও এটি পরিবর্তন করা দরকার Engineer
। (বাহ, এই সময়েOCP
খুব লঙ্ঘন করা হয়)
তারপরে, আমাদের এই গন্ডগোলটি পরিষ্কার করতে কী আছে? উত্তরটি আসলে বিমূর্ততা। বিমূর্ততা দ্বারা, আমরা এই দুটি শ্রেণীর মধ্যে নির্ভরতা অপসারণ করতে পারি। উদাহরণস্বরূপ, আমি Interface
প্রোগ্রামার ক্লাসের জন্য একটি তৈরি করতে পারি এবং এখন থেকে প্রতিটি ক্লাস যে Programmer
এটি ব্যবহার করতে চায় তা ব্যবহার করতে হবেInterface
, তারপরে প্রোগ্রামার ক্লাস পরিবর্তন করে, আমাদের যে ক্লাস ব্যবহার করেছে তা পরিবর্তন করার দরকার নেই, কারণ বিমূর্ততার কারণে আমরা ব্যবহার করা হয়েছে।
দ্রষ্টব্য: DependencyInjection
আমাদের করতে DIP
এবং SRP
খুব সহায়তা করতে পারে ।
সাধারণত উত্তরের উত্তরের উদ্রেক ঘটায় আমি ভাল বনাম খারাপ অনুশীলন প্রদর্শন করতে নিজের একটি ছোট্ট নমুনা যুক্ত করতে চাই। এবং হ্যাঁ, আমি পাথর নিক্ষেপের কেউ নই!
বলুন, আপনি একটি ছোট প্রোগ্রাম কনসোল আই / ওয়ের মাধ্যমে একটি স্ট্রিংকে বেস 6464 ফর্ম্যাটে রূপান্তর করতে চান । এখানে নির্বিকার পন্থা:
class Program
{
static void Main(string[] args)
{
/*
* BadEncoder: High-level class *contains* low-level I/O functionality.
* Hence, you'll have to fiddle with BadEncoder whenever you want to change
* the I/O mode or details. Not good. A good encoder should be I/O-agnostic --
* problems with I/O shouldn't break the encoder!
*/
BadEncoder.Run();
}
}
public static class BadEncoder
{
public static void Run()
{
Console.WriteLine(Convert.ToBase64String(Encoding.UTF8.GetBytes(Console.ReadLine())));
}
}
ডিআইপি মূলত বলেছে যে উচ্চ-স্তরের উপাদানগুলি নিম্ন-স্তরের বাস্তবায়নের উপর নির্ভরশীল হওয়া উচিত নয়, যেখানে রবার্ট সি মার্টিনের ("ক্লিন আর্কিটেকচার") অনুসারে "স্তর" I / O থেকে দূরত্ব। তবে কীভাবে আপনি এই পরিস্থিতি থেকে বেরিয়ে আসবেন? কীভাবে কীভাবে এটি বাস্তবায়িত হয় তা বিরক্ত না করে কেবলমাত্র কেন্দ্রীয় এনকোডারকে কেবল ইন্টারফেসের উপর নির্ভরশীল করে তুলে:
class Program
{
static void Main(string[] args)
{
/* Demo of the Dependency Inversion Principle (= "High-level functionality
* should not depend upon low-level implementations"):
* You can easily implement new I/O methods like
* ConsoleReader, ConsoleWriter without ever touching the high-level
* Encoder class!!!
*/
GoodEncoder.Run(new ConsoleReader(), new ConsoleWriter()); }
}
public static class GoodEncoder
{
public static void Run(IReadable input, IWriteable output)
{
output.WriteOutput(Convert.ToBase64String(Encoding.ASCII.GetBytes(input.ReadInput())));
}
}
public interface IReadable
{
string ReadInput();
}
public interface IWriteable
{
void WriteOutput(string txt);
}
public class ConsoleReader : IReadable
{
public string ReadInput()
{
return Console.ReadLine();
}
}
public class ConsoleWriter : IWriteable
{
public void WriteOutput(string txt)
{
Console.WriteLine(txt);
}
}
নোট করুন যে GoodEncoder
আই / ও মোডটি পরিবর্তনের জন্য আপনাকে স্পর্শ করার দরকার নেই - যে শ্রেণিটি I / O ইন্টারফেসগুলি এটি জানে তাতে খুশি; কোনও নিম্ন-স্তরের বাস্তবায়ন IReadable
এবং IWriteable
এটি কখনই বিরক্ত করবে না।
GoodEncoder
আপনার দ্বিতীয় উদাহরণের উপর নির্ভর করে না। ডিআইপি উদাহরণ তৈরি করার জন্য, আপনি এখানে যে ইন্টারফেসগুলি উত্তোলন করেছেন তার "মালিকানাধীন" ধারণাটি প্রবর্তন করতে হবে - এবং বিশেষত, গুডইনকোডার হিসাবে একই প্যাকেজে তাদের প্রয়োগগুলি বাইরে থাকাকালীন রাখতে হবে।
ডিপেন্ডেন্সি ইনভার্সন প্রিন্সিপাল (ডিআইপি) বলেছে
i) উচ্চ স্তরের মডিউলগুলি নিম্ন-স্তরের মডিউলগুলির উপর নির্ভর করে না। উভয়েরই বিমূর্ততার উপর নির্ভর করা উচিত।
ii) বিমূর্ততা কখনই বিশদের উপর নির্ভর করে না। বিবরণ বিমূর্ততা উপর নির্ভর করা উচিত।
উদাহরণ:
public interface ICustomer
{
string GetCustomerNameById(int id);
}
public class Customer : ICustomer
{
//ctor
public Customer(){}
public string GetCustomerNameById(int id)
{
return "Dummy Customer Name";
}
}
public class CustomerFactory
{
public static ICustomer GetCustomerData()
{
return new Customer();
}
}
public class CustomerBLL
{
ICustomer _customer;
public CustomerBLL()
{
_customer = CustomerFactory.GetCustomerData();
}
public string GetCustomerNameById(int id)
{
return _customer.GetCustomerNameById(id);
}
}
public class Program
{
static void Main()
{
CustomerBLL customerBLL = new CustomerBLL();
int customerId = 25;
string customerName = customerBLL.GetCustomerNameById(customerId);
Console.WriteLine(customerName);
Console.ReadKey();
}
}
দ্রষ্টব্য: শ্রেণীর ইন্টারফেস বা বিমূর্ত শ্রেণির মতো বিমূর্তকরণের উপর নির্ভর করা উচিত, নির্দিষ্ট বিবরণ নয় (ইন্টারফেসের প্রয়োগ)।