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

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

এটা ঠিক তাই ঘটে যে প্রোগ্রামাররা ডিজাইন প্যাটার্ন আকারে সফল সমাধান একত্রিত করে। নিদর্শন উপর সাহিত্য অনেক আছে. এরিচ গামা, রিচার্ড হেলম, রাল্ফ জনসন এবং জন ভিলিসাইডসের "ডিজাইন প্যাটার্নস" এবং মার্টিন ফাউলারের "প্যাটার্নস অফ এন্টারপ্রাইজ অ্যাপ্লিকেশন আর্কিটেকচার" অবশ্যই ক্লাসিক হিসাবে বিবেচিত। পিএইচপি-তে - এটি। এটি এমনই ঘটে যে এই সমস্ত সাহিত্য এমন লোকেদের জন্য বেশ জটিল যারা সবেমাত্র OOP আয়ত্ত করতে শুরু করেছেন। তাই আমার কাছে এমন কিছু নিদর্শন উপস্থাপন করার ধারণা ছিল যা আমি একটি অত্যন্ত সরলীকৃত আকারে সবচেয়ে দরকারী বলে মনে করি। কথায়, এই নিবন্ধটি আমার প্রথম KISS শৈলীতে ডিজাইন প্যাটার্ন ব্যাখ্যা করার প্রয়াস।
আজ আমরা একটি OOP অ্যাপ্লিকেশনে অবজেক্ট ইনিশিয়ালাইজেশনের সাথে কী কী সমস্যা দেখা দিতে পারে এবং এই সমস্যাগুলি সমাধান করতে আপনি কীভাবে কিছু জনপ্রিয় ডিজাইন প্যাটার্ন ব্যবহার করতে পারেন সে সম্পর্কে কথা বলব।

উদাহরণ

একটি আধুনিক OOP অ্যাপ্লিকেশন দশ, শত এবং কখনও কখনও হাজার হাজার বস্তুর সাথে কাজ করে। ঠিক আছে, আসুন এই বস্তুগুলিকে আমাদের অ্যাপ্লিকেশনগুলিতে কীভাবে শুরু করা হয় তা ঘনিষ্ঠভাবে দেখে নেওয়া যাক। অবজেক্ট প্রারম্ভিকতা হল একমাত্র দিক যা এই নিবন্ধে আমাদের আগ্রহী, তাই আমি সমস্ত "অতিরিক্ত" বাস্তবায়ন বাদ দেওয়ার সিদ্ধান্ত নিয়েছি।
ধরা যাক আমরা একটি সুপার-ডুপার দরকারী ক্লাস তৈরি করেছি যা একটি নির্দিষ্ট URI-তে একটি GET অনুরোধ পাঠাতে পারে এবং সার্ভার প্রতিক্রিয়া থেকে HTML ফেরত দিতে পারে। যাতে আমাদের ক্লাসটি খুব সাধারণ বলে মনে হয় না, এটিকে ফলাফলও পরীক্ষা করতে দিন এবং সার্ভারটি "ভুলভাবে" প্রতিক্রিয়া জানালে একটি ব্যতিক্রম নিক্ষেপ করুন।

ক্লাস গ্র্যাবার ( পাবলিক ফাংশন get($url) (/** HTML কোড ফেরত দেয় বা একটি ব্যতিক্রম নিক্ষেপ করে */) )

আসুন আরেকটি ক্লাস তৈরি করি যার অবজেক্টগুলি প্রাপ্ত এইচটিএমএল ফিল্টার করার জন্য দায়ী। ফিল্টার পদ্ধতিটি আর্গুমেন্ট হিসাবে HTML কোড এবং একটি CSS নির্বাচককে নেয় এবং এটি প্রদত্ত নির্বাচকের জন্য পাওয়া উপাদানগুলির একটি অ্যারে প্রদান করে।

ক্লাস HtmlExtractor ( পাবলিক ফাংশন ফিল্টার ($html, $selector) (/** ফিল্টার করা উপাদানগুলির অ্যারে প্রদান করে */) )

এখন, কল্পনা করুন যে প্রদত্ত কীওয়ার্ডের জন্য আমাদের গুগলে অনুসন্ধান ফলাফল পেতে হবে। এটি করার জন্য, আমরা আরেকটি ক্লাস চালু করব যেটি একটি অনুরোধ পাঠাতে Grabber ক্লাস ব্যবহার করবে এবং প্রয়োজনীয় বিষয়বস্তু বের করার জন্য HtmlExtractor ক্লাস ব্যবহার করবে। এটিতে ইউআরআই নির্মাণের যুক্তিও থাকবে, প্রাপ্ত এইচটিএমএল ফিল্টার করার জন্য একটি নির্বাচক এবং প্রাপ্ত ফলাফলগুলি প্রক্রিয়াকরণ।

ক্লাস GoogleFinder ( ব্যক্তিগত $grabber; ব্যক্তিগত $filter; পাবলিক ফাংশন __construct() ( $this->grabber = new Grabber(); $this->filter = new HtmlExtractor(); ) পাবলিক ফাংশন খুঁজুন($searchString) ( /* * প্রতিষ্ঠিত ফলাফলের অ্যারে প্রদান করে */))

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

ক্লাস GoogleFinder ( ব্যক্তিগত $grabber; ব্যক্তিগত $filter; পাবলিক ফাংশন __construct(Grabber $grabber, HtmlExtractor $filter) ( $this->grabber = $grabber; $this->filter = $filter; ) পাবলিক ফাংশন খুঁজুন($searchString) (/** প্রতিষ্ঠিত ফলাফলের অ্যারে প্রদান করে */))

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

