আপনি যখন এই সমস্যাগুলি সমাধান করেন তখন তারা যে সমস্যাগুলি সমাধান করতে পারে সেগুলি সমাধান করার জন্য আপনার কৌশলগুলি ব্যবহার করা উচিত। নির্ভরতা বিপরীতকরণ এবং ইনজেকশন আলাদা নয়।
নির্ভরতা বিপর্যয় বা ইনজেকশন এমন একটি কৌশল যা কোনও কোড প্রয়োগ করার সময় রান করার সময় আপনার কোডটি সিদ্ধান্ত নিতে পারে your এটি দেরীতে বাইন্ডিংয়ের সুবিধা সর্বাধিক করে তোলে। কৌশলটি প্রয়োজনীয় যখন ভাষা যখন অ-ইনস্ট্যান্ট ফাংশনগুলির রান টাইম রিপ্লেসমেন্টকে সমর্থন করে না। উদাহরণস্বরূপ, জাভাতে কোনও স্ট্যাটিক পদ্ধতিতে কলগুলির সাথে আলাদাভাবে প্রয়োগের কলগুলি প্রতিস্থাপনের জন্য কোনও ব্যবস্থা নেই; পাইথনের সাথে বিপরীতে, যেখানে ফাংশন কলটি প্রতিস্থাপনের জন্য প্রয়োজনীয় সমস্ত হ'ল নামটি একটি আলাদা ফাংশনে আবদ্ধ করা (ফাংশনটি ধারণ করে চলকটিকে পুনরায় সাইন করা)।
আমরা কেন ফাংশনটির প্রয়োগকে আলাদা করতে চাই? এর দুটি প্রধান কারণ রয়েছে:
- আমরা পরীক্ষার উদ্দেশ্যে ফেক ব্যবহার করতে চাই। এটি আমাদের এমন কোনও শ্রেণীর পরীক্ষা করতে দেয় যা আসলে ডাটাবেসের সাথে সংযোগ না করে কোনও ডাটাবেস আনার উপর নির্ভর করে।
- আমাদের একাধিক বাস্তবায়ন সমর্থন করা দরকার। উদাহরণস্বরূপ, আমাদের একটি সিস্টেম স্থাপন করতে হবে যা মাইএসকিউএল এবং পোস্টগ্রেএসকিউএল উভয় ডেটাবেস সমর্থন করে।
আপনি নিয়ন্ত্রণ পাত্রে বিপরীতকরণের নোট নিতেও পারেন। এটি এমন একটি কৌশল যা আপনাকে এই সিউডোকোডের মতো দেখতে বিশাল, জটযুক্ত নির্মাণ গাছগুলি এড়াতে সহায়তা করার উদ্দেশ্যে করা হয়েছে:
thing5 = new MyThing5();
thing3 = new MyThing3(thing5, new MyThing10());
myApp = new MyApp(
new MyAppDependency1(thing5, thing3),
new MyAppDependency2(
new Thing1(),
new Thing2(new Thing3(thing5, new Thing4(thing5)))
),
...
new MyAppDependency15(thing5)
);
এটি আপনাকে আপনার ক্লাসগুলি রেজিস্টার করতে দেয় এবং তারপরে আপনার জন্য নির্মাণটি করতে দেয়:
injector.register(Thing1); // Yes, you'd need some kind of actual class reference.
injector.register(Thing2);
...
injector.register(MyAppDepdency15);
injector.register(MyApp);
myApp = injector.create(MyApp); // The injector fills in all the construction parameters.
মনে রাখবেন যে নিবন্ধিত ক্লাসগুলি স্টেটলেস সিঙ্গেলন হতে পারে তবে এটি সবচেয়ে সহজ ।
সাবধানতা শব্দ
নোট করুন যে নির্ভরতা বিপরীতমুখীটি আপনার যুক্তি ডিক্লুংয়ের জন্য জবাব দেওয়া উচিত নয় । পরিবর্তে প্যারামিটারাইজেশন ব্যবহার করার সুযোগগুলি সন্ধান করুন। উদাহরণস্বরূপ এই সিউডোকোড পদ্ধতিটি বিবেচনা করুন:
myAverageAboveMin()
{
dbConn = new DbConnection("my connection string");
dbQuery = dbConn.makeQuery();
dbQuery.Command = "SELECT * FROM MY_DATA WHERE x > :min";
dbQuery.setParam("min", 5);
dbQuery.Execute();
myData = dbQuery.getAll();
count = 0;
total = 0;
foreach (row in myData)
{
count++;
total += row.x;
}
return total / count;
}
আমরা এই পদ্ধতির কিছু অংশের জন্য নির্ভরতা বিপরীত ব্যবহার করতে পারি:
class MyQuerier
{
private _dbConn;
MyQueries(dbConn) { this._dbConn = dbConn; }
fetchAboveMin(min)
{
dbQuery = this._dbConn.makeQuery();
dbQuery.Command = "SELECT * FROM MY_DATA WHERE x > :min";
dbQuery.setParam("min", min);
dbQuery.Execute();
return dbQuery.getAll();
}
}
class Averager
{
private _querier;
Averager(querier) { this._querier = querier; }
myAverageAboveMin(min)
{
myData = this._querier.fetchAboveMin(min);
count = 0;
total = 0;
foreach (row in myData)
{
count++;
total += row.x;
}
return total / count;
}
তবে আমাদের করা উচিত নয়, কমপক্ষে পুরোপুরি নয়। লক্ষ্য করুন যে আমরা এর সাথে একটি রাষ্ট্রীয় শ্রেণি তৈরি করেছি Querier
। এটি এখন কিছু মূলত বিশ্বব্যাপী সংযোগ বস্তুর একটি রেফারেন্স ধারণ করে holds এটি প্রোগ্রামের সামগ্রিক অবস্থা বুঝতে অসুবিধা এবং বিভিন্ন শ্রেণি একে অপরের সাথে কীভাবে সমন্বয় সাধন করে এমন সমস্যা তৈরি করে। আরও লক্ষ করুন যে আমরা গড় যুক্তি পরীক্ষা করতে চাইলে আমরা কোয়েরিয়ার বা সংযোগটি জাল করতে বাধ্য হই। প্যারামিটারাইজেশন বাড়াতে আরও ভাল পন্থা হবে :
class MyQuerier
{
fetchAboveMin(dbConn, min)
{
dbQuery = dbConn.makeQuery();
dbQuery.Command = "SELECT * FROM MY_DATA WHERE x > :min";
dbQuery.setParam("min", min);
dbQuery.Execute();
return dbQuery.getAll();
}
}
class Averager
{
averageData(myData)
{
count = 0;
total = 0;
foreach (row in myData)
{
count++;
total += row.x;
}
return total / count;
}
class StuffDoer
{
private _querier;
private _averager;
StuffDoer(querier, averager)
{
this._querier = querier;
this._averager = averager;
}
myAverageAboveMin(dbConn, min)
{
myData = this._querier.fetchAboveMin(dbConn, min);
return this._averager.averageData(myData);
}
}
এবং সংযোগটি এমন কিছু এমনকি উচ্চ স্তরে পরিচালিত হবে যা পুরোপুরি অপারেশনের জন্য দায়ী এবং এই আউটপুটটির সাথে কী করা জানে।
এখন আমরা ক্যোয়ারিংয়ের পুরোপুরি স্বতন্ত্রভাবে গড় যুক্তি পরীক্ষা করতে পারি এবং আরও বিভিন্ন পরিস্থিতিতে আমরা এর ব্যবহার আরও কীভাবে করতে পারি। আমরা প্রশ্ন পারে কিনা আমরা এমনকি প্রয়োজন MyQuerier
এবং Averager
বস্তু, এবং হয়ত উত্তর যে আমরা না যদি আমরা ইউনিট পরীক্ষা মনস্থ না StuffDoer
, এবং ইউনিট টেস্টিং StuffDoer
পুরোপুরি যুক্তিসঙ্গত হবে যেহেতু এটা এত শক্তভাবে ডাটাবেসের সাথে মিলিত হচ্ছে। এটি কেবলমাত্র ইন্টিগ্রেশন পরীক্ষাগুলি coverেকে রাখার জন্য আরও বোধগম্য হতে পারে। সেক্ষেত্রে আমরা হয়ত ভাল তৈরি করতে fetchAboveMin
এবং averageData
অচল পদ্ধতিতে চলেছি।