ক্লাস কন্ট্রোলার ( পাবলিক ফাংশন অ্যাকশন () ( /* কিছু জিনিস */ $finder = নতুন GoogleFinder(নতুন Grabber(), নতুন HtmlExtractor()); $results = $finder->

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

রেজিস্ট্রি টেমপ্লেট।

সুতরাং, আমরা কনফিগারেশনে অবজেক্ট তৈরি করার সিদ্ধান্ত নিয়েছি। এটা করা যাক.

$registry = নতুন ArrayObject(); $registry["grabber"] = new Grabber(); $registry["filter"] = নতুন HtmlExtractor(); $registry["google_finder"] = নতুন GoogleFinder($registry["grabber"], $registry["filter"]);
আমাদের যা করতে হবে তা হল আমাদের ArrayObject কে কন্ট্রোলারে পাস করা এবং সমস্যাটি সমাধান করা হয়েছে।

ক্লাস কন্ট্রোলার ( ব্যক্তিগত $রেজিস্ট্রি; পাবলিক ফাংশন __কনস্ট্রাক্ট(অ্যারেঅবজেক্ট $রেজিস্ট্রি) ( $this->রেজিস্ট্রি = $রেজিস্ট্রি; ) পাবলিক ফাংশন অ্যাকশন() ( /* কিছু জিনিস */ $results = $this->রেজিস্ট্রি["google_finder" ]->find("সার্চ স্ট্রিং"); /* ফলাফল সহ কিছু করুন */ ) )

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

কারখানা পদ্ধতি

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

ক্লাস ফ্যাক্টরি ( পাবলিক ফাংশন getGoogleFinder() ( নতুন GoogleFinder($this->getGrabber(), $this->getHtmlExtractor() ফেরত দিন; ) প্রাইভেট ফাংশন getGrabber() ( রিটার্ন নতুন Grabber(); ) প্রাইভেট ফাংশন getHtmlExtractor() ( নতুন HtmlFiletr (); ) ) ফেরত দিন

একটি নিয়ম হিসাবে, কারখানাগুলি তৈরি করা হয় যা এক ধরণের বস্তু তৈরির জন্য দায়ী। কখনও কখনও একটি কারখানা সংশ্লিষ্ট বস্তুর একটি গ্রুপ তৈরি করতে পারে। বস্তুর পুনরায় তৈরি করা এড়াতে আমরা একটি সম্পত্তিতে ক্যাশিং ব্যবহার করতে পারি।

ক্লাস ফ্যাক্টরি ( ব্যক্তিগত $ফাইন্ডার; পাবলিক ফাংশন getGoogleFinder() ( যদি (null === $this->finder) ( $this->finder = new GoogleFinder($this->getGrabber(), $this->getHtmlExtractor() ); ) $this->ফাইন্ডার ফেরত দিন; ) )

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

ক্লাস কন্ট্রোলার ( ব্যক্তিগত $ফ্যাক্টরি; পাবলিক ফাংশন __construct(ফ্যাক্টরি $ফ্যাক্টরি) ( $this->factory = $factory;) পাবলিক ফাংশন অ্যাকশন() ( /* কিছু জিনিস */ $results = $this->factory->getGoogleFinder( --> খুঁজুন("সার্চ স্ট্রিং"); /* ফলাফল সহ কিছু করুন */ ) )

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

পরিষেবা লোকেটার

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

Class ServiceContainer ArrayObject প্রসারিত করে ( পাবলিক ফাংশন get($key) ( if (is_callable($this[$key])) ( return call_user_func($this[$key]); ) নতুন \RuntimeException("এর অধীনে পরিষেবার সংজ্ঞা খুঁজে পাচ্ছি না কী [ $key ]"); ))

তারপর সংজ্ঞা নিবন্ধন এই মত দেখাবে:

$container = নতুন সার্ভিস কনটেইনার(); $container["grabber"] = ফাংশন () ( রিটার্ন নতুন গ্র্যাবার();); $container["html_filter"] = ফাংশন () ( রিটার্ন নতুন HtmlExtractor();); $container["google_finder"] = function() ব্যবহার ($container) ( রিটার্ন নতুন GoogleFinder($container->get("grabber"), $container->get("html_filter")););

এবং কন্ট্রোলারের ব্যবহার এইরকম:

ক্লাস কন্ট্রোলার ( প্রাইভেট $কন্টেইনার; পাবলিক ফাংশন __construct(ServiceContainer $container) ( $this->container = $container; ) পাবলিক ফাংশন অ্যাকশন() ( /* কিছু জিনিস */ $results = $this->container->get( "google_finder")->find("সার্চ স্ট্রিং"); /* ফলাফল সহ কিছু করুন */ ) )

একটি পরিষেবা ধারক খুব সহজ হতে পারে, বা এটি খুব জটিল হতে পারে। উদাহরণস্বরূপ, সিমফনি পরিষেবা কন্টেইনার অনেকগুলি বৈশিষ্ট্য সরবরাহ করে: পরামিতি, পরিষেবাগুলির সুযোগ, ট্যাগ, উপনাম, ব্যক্তিগত পরিষেবাগুলির দ্বারা পরিষেবাগুলির জন্য অনুসন্ধান, সমস্ত পরিষেবা (কম্পিলার পাস) যোগ করার পরে কন্টেইনারে পরিবর্তন করার ক্ষমতা এবং আরও অনেক কিছু। DIExtraBundle স্ট্যান্ডার্ড বাস্তবায়নের ক্ষমতা আরও প্রসারিত করে।
কিন্তু এর আমাদের উদাহরণ ফিরে আসা যাক. আপনি দেখতে পাচ্ছেন, সার্ভিস লোকেটার শুধুমাত্র পূর্ববর্তী টেমপ্লেটগুলির মতো একই সমস্যার সমাধান করে না, তবে তাদের নিজস্ব পরিষেবা সংজ্ঞা সহ মডিউলগুলি ব্যবহার করাও সহজ করে তোলে।
উপরন্তু, কাঠামো স্তরে আমরা বিমূর্ততা একটি অতিরিক্ত স্তর পেয়েছি. যথা, ServiceContainer::get পদ্ধতি পরিবর্তন করে আমরা, উদাহরণস্বরূপ, বস্তুটিকে একটি প্রক্সি দিয়ে প্রতিস্থাপন করতে পারি। এবং প্রক্সি অবজেক্টের প্রয়োগের সুযোগ শুধুমাত্র বিকাশকারীর কল্পনা দ্বারা সীমাবদ্ধ। এখানে আপনি AOP প্যারাডাইম, LazyLoading, ইত্যাদি বাস্তবায়ন করতে পারেন।
তবে বেশিরভাগ বিকাশকারীরা এখনও পরিষেবা লোকেটারকে একটি অ্যান্টি-প্যাটার্ন হিসাবে বিবেচনা করে। কারণ, তাত্ত্বিকভাবে, আমরা যতগুলি তথাকথিত থাকতে পারি ধারক সচেতন ক্লাস (অর্থাৎ কন্টেইনারের রেফারেন্স ধারণ করে এমন ক্লাস)। উদাহরণস্বরূপ, আমাদের কন্ট্রোলার, যার ভিতরে আমরা যে কোনও পরিষেবা পেতে পারি।
দেখা যাক কেন এটা খারাপ।
প্রথমত, আবার পরীক্ষা। শুধুমাত্র পরীক্ষায় ব্যবহৃত ক্লাসের জন্য উপহাস তৈরি করার পরিবর্তে, আপনাকে পুরো ধারকটিকে উপহাস করতে হবে বা একটি বাস্তব ধারক ব্যবহার করতে হবে। প্রথম বিকল্পটি আপনার জন্য উপযুক্ত নয়, কারণ ... আপনাকে পরীক্ষায় প্রচুর অপ্রয়োজনীয় কোড লিখতে হবে, দ্বিতীয়ত, কারণ এটি ইউনিট পরীক্ষার নীতির সাথে সাংঘর্ষিক, এবং পরীক্ষা বজায় রাখার জন্য অতিরিক্ত খরচ হতে পারে।
দ্বিতীয়ত, রিফ্যাক্টর করা আমাদের জন্য কঠিন হবে। কন্টেইনারে যেকোনো পরিষেবা (বা পরিষেবার সংজ্ঞা) পরিবর্তন করে, আমরা সমস্ত নির্ভরশীল পরিষেবাগুলিও পরীক্ষা করতে বাধ্য হব৷ এবং এই সমস্যা একটি IDE সাহায্যে সমাধান করা যাবে না. অ্যাপ্লিকেশন জুড়ে এই ধরনের জায়গা খুঁজে পাওয়া এত সহজ হবে না। নির্ভরশীল পরিষেবাগুলি ছাড়াও, আপনাকে সেই সমস্ত জায়গাগুলিও পরীক্ষা করতে হবে যেখানে কন্টেইনার থেকে রিফ্যাক্টর পরিষেবা পাওয়া যায়।
ঠিক আছে, তৃতীয় কারণটি হল যে কনটেইনার থেকে পরিষেবাগুলির অনিয়ন্ত্রিত টানা শীঘ্রই বা পরে কোডে গণ্ডগোল এবং অপ্রয়োজনীয় বিভ্রান্তির দিকে নিয়ে যাবে। এটি ব্যাখ্যা করা কঠিন, এই বা সেই পরিষেবাটি কীভাবে কাজ করে তা বোঝার জন্য আপনাকে আরও বেশি সময় ব্যয় করতে হবে, অন্য কথায়, আপনি সম্পূর্ণরূপে বুঝতে পারবেন এটি কী করে বা কীভাবে একটি ক্লাস কাজ করে শুধুমাত্র তার পুরো সোর্স কোড পড়ে।

ইনজেকশন নির্ভরতা

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

$container["google_finder"] = function() ব্যবহার ($container) ( রিটার্ন নতুন কন্ট্রোলার(Grabber $grabber););

এবং কন্ট্রোলারে ধারক থেকে পরিত্রাণ পান:

ক্লাস কন্ট্রোলার ( ব্যক্তিগত $ফাইন্ডার; পাবলিক ফাংশন __কনস্ট্রাকট(গুগলফাইন্ডার $ফাইন্ডার) ( $this->ফাইন্ডার = $ফাইন্ডার;) পাবলিক ফাংশন অ্যাকশন() ( /* কিছু জিনিস */ $results = $this->finder->find( "অনুসন্ধান স্ট্রিং"); /* ফলাফল সহ কিছু করুন */ ) )

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

উপসংহার

ঠিক আছে, সময় এসেছে যা বলা হয়েছে সব কিছুর যোগফল দেওয়ার। এবং অনেক কিছু বলা হয়েছে... :)
সুতরাং, বস্তু তৈরির কাজ গঠন করতে, আমরা নিম্নলিখিত নিদর্শনগুলি ব্যবহার করতে পারি:
  • রেজিস্ট্রি: টেমপ্লেটটির সুস্পষ্ট অসুবিধা রয়েছে, যার মধ্যে সবচেয়ে মৌলিক হল বস্তুগুলিকে একটি সাধারণ পাত্রে রাখার আগে তৈরি করা। স্পষ্টতই, আমরা এটি ব্যবহার করে সুবিধার চেয়ে বেশি সমস্যা পাব। এটি স্পষ্টতই টেমপ্লেটের সর্বোত্তম ব্যবহার নয়।
  • কারখানা পদ্ধতি: প্যাটার্নের প্রধান সুবিধা: বস্তুগুলি স্পষ্টভাবে তৈরি করা হয়। প্রধান অসুবিধা: নিয়ন্ত্রকদের হয় নিজেরাই কারখানা তৈরি করার বিষয়ে চিন্তা করতে হবে, যা ক্লাসের নাম হার্ডকোড হওয়ার সমস্যার সম্পূর্ণ সমাধান করে না, বা কাঠামোটি অবশ্যই সমস্ত প্রয়োজনীয় কারখানাগুলির সাথে কন্ট্রোলার সরবরাহ করার জন্য দায়ী হতে হবে, যা এতটা স্পষ্ট হবে না। বস্তু তৈরির প্রক্রিয়া কেন্দ্রীয়ভাবে পরিচালনা করার কোন সম্ভাবনা নেই।
  • পরিষেবা লোকেটার: বস্তুর সৃষ্টি নিয়ন্ত্রণ করার একটি আরো উন্নত উপায়। অবজেক্ট তৈরি করার সময় মুখোমুখি হওয়া সাধারণ কাজগুলিকে স্বয়ংক্রিয় করতে বিমূর্ততার একটি অতিরিক্ত স্তর ব্যবহার করা যেতে পারে। উদাহরণ স্বরূপ:
    ক্লাস সার্ভিস কনটেইনার ArrayObject প্রসারিত করে ( পাবলিক ফাংশন get($key) ( if (is_callable($this[$key])) ( $obj = call_user_func($this[$key]); যদি ($obj instance of RequestAwareInterface) ( $obj- >setRequest($this->get("request")); ) $obj ফেরত দিন; ) নতুন \RuntimeException("কী [ $key ]" এর অধীনে পরিষেবার সংজ্ঞা খুঁজে পাচ্ছি না); ))
    সার্ভিস লোকেটারের অসুবিধা হল ক্লাসের পাবলিক API তথ্যপূর্ণ হওয়া বন্ধ করে দেয়। এটিতে কী কী পরিষেবা ব্যবহার করা হয়েছে তা বোঝার জন্য ক্লাসের সম্পূর্ণ কোডটি পড়তে হবে। একটি শ্রেণী যা একটি পাত্রের একটি রেফারেন্স ধারণ করে পরীক্ষা করা আরও কঠিন।
  • ইনজেকশন নির্ভরতা: অগত্যা আমরা আগের প্যাটার্নের মতো একই পরিষেবা ধারক ব্যবহার করতে পারি। পার্থক্য হল এই ধারকটি কীভাবে ব্যবহার করা হয়। যদি আমরা কন্টেইনারের উপর নির্ভরশীল ক্লাস করা এড়াই, আমরা একটি পরিষ্কার এবং স্পষ্ট ক্লাস API পাব।
পিএইচপি অ্যাপ্লিকেশনগুলিতে অবজেক্ট তৈরির সমস্যা সম্পর্কে আমি আপনাকে বলতে চাই না। প্রোটোটাইপ প্যাটার্নও রয়েছে, আমরা প্রতিফলন API ব্যবহার বিবেচনা করিনি, আমরা পরিষেবাগুলির অলস লোডিংয়ের সমস্যা এবং অন্যান্য অনেক সূক্ষ্মতাকে একপাশে রেখেছি। নিবন্ধটি বেশ দীর্ঘ হয়ে উঠেছে, তাই আমি এটি গুটিয়ে নেব :)
আমি দেখাতে চেয়েছিলাম যে ডিপেনডেন্সি ইনজেকশন এবং অন্যান্য প্যাটার্নগুলি ততটা জটিল নয় যতটা সাধারণভাবে বিশ্বাস করা হয়।
আমরা যদি নির্ভরতা ইনজেকশন সম্পর্কে কথা বলি, তাহলে এই প্যাটার্নের KISS বাস্তবায়ন আছে, উদাহরণস্বরূপ

ভবিষ্যত ডাটাবেসের কাঠামোর উপর স্পর্শ করা। একটি শুরু করা হয়েছে, এবং আমরা পিছু হটতে পারি না, এবং আমি এটি সম্পর্কে চিন্তাও করি না।

আমরা একটু পরে ডাটাবেসে ফিরে আসব, তবে আপাতত আমরা আমাদের ইঞ্জিনের জন্য কোড লেখা শুরু করব। কিন্তু প্রথম, হার্ডওয়্যার একটি সামান্য বিট. শুরু করুন।

প্রথমে

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

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

নকশা নিদর্শন

এটি কী এবং কী কী জাত রয়েছে সে সম্পর্কে প্রচুর নিবন্ধ রয়েছে; বিষয়টি বেশ হ্যাকনিড এবং আমি আপনাকে নতুন কিছু বলব না। আমার প্রিয় উইকিতে এই বিষয়ে তথ্য রয়েছে: একটি স্লাইড সহ একটি গাড়ি এবং আরও কিছু।

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

সমস্ত ধরণের ভীতিকর (এবং এত ভীতিকর নয়) প্যাটার্ন নামের বিশাল তালিকা থেকে, আমরা এখন পর্যন্ত শুধুমাত্র দুটিতে আগ্রহী: রেজিস্ট্রি এবং সিঙ্গলটন।

রেজিস্ট্রি (অথবা নিবন্ধন করুন) হল একটি প্যাটার্ন যা একটি নির্দিষ্ট অ্যারেতে কাজ করে যেখানে আপনি একটি নির্দিষ্ট সেট অবজেক্ট যোগ করতে এবং অপসারণ করতে পারেন এবং সেগুলির যেকোনো একটি এবং এর ক্ষমতাগুলিতে অ্যাক্সেস পেতে পারেন।

একাকী (বা সিঙ্গলটন) একটি প্যাটার্ন যা নিশ্চিত করে যে একটি ক্লাসের শুধুমাত্র একটি উদাহরণ বিদ্যমান থাকতে পারে। এটি অনুলিপি করা যাবে না, ঘুমোতে বা জাগ্রত করা যাবে না (PHP ম্যাজিক সম্পর্কে কথা বলা: __clone(), __sleep(), __wakeup())। সিঙ্গেলটনের একটি বিশ্বব্যাপী অ্যাক্সেস পয়েন্ট রয়েছে।

সংজ্ঞাগুলি সম্পূর্ণ বা সাধারণীকৃত নয়, তবে এটি বোঝার জন্য যথেষ্ট। যাইহোক আমাদের আলাদাভাবে তাদের দরকার নেই। আমরা এই নিদর্শন প্রতিটি ক্ষমতা আগ্রহী, কিন্তু একটি শ্রেণীতে: যেমন একটি প্যাটার্ন বলা হয় সিঙ্গেলটন রেজিস্ট্রি বা সিঙ্গেলটন রেজিস্ট্রি।

এটা আমাদের কি দেবে?
  • আমরা নিশ্চিত হব যে রেজিস্ট্রির একটি একক দৃষ্টান্ত থাকবে, যাতে আমরা যেকোন সময় বস্তু যোগ করতে পারি এবং কোডের যেকোনো জায়গা থেকে সেগুলি ব্যবহার করতে পারি;
  • এটি অনুলিপি করা এবং পিএইচপি ভাষার অন্যান্য অবাঞ্ছিত (এই ক্ষেত্রে) জাদু ব্যবহার করা অসম্ভব হবে।

এই পর্যায়ে, এটি বোঝার জন্য এটি যথেষ্ট যে একটি একক রেজিস্ট্রি আমাদের সিস্টেমের একটি মডুলার কাঠামো বাস্তবায়নের অনুমতি দেবে, যেটি আমরা লক্ষ্যগুলি নিয়ে আলোচনা করার সময় চেয়েছিলাম, এবং আপনি বিকাশের অগ্রগতির সাথে সাথে বাকিটি বুঝতে পারবেন।

ওয়েল, যথেষ্ট শব্দ, এর তৈরি করা যাক!

প্রথম লাইন

যেহেতু এই ক্লাসটি কার্নেলের কার্যকারিতার সাথে সম্পর্কিত, তাই আমরা আমাদের প্রোজেক্টের রুটে একটি ফোল্ডার তৈরি করে শুরু করব যার নাম core যেখানে আমরা কার্নেল মডিউলের সমস্ত ক্লাস রাখব। আমরা রেজিস্ট্রি দিয়ে শুরু করি, তাই registry.php ফাইলটিকে কল করি

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

যেহেতু আমরা সংযুক্ত এমন কিছুকে রক্ষা করছি, আমরা ধ্রুবককে কল করব _PLUGSECURE_ :

যদি (!সংজ্ঞায়িত("_PLUGSECURE_")) ( die("ডাইরেক্ট মডিউল কল নিষিদ্ধ!");)

এখন, আপনি যদি এই ফাইলটি সরাসরি অ্যাক্সেস করার চেষ্টা করেন, তাহলে দরকারী কিছুই বের হবে না, যার অর্থ লক্ষ্য অর্জন করা হয়েছে।

এর পরে, আমি আমাদের সমস্ত মডিউলের জন্য একটি নির্দিষ্ট মান নির্ধারণ করার প্রস্তাব করছি। আমি প্রতিটি মডিউলকে একটি ফাংশন প্রদান করতে চাই যা এটি সম্পর্কে কিছু তথ্য প্রদান করবে, যেমন মডিউলের নাম, এবং এই ফাংশনটি অবশ্যই ক্লাসে আবশ্যক। এই লক্ষ্য অর্জনের জন্য আমরা নিম্নলিখিতগুলি লিখি:

ইন্টারফেস স্টোরেবল অবজেক্ট (পাবলিক স্ট্যাটিক ফাংশন getClassName();)

এটার মত. এখন, যদি আমরা একটি ফাংশন ছাড়া কোনো ক্লাস সংযোগ getClassName()আমরা একটি ত্রুটি বার্তা দেখতে পাব। আমি আপাতত এটিতে ফোকাস করব না, এটি অন্তত পরীক্ষা এবং ডিবাগ করার জন্য পরে আমাদের জন্য উপযোগী হবে।

এটা আমাদের একক রেজিস্ট্রি নিজেই ক্লাস জন্য সময়. আমরা ক্লাস এবং এর কিছু ভেরিয়েবল ঘোষণা করে শুরু করব:

ক্লাস রেজিস্ট্রি StorableObject প্রয়োগ করে ( //মডিউল নাম, পঠনযোগ্য প্রাইভেট স্ট্যাটিক $className = "রেজিস্ট্রি"; //রেজিস্ট্রি ইনস্ট্যান্স প্রাইভেট স্ট্যাটিক $ইনস্ট্যান্স; //অবজেক্টের অ্যারে প্রাইভেট স্ট্যাটিক $objects = অ্যারে();

এখন পর্যন্ত সবকিছু যৌক্তিক এবং বোধগম্য। এখন, আপনার মনে আছে, আমাদের সিঙ্গলটন বৈশিষ্ট্য সহ একটি রেজিস্ট্রি রয়েছে, তাই আসুন অবিলম্বে একটি ফাংশন লিখি যা আমাদের এইভাবে রেজিস্ট্রির সাথে কাজ করতে দেয়:

পাবলিক স্ট্যাটিক ফাংশন singleton() ( if(!isset(self::$instance)) ( $obj = __CLASS__; self::$instance = new $obj; ) return self::$instance; )

আক্ষরিক অর্থে: ফাংশনটি আমাদের রেজিস্ট্রির একটি উদাহরণ বিদ্যমান কিনা তা পরীক্ষা করে: যদি না হয় তবে এটি এটি তৈরি করে এবং ফেরত দেয়; যদি এটি ইতিমধ্যেই বিদ্যমান থাকে তবে এটি কেবল এটি ফেরত দেয়। এই ক্ষেত্রে, আমাদের কিছু যাদু প্রয়োজন নেই, তাই সুরক্ষার জন্য আমরা এটিকে ব্যক্তিগত ঘোষণা করব:

ব্যক্তিগত ফাংশন __construct()() ব্যক্তিগত ফাংশন __clone()() ব্যক্তিগত ফাংশন __wakeup()() ব্যক্তিগত ফাংশন __sleep() ()

এখন আমাদের রেজিস্ট্রিতে একটি বস্তু যোগ করার জন্য আমাদের একটি ফাংশন প্রয়োজন - এই ফাংশনটিকে একটি সেটার বলা হয় এবং আমি কীভাবে যাদু ব্যবহার করতে পারি এবং একটি বস্তু যুক্ত করার বিকল্প উপায় প্রদান করতে পারি তা দেখানোর জন্য আমি এটি দুটি উপায়ে বাস্তবায়ন করার সিদ্ধান্ত নিয়েছি। প্রথম পদ্ধতিটি একটি আদর্শ ফাংশন, দ্বিতীয়টি __set() এর ম্যাজিকের মাধ্যমে প্রথমটি কার্যকর করে।

//$অবজেক্ট - সংযুক্ত অবজেক্টের পথ //$কী - রেজিস্টার পাবলিক ফাংশনে অবজেক্টের অ্যাক্সেস কী অ্যাডঅবজেক্ট($কী, $অবজেক্ট) ( প্রয়োজন_একটি ($অবজেক্ট); //অবজেক্টের অ্যারেতে একটি অবজেক্ট তৈরি করুন self::$objects[ $key] = new $key(self::$instance); ) //যাদু পাবলিক ফাংশনের মাধ্যমে একটি বিকল্প পদ্ধতি __set($key, $object) ( $this->addObject($key, $ বস্তু;)

এখন, আমাদের রেজিস্ট্রিতে একটি বস্তু যোগ করার জন্য, আমরা দুই ধরনের এন্ট্রি ব্যবহার করতে পারি (আসুন আমরা ইতিমধ্যে একটি রেজিস্ট্রি ইনস্ট্যান্স $registry তৈরি করেছি এবং আমরা config.php ফাইলটি যোগ করতে চাই):

$registry->addObject("config", "/core/config.php"); //নিয়মিত পদ্ধতি $registry->config = "/core/config.php"; // PHP ম্যাজিক ফাংশনের মাধ্যমে __set()

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

কোন রেকর্ডিং ব্যবহার করবেন তা আপনার উপর নির্ভর করে। আমি যাদু পদ্ধতির মাধ্যমে রেকর্ডিং পছন্দ করি - এটি "সুন্দর" এবং ছোট।

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

//অবজেক্টটি রেজিস্টার থেকে পান //$key - অ্যারের পাবলিক ফাংশনের কী getObject($key) ( //ভেরিয়েবলটি একটি অবজেক্ট কিনা তা পরীক্ষা করুন যদি (is_object(self::$objects[$key])) ( //যদি তাই হয়, তাহলে আমরা এই অবজেক্টটি রিটার্ন করি self::$objects[$key]; ) ) //একটি অনুরূপ পদ্ধতি ম্যাজিক পাবলিক ফাংশনের মাধ্যমে __get($key) ( if (is_object(self::$objects[$) কী])) (আত্ম ফেরত: :$বস্তু[$কী]; ))

সেটারের মতো, বস্তুটিতে অ্যাক্সেস পেতে আমাদের 2টি সমতুল্য এন্ট্রি থাকবে:

$registry->getObject("config"); //নিয়মিত পদ্ধতি $registry->config; // PHP ম্যাজিক ফাংশনের মাধ্যমে __get()

মনোযোগী পাঠক অবিলম্বে প্রশ্ন জিজ্ঞাসা করবে: কেন __set() ম্যাজিক ফাংশনে আমি শুধু একটি নিয়মিত (নন-ম্যাজিক) অবজেক্ট যোগ করার ফাংশন কল করি, কিন্তু __get() গেটারে আমি একই কলের পরিবর্তে getObject() ফাংশন কোড কপি করি?সত্যি বলতে, আমি এই প্রশ্নের সঠিক উত্তর দিতে পারি না, আমি শুধু বলব যে অন্য মডিউলগুলিতে __get() ম্যাজিকের সাথে কাজ করার সময় আমার সমস্যা হয়েছিল, কিন্তু "হেড-অন" কোডটি পুনরায় লেখার সময় এই ধরনের কোনও সমস্যা নেই।

হয়তো তাই আমি প্রায়শই নিবন্ধগুলিতে পিএইচপি জাদু পদ্ধতির প্রতি নিন্দা এবং সেগুলি ব্যবহার এড়াতে পরামর্শ দেখেছি।

"সমস্ত জাদু একটি মূল্য সঙ্গে আসে।" © Rumplestiltskin

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

$registry = Registry::singleton();

আমরা একটি ত্রুটি পেতে হবে:

মারাত্মক ত্রুটি: ক্লাস রেজিস্ট্রিতে 1টি বিমূর্ত পদ্ধতি রয়েছে এবং তাই অবশ্যই বিমূর্ত ঘোষণা করতে হবে বা অবশিষ্ট পদ্ধতিগুলি (StorableObject::getClassName) প্রয়োগ করতে হবে ...

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

পাবলিক স্ট্যাটিক ফাংশন getClassName() (রিটার্ন self::$className;)

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

পাবলিক ফাংশন getObjectsList() ( // যে অ্যারে আমরা $names = array() ফেরত দেব; // অবজেক্টের অ্যারে থেকে প্রতিটি অবজেক্টের নাম পাবেন foreach(self::$objects as $obj) ( $names = $ obj->getClassName() ; ) // রেজিস্টার মডিউলের নাম অ্যারে array_push($names, self::getClassName()) এ যোগ করুন; //এবং ফেরত $names;)

এখানেই শেষ. এটি রেজিস্টার সম্পূর্ণ করে। তার কাজ পরীক্ষা করা যাক? চেক করার সময়, আমাদের কিছু সংযোগ করতে হবে - একটি কনফিগারেশন ফাইল থাকতে দিন। একটি নতুন core/config.php ফাইল তৈরি করুন এবং আমাদের রেজিস্ট্রির জন্য প্রয়োজনীয় ন্যূনতম সামগ্রী যোগ করুন:

// ধ্রুবক চেক করতে ভুলবেন না যদি (! defined("_PLUGSECURE_")) ( die("ডাইরেক্ট মডিউল কল নিষিদ্ধ!"); ) ক্লাস কনফিগ ( //মডিউল নাম, পঠনযোগ্য প্রাইভেট স্ট্যাটিক $className = "কনফিগ "; পাবলিক স্ট্যাটিক ফাংশন getClassName() (রিটার্ন self::$className; ) )

এরকম কিছু. এখন আসুন যাচাইকরণে এগিয়ে যাই। আমাদের প্রজেক্টের রুটে একটি index.php ফাইল তৈরি করুন এবং এতে নিম্নলিখিত কোডটি লিখুন:

সংজ্ঞায়িত করুন("_PLUGSECURE_", সত্য); //অবজেক্টের সরাসরি অ্যাক্সেস থেকে রক্ষা করার জন্য একটি ধ্রুবক সংজ্ঞায়িত করা হয়েছে need_once "/core/registry.php"; //রেজিস্টার $registry = Registry::singleton(); // একটি রেজিস্টার সিঙ্গলটন ইনস্ট্যান্স $registry->config = "/core/config.php" তৈরি করেছে; //আমাদের সংযোগ করুন, এখন পর্যন্ত অকেজো, কনফিগারেশন //সংযুক্ত মডিউলগুলির নামগুলি ইকো প্রদর্শন করুন " সংযুক্ত"; foreach ($registry->

  • " $names "
  • "; }

    অথবা, আপনি যদি এখনও জাদু এড়ান, তাহলে 5 তম লাইনটি একটি বিকল্প পদ্ধতিতে প্রতিস্থাপিত করা যেতে পারে:

    সংজ্ঞায়িত করুন("_PLUGSECURE_", সত্য); //অবজেক্টের সরাসরি অ্যাক্সেস থেকে রক্ষা করার জন্য একটি ধ্রুবক সংজ্ঞায়িত করা হয়েছে need_once "/core/registry.php"; //রেজিস্টার $registry = Registry::singleton(); // একটি রেজিস্টার সিঙ্গলটন ইনস্ট্যান্স $registry->addObject("config", "/core/config.php") তৈরি করেছেন; //আমাদের সংযোগ করুন, এখন পর্যন্ত অকেজো, কনফিগারেশন //সংযুক্ত মডিউলগুলির নামগুলি ইকো প্রদর্শন করুন " সংযুক্ত"; foreach ($registry->getObjectsList() $names হিসাবে) ( echo "

  • " $names "
  • "; }

    এখন ব্রাউজার খুলুন এবং ঠিকানা বারে http://localhost/index.php বা সহজভাবে http://localhost/ লিখুন (আপনি স্ট্যান্ডার্ড ওপেন সার্ভার বা অনুরূপ ওয়েব সার্ভার সেটিংস ব্যবহার করলে প্রাসঙ্গিক)

    ফলস্বরূপ, আমাদের এইরকম কিছু দেখতে হবে:

    আপনি দেখতে পাচ্ছেন, কোনও ত্রুটি নেই, যার অর্থ সবকিছু কাজ করে, যার জন্য আমি আপনাকে অভিনন্দন জানাই :)

    আজ আমরা এখানে থামব। পরবর্তী নিবন্ধে, আমরা ডাটাবেসে ফিরে আসব এবং MySQL SUDB এর সাথে কাজ করার জন্য একটি ক্লাস লিখব, এটিকে রেজিস্ট্রির সাথে সংযুক্ত করব এবং অনুশীলনে কাজটি পরীক্ষা করব। দেখা হবে!

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

    ক্রমানুসারে উভয় বিকল্প বিবেচনা করা যাক।

    একটি "বিশুদ্ধ রেজিস্ট্রি" বা সহজভাবে রেজিস্ট্রি বলা হয় একটি স্ট্যাটিক ইন্টারফেস সহ একটি ক্লাসের বাস্তবায়ন। সিঙ্গেলটন প্যাটার্ন থেকে প্রধান পার্থক্য হল এটি একটি ক্লাসের অন্তত একটি উদাহরণ তৈরি করার ক্ষমতাকে ব্লক করে। এই বিবেচনায়, প্রাইভেট বা সুরক্ষিত মডিফায়ারের পিছনে ম্যাজিক পদ্ধতি __clone() এবং __wakeup() লুকিয়ে রাখার কোন মানে নেই।

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

    রেজিস্ট্রির উপর সম্পূর্ণ নিয়ন্ত্রণের জন্য, আরেকটি ইন্টারফেস উপাদান চালু করা হয়েছে - একটি পদ্ধতি যা আপনাকে স্টোরেজ থেকে একটি বস্তু মুছে ফেলতে দেয়।

    সিঙ্গেলটন প্যাটার্নের অনুরূপ সমস্যাগুলি ছাড়াও, আরও দুটি রয়েছে:

    • অন্য ধরনের নির্ভরতা প্রবর্তন - রেজিস্ট্রি কীগুলিতে;
    • দুটি ভিন্ন রেজিস্ট্রি কী একই বস্তুর একটি রেফারেন্স থাকতে পারে

    প্রথম ক্ষেত্রে, অতিরিক্ত নির্ভরতা এড়ানো অসম্ভব। কিছু পরিমাণে, আমরা কী নামের সাথে সংযুক্ত হয়ে যাই।

    দ্বিতীয় সমস্যাটি রেজিস্ট্রি::সেট() পদ্ধতিতে একটি চেক প্রবর্তন করে সমাধান করা হয়েছে:

    পাবলিক স্ট্যাটিক ফাংশন সেট($key, $item) ( যদি (!array_key_exists($key, self::$_registry)) ( foreach (self::$_registry $val হিসাবে) ( if ($val === $item) ( নতুন ব্যতিক্রম নিক্ষেপ ("আইটেম ইতিমধ্যেই বিদ্যমান"); ) ) self::$_registry[$key] = $item; ) )

    « রেজিস্ট্রি প্যাটার্ন পরিষ্কার করুন"আরেকটি সমস্যার জন্ম দেয় - ক্লাসের নামের মাধ্যমে সেটার এবং গেটার অ্যাক্সেস করার প্রয়োজনের কারণে নির্ভরতা বৃদ্ধি করে। আপনি একটি বস্তুর একটি রেফারেন্স তৈরি করতে এবং এটির সাথে কাজ করতে পারবেন না, যেমনটি সিঙ্গেলটন প্যাটার্নের ক্ষেত্রে ছিল, যখন এই পদ্ধতিটি উপলব্ধ ছিল:

    $instance = Singleton::getInstance(); $instance->Foo();

    এখানে আমাদের কাছে একটি সিঙ্গেলটন উদাহরণের একটি রেফারেন্স সংরক্ষণ করার সুযোগ আছে, উদাহরণস্বরূপ, বর্তমান শ্রেণীর একটি সম্পত্তিতে, এবং এটির সাথে OOP মতাদর্শের প্রয়োজন অনুসারে কাজ করুন: এটিকে একত্রিত বস্তুতে প্যারামিটার হিসাবে পাস করুন বা বংশধরে এটি ব্যবহার করুন৷

    এই সমস্যা সমাধানের জন্য আছে সিঙ্গেলটন রেজিস্ট্রি বাস্তবায়ন, যা অনেক লোক পছন্দ করে না কারণ এটি অপ্রয়োজনীয় কোড বলে মনে হয়। আমি মনে করি এই মনোভাবের কারণ হল OOP-এর নীতিগুলির কিছু ভুল বোঝাবুঝি বা তাদের জন্য ইচ্ছাকৃত অবজ্ঞা।

    _registry[$key] = $object; ) স্থির পাবলিক ফাংশন get($key) ( return self::getInstance()->_registry[$key]; ) প্রাইভেট ফাংশন __wakeup() ( ) প্রাইভেট ফাংশন __construct() () প্রাইভেট ফাংশন __clone() () ) ?>

    অর্থ বাঁচাতে, আমি ইচ্ছাকৃতভাবে পদ্ধতি এবং বৈশিষ্ট্যগুলির জন্য মন্তব্য ব্লকগুলি বাদ দিয়েছি। আমি তাদের প্রয়োজন মনে করি না.

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

    আমি আমাদের জীবনে প্রায়ই ব্যবহৃত নিদর্শন সম্পর্কে সংক্ষিপ্তভাবে লেখার সিদ্ধান্ত নিয়েছি, আরও উদাহরণ, কম জল, চলুন।

    সিঙ্গেলটন

    "একক" এর মূল বিষয় হল যে আপনি যখন বলবেন "আমার একটি টেলিফোন এক্সচেঞ্জ দরকার" তখন তারা আপনাকে বলবে "এটি ইতিমধ্যে সেখানে তৈরি করা হয়েছে," এবং "আসুন এটি আবার তৈরি করি।" একজন "একাকী" সবসময় একা থাকে।

    ক্লাস সিঙ্গেলটন ( প্রাইভেট স্ট্যাটিক $ইনস্ট্যান্স = নাল; ব্যক্তিগত ফাংশন __construct())( /* ... @return Singleton */ ) // নতুন সিঙ্গেলটন প্রাইভেট ফাংশন __clone() ( /* ... @return Singleton এর মাধ্যমে সৃষ্টির বিরুদ্ধে রক্ষা করুন */ ) // ক্লোনিং প্রাইভেট ফাংশন __wakeup() ( /* ... @return Singleton */ ) // unserialize পাবলিক স্ট্যাটিক ফাংশন getInstance() ( if (is_null(self::$instance) এর মাধ্যমে সৃষ্টির বিরুদ্ধে রক্ষা করুন ) ) ( self::$instance = new self; ) return self::$instance; ) )

    রেজিস্ট্রি (রেজিস্ট্রি, জার্নাল অফ এন্ট্রি)

    নাম অনুসারে, এই প্যাটার্নটি রেকর্ডগুলি সংরক্ষণ করার জন্য ডিজাইন করা হয়েছে যা এটিতে রাখা হয়েছে এবং সেই অনুযায়ী, যদি প্রয়োজন হয় তবে এই রেকর্ডগুলি (নাম অনুসারে) ফিরিয়ে দিন৷ একটি টেলিফোন এক্সচেঞ্জের উদাহরণে, এটি বাসিন্দাদের টেলিফোন নম্বর সম্পর্কিত একটি রেজিস্টার।

    ক্লাস রেজিস্ট্রি ( ব্যক্তিগত $রেজিস্ট্রি = অ্যারে(); পাবলিক ফাংশন সেট($কী, $অবজেক্ট) ( $this->রেজিস্ট্রি[$key] = $object; ) পাবলিক ফাংশন get($key) ( $this->registry ফেরত দিন [$কী];))

    সিঙ্গেলটন রেজিস্ট্রি- এর সাথে বিভ্রান্ত করবেন না)

    "রেজিস্ট্রি" প্রায়শই একটি "একাকী" হয় তবে এটি সর্বদা সেভাবে হতে হবে না। উদাহরণস্বরূপ, আমরা অ্যাকাউন্টিং বিভাগে বেশ কয়েকটি জার্নাল তৈরি করতে পারি, একটিতে "A" থেকে "M" পর্যন্ত কর্মচারী রয়েছে, অন্যটিতে "N" থেকে "Z" পর্যন্ত। এই জাতীয় প্রতিটি জার্নাল একটি "রেজিস্ট্রি" হবে, তবে একটি "একক" নয়, কারণ ইতিমধ্যে 2টি জার্নাল রয়েছে৷

    ক্লাস সিঙ্গেলটনরেজিস্ট্রি ( প্রাইভেট স্ট্যাটিক $ইনস্ট্যান্স = নাল; প্রাইভেট $রেজিস্ট্রি = অ্যারে(); প্রাইভেট ফাংশন __কনস্ট্রাক্ট() ( /* ... @রিটার্ন সিঙ্গেলটন */ ) // নতুন সিঙ্গেলটন প্রাইভেট ফাংশন __ক্লোন() (//এর মাধ্যমে সৃষ্টি থেকে রক্ষা করুন * ... @return Singleton */ ) // প্রাইভেট ফাংশন ক্লোনিংয়ের মাধ্যমে সৃষ্টির বিরুদ্ধে রক্ষা করুন __wakeup() ( /* ... @return Singleton */ ) // পাবলিক স্ট্যাটিক ফাংশন getInstance() (যদি ( is_null(self::$instance)) ( self::$instance = new self; ) return self::$instance; ) পাবলিক ফাংশন সেট($key, $object) ( $this->registry[$key] = $ অবজেক্ট; ) পাবলিক ফাংশন get($key) ( $this->registry[$key]; ) )

    মাল্টিটন ("একক" এর পুল) বা অন্য কথায়রেজিস্ট্রি সিঙ্গেলটন ) - সিঙ্গেলটন রেজিস্ট্রির সাথে বিভ্রান্ত করবেন না

    প্রায়শই "রেজিস্টার" বিশেষভাবে "একক" সংরক্ষণ করতে ব্যবহৃত হয়। কিন্তু যেহেতু "রেজিস্ট্রি" প্যাটার্নটি একটি "জেনারেটিভ প্যাটার্ন" নয়, তবে আমি "সিঙ্গেলটন" এর সাথে সম্পর্কিত "রেজিস্টার" বিবেচনা করতে চাই।এজন্য আমরা একটি প্যাটার্ন নিয়ে এসেছি মাল্টিটন, যা অনুযায়ীএর মূল অংশে, এটি একটি "রেজিস্ট্রি" যাতে বেশ কয়েকটি "সিঙ্গেল" রয়েছে, যার প্রত্যেকটির নিজস্ব "নাম" রয়েছে যার মাধ্যমে এটি অ্যাক্সেস করা যেতে পারে।

    সংক্ষিপ্ত: আপনি এই শ্রেণীর অবজেক্ট তৈরি করতে পারবেন, কিন্তু শুধুমাত্র যদি আপনি বস্তুর নাম দেন। কোন বাস্তব জীবনের উদাহরণ নেই, কিন্তু আমি ইন্টারনেটে নিম্নলিখিত উদাহরণ খুঁজে পেয়েছি:

    ক্লাস ডেটাবেস ( ব্যক্তিগত স্ট্যাটিক $ইনস্ট্যান্স = অ্যারে(); ব্যক্তিগত ফাংশন __construct() ( ) ব্যক্তিগত ফাংশন __clone() ( ) পাবলিক স্ট্যাটিক ফাংশন getInstance($key) ( if(!array_key_exists($key, self::$instances)) ( self::$instances[$key] = new self(); ) return self::$instances[$key]; ) ) $master = Database::getInstance("master"); var_dump($master); // অবজেক্ট(ডেটাবেস)#1 (0) ( ) $logger = ডেটাবেস::getInstance("logger"); var_dump($logger); // অবজেক্ট(ডেটাবেস)#2 (0) ( ) $masterDupe = ডেটাবেস::getInstance("master"); var_dump($masterDupe); // অবজেক্ট(ডেটাবেস)#1 (0) ( ) // মারাত্মক ত্রুটি: ব্যক্তিগত ডেটাবেসে কল করুন::__construct() অবৈধ প্রসঙ্গ $dbFatalError = নতুন ডেটাবেস(); // PHP মারাত্মক ত্রুটি: ব্যক্তিগত ডেটাবেসে কল করুন::__clone() $dbCloneError = ক্লোন $masterDupe;

    অবজেক্ট পুল

    মূলত এই প্যাটার্ন হয় একটি "রেজিস্ট্রি" যা শুধুমাত্র বস্তু সংরক্ষণ করে, কোন স্ট্রিং, অ্যারে ইত্যাদি। তথ্যের ধরণ.

    কারখানা

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

    অ্যাবস্ট্রাক্ট ক্লাস AnimalAbstract ( সুরক্ষিত $species; পাবলিক ফাংশন getSpecies() ( $this->species; ) ) ক্লাস Cat প্রসারিত করে AnimalAbstract ( protected $species = "cat"; ) ক্লাস Dog AnimalAbstract প্রসারিত করে ( সুরক্ষিত $species = "কুকুর"; ) ক্লাস অ্যানিমালফ্যাক্টরি ( পাবলিক স্ট্যাটিক ফাংশন ফ্যাক্টরি ($প্রাণী) ( সুইচ ($প্রাণী) ( কেস "বিড়াল": $obj = নতুন ক্যাট(); বিরতি; কেস "কুকুর": $obj = নতুন কুকুর(); বিরতি; ডিফল্ট : নতুন ব্যতিক্রম নিক্ষেপ ("প্রাণী কারখানা প্রজাতির প্রাণী তৈরি করতে পারেনি""। $animal। """, 1000); ) $obj ফেরত দিন; ) ) $cat = AnimalFactory::factory("cat"); // বস্তু(বিড়াল)#1 প্রতিধ্বনি $cat->getSpecies(); // cat $dog = Animal Factory::factory("dog"); // বস্তু(কুকুর)#1 ইকো $dog->getSpecies(); // কুকুর $hippo = পশু কারখানা :: কারখানা ("হিপ্পোপটামাস"); // এটি একটি ব্যতিক্রম নিক্ষেপ করবে

    আমি আপনার দৃষ্টি আকর্ষণ করতে চাই যে ফ্যাক্টরি পদ্ধতিটিও একটি প্যাটার্ন; এটিকে ফ্যাক্টরি পদ্ধতি বলা হয়।

    নির্মাতা (নির্মাতা)

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

    ক্লাস বোতল (সর্বজনীন $নাম; পাবলিক $লিটার; ) /** * সকল নির্মাতাকে অবশ্যই */ ইন্টারফেস বোতলবিল্ডার ইন্টারফেস (সর্বজনীন ফাংশন সেটনাম(); পাবলিক ফাংশন সেটলিটারস(); পাবলিক ফাংশন getResult(); ) ক্লাস CocaColaBuilder প্রয়োগ করে BottleBuilderInterface ( ব্যক্তিগত $ বোতল; পাবলিক ফাংশন __কনস্ট্রাক্ট() ( $this->বোতল = নতুন বোতল(); ) পাবলিক ফাংশন সেট নাম($value) ($this->bottle->name = $value; ) পাবলিক ফাংশন সেটলিটারস($value) ($ this->বোতল->লিটার = $value; ) পাবলিক ফাংশন getResult() ( $this->বোতল ফেরত দিন; ) ) $juice = new CocaColaBuilder(); $juice->setName("কোকা-কোলা লাইট"); $juice->setLiters(2); $juice->getResult();

    প্রোটোটাইপ

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

    $newJuice = ক্লোন $juice;

    অলস সূচনা

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

    অ্যাডাপ্টার বা মোড়ক (অ্যাডাপ্টার, মোড়ক)

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

    ক্লাস MyClass ( পাবলিক ফাংশন মেথডএ আপনি $name পদ্ধতিতে কল করতে চলেছেন।"); call_user_func_array(array($this->myClass, $name), $arguments); ) ) $obj = new MyClassWrapper(); $obj->methodA();

    ইনজেকশন নির্ভরতা

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

    ক্লাস AppleJuice () // এই পদ্ধতিটি নির্ভরতা ইনজেকশন প্যাটার্নের একটি আদিম বাস্তবায়ন এবং আরও আপনি এই ফাংশনটি দেখতে পাবেন getBottleJuice())( $obj = new আপেল জুস আপেল জুস)( $obj ফেরত দিন; ) ) $bottleJuice = getBottleJuice();

    এখন কল্পনা করুন যে আমরা আর আপেলের রস চাই না, আমরা কমলার রস চাই।

    ক্লাস AppleJuice() ক্লাস কমলার শরবত() // এই পদ্ধতিটি নির্ভরতা ইনজেকশন ফাংশন প্রয়োগ করে getBottleJuice())( $obj = new কমলার শরবত; // বস্তুটি পরীক্ষা করুন, যদি তারা আমাদের বিয়ার স্লিপ করে (বিয়ার রস নয়) যদি ($obj instanceof) কমলার শরবত)( $obj ফেরত দিন; ) )

    আপনি দেখতে পাচ্ছেন, আমাদের কেবল রসের ধরণই নয়, রসের প্রকারের জন্যও চেক করতে হয়েছিল, যা খুব সুবিধাজনক নয়। নির্ভরতা বিপরীত নীতি ব্যবহার করা অনেক বেশি সঠিক:

    ইন্টারফেস জুস () ক্লাস অ্যাপলজুস জুস প্রয়োগ করে () ক্লাস অরেঞ্জজুস জুস প্রয়োগ করে () ফাংশন getBottleJuice())( $obj = new OrangeJuice; // বস্তুটি পরীক্ষা করুন, যদি তারা আমাদের বিয়ার স্লিপ করে (বিয়ার রস নয়) যদি ($obj) উদাহরণস্বরুপ রস)( $obj ফেরত দিন; ) )

    নির্ভরতা ইনভার্সন কখনও কখনও নির্ভরতা ইনজেকশনের সাথে বিভ্রান্ত হয়, তবে তাদের বিভ্রান্ত করার কোন প্রয়োজন নেই, কারণ নির্ভরতা বিপরীত একটি নীতি, একটি প্যাটার্ন নয়।

    পরিষেবা লোকেটার

    "পরিষেবা লোকেটার" হল "নির্ভরতা ইনজেকশন" বাস্তবায়নের একটি পদ্ধতি। এটি ইনিশিয়ালাইজেশন কোডের উপর নির্ভর করে বিভিন্ন ধরনের অবজেক্ট রিটার্ন করে। কাজটি হতে দিন আমাদের জুস প্যাকেজ, নির্মাতা, কারখানা বা অন্য কিছু দ্বারা তৈরি করা, যেখানে ক্রেতা চায় সেখানে পৌঁছে দেওয়া। আমরা লোকেটারকে বলি "আমাদের একটি ডেলিভারি পরিষেবা দিন" এবং পরিষেবাটিকে কাঙ্খিত ঠিকানায় রস সরবরাহ করতে বলি৷ আজ একটি সেবা আছে, এবং আগামীকাল আরেকটি হতে পারে। এটি কোন নির্দিষ্ট পরিষেবা তা আমাদের কাছে বিবেচ্য নয়, আমাদের জন্য এটা জানা গুরুত্বপূর্ণ যে এই পরিষেবাটি আমরা যা বলি এবং আমরা এটি কোথায় বলি। পরিবর্তে, পরিষেবাগুলি "ডেলিভার" প্রয়োগ করে<предмет>চালু<адрес>».

    যদি আমরা বাস্তব জীবনের কথা বলি, তাহলে সম্ভবত একটি পরিষেবা লোকেটারের একটি ভাল উদাহরণ হবে PDO PHP এক্সটেনশন, কারণ আজ আমরা একটি MySQL ডাটাবেসের সাথে কাজ করি, এবং আগামীকাল আমরা PostgreSQL এর সাথে কাজ করতে পারি। আপনি ইতিমধ্যেই বুঝতে পেরেছেন, এটি কোন ডাটাবেসে তার ডেটা পাঠায় তা আমাদের ক্লাসের জন্য কোন ব্যাপার না, এটি গুরুত্বপূর্ণ যে এটি এটি করতে পারে।

    $db = নতুন PDO(" mysql:dbname=test;host=localhost", $user, $pass); $db = নতুন PDO(" pgsql:dbname=test host=localhost", $user, $pass);

    ডিপেনডেন্সি ইনজেকশন এবং সার্ভিস লোকেটারের মধ্যে পার্থক্য

    আপনি যদি এখনও লক্ষ্য না করেন তবে আমি ব্যাখ্যা করতে চাই। ইনজেকশন নির্ভরতাফলস্বরূপ, এটি একটি পরিষেবা প্রদান করে না (যা কোথাও কিছু সরবরাহ করতে পারে) কিন্তু একটি বস্তু যার ডেটা এটি ব্যবহার করে।

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

    ঠিক আছে, এইভাবে আমরা $key = $value - Registry::set($key, $value) $key - Registry::get($key) unset($key) - রিমুভ রেজিস্ট্রি::রিমুভ পদ্ধতিগুলির একটি মূঢ় প্রতিস্থাপন পেতে পারি ($key) এটা শুধু অস্পষ্ট হয়ে যায় - কেন এই অতিরিক্ত কোড। সুতরাং, আসুন আমাদের ক্লাসকে তা করতে শেখাই যা গ্লোবাল ভেরিয়েবল করতে পারে না। এর সাথে মরিচ যোগ করা যাক।

    getMessage()); ) Amdy_Registry::unlock("test"); var_dump(Amdy_Registry::get("test")); ?>

    প্যাটার্নের সাধারণ কাজগুলিতে, আমি পরিবর্তনগুলি থেকে একটি ভেরিয়েবল ব্লক করার ক্ষমতা যুক্ত করেছি, এটি বড় প্রকল্পগুলিতে খুব সুবিধাজনক, আপনি দুর্ঘটনাক্রমে কিছু সন্নিবেশ করবেন না। উদাহরণস্বরূপ, ডাটাবেসের সাথে কাজ করার জন্য সুবিধাজনক
    সংজ্ঞায়িত করুন('DB_DNS', 'mysql:host=localhost;dbname= ’);
    সংজ্ঞায়িত করুন('DB_USER', ' ’);
    সংজ্ঞায়িত করুন('DB_PASSWORD', ' ’);
    define('DB_HANDLE');

    Amdy_Registry::set(DB_HANDLE, নতুন PDO(DB_DNS, DB_USER, DB_PASSWORD));
    Amdy_Registry ::lock(DB_HANDLE);

    এখন কোডের ব্যাখ্যার জন্য, ডেটা সঞ্চয় করার জন্য, আমরা স্ট্যাটিক ভেরিয়েবল $data ব্যবহার করি, $লক ভেরিয়েবল পরিবর্তনের জন্য লক করা কীগুলি সম্পর্কে ডেটা সংরক্ষণ করে। নেটওয়ার্কে, আমরা ভেরিয়েবলটি লক করা আছে কিনা তা পরীক্ষা করি এবং এটিকে রেজিস্টারে পরিবর্তন বা যোগ করি। মুছে ফেলার সময়, আমরা লকটিও পরীক্ষা করি; ডিফল্ট ঐচ্ছিক প্যারামিটার বাদ দিয়ে গেটার অপরিবর্তিত থাকে। ঠিক আছে, ব্যতিক্রম পরিচালনায় মনোযোগ দেওয়া মূল্যবান, যা কিছু কারণে খুব কমই ব্যবহৃত হয়৷ যাইহোক, আমার কাছে ইতিমধ্যে ব্যতিক্রমগুলির একটি খসড়া আছে, নিবন্ধটির জন্য অপেক্ষা করুন৷ নীচে পরীক্ষার জন্য একটি খসড়া কোড রয়েছে, এখানে পরীক্ষা সম্পর্কে একটি নিবন্ধ রয়েছে, এটি লিখতেও ক্ষতি হবে না, যদিও আমি TDD-এর ভক্ত নই।

    পরবর্তী নিবন্ধে আমরা ডেটা প্রারম্ভিকতা যোগ করে এবং "অলসতা" প্রয়োগ করে কার্যকারিতা আরও প্রসারিত করব।