অন্যান্য উত্তরগুলি ইন্টারফেস এবং বৈশিষ্ট্যের মধ্যে পার্থক্য ব্যাখ্যা করার দুর্দান্ত কাজ করে। আমি একটি দরকারী বাস্তব বিশ্বের উদাহরণের উপর ফোকাস করব, বিশেষত একটিতে যা দেখায় যে বৈশিষ্ট্যগুলি উদাহরণ ভেরিয়েবলগুলি ব্যবহার করতে পারে - আপনাকে ন্যূনতম বয়লারপ্লেট কোড সহ কোনও শ্রেণিতে আচরণ যুক্ত করতে দেয়।
আবার, অন্যদের দ্বারা উল্লিখিত মত, বৈশিষ্টগুলি ইন্টারফেসের সাথে ভালভাবে জুড়ি দেয়, ইন্টারফেসটিকে আচরণের চুক্তিটি নির্দিষ্ট করতে দেয় এবং বৈশিষ্ট্যটি বাস্তবায়নে পরিপূর্ণ হয়।
কোনও ক্লাসে ইভেন্ট প্রকাশ / সাবস্ক্রাইব ক্ষমতা যুক্ত করা কিছু কোড বেসগুলিতে একটি সাধারণ দৃশ্য হতে পারে। এখানে 3 টি সাধারণ সমাধান রয়েছে:
- ইভেন্টের পাব / সাব কোড সহ একটি বেস শ্রেণীর সংজ্ঞা দিন এবং তারপরে দক্ষতা অর্জনের জন্য যে ক্লাসগুলি ইভেন্টগুলির অফার করতে চায় সেগুলি এটি প্রসারিত করতে পারে।
- ইভেন্টের পাব / সাব কোড সহ একটি শ্রেণীর সংজ্ঞা দিন এবং তারপরে অন্যান্য শ্রেণিগুলি যা ইভেন্টগুলি দিতে চায় সেগুলি রচনাটির মাধ্যমে এটি ব্যবহার করতে পারে, রচনা অবজেক্টটি আবদ্ধ করার জন্য তাদের নিজস্ব পদ্ধতিগুলি সংজ্ঞায়িত করে, পদ্ধতিটির কলকে প্রক্সিং করে।
- ইভেন্ট পাব / সাব কোড সহ একটি বৈশিষ্ট্য সংজ্ঞায়িত করুন, এবং তারপরে অন্যান্য শ্রেণিগুলি যা ইভেন্টগুলি দিতে চায়
use
তা বৈশিষ্ট্য অর্জনের জন্য, বৈশিষ্টটি, এটি আমদানি করতে পারে।
প্রতিটি কাজ কতটা ভাল করে?
# 1 ভাল কাজ করে না। এটি হ'ল, যতক্ষণ না আপনি বুঝতে পারবেন যে আপনি বেস ক্লাসটি বাড়িয়ে দিতে পারবেন না কারণ আপনি ইতিমধ্যে অন্য কিছু প্রসারিত করছেন। আমি এর উদাহরণ দেখাব না কারণ এটি উত্তরাধিকারসূত্রে ব্যবহার করার জন্য এটি কতটা সীমাবদ্ধ তা স্পষ্ট হওয়া উচিত।
# 2 এবং # 3 উভয়ই ভাল কাজ করে। আমি একটি উদাহরণ দেখাব যা কিছু পার্থক্য তুলে ধরে।
প্রথমত, কিছু কোড যা উভয় উদাহরণের মধ্যে একই হবে:
একটি ইন্টারফেস
interface Observable {
function addEventListener($eventName, callable $listener);
function removeEventListener($eventName, callable $listener);
function removeAllEventListeners($eventName);
}
এবং ব্যবহার দেখানোর জন্য কিছু কোড:
$auction = new Auction();
// Add a listener, so we know when we get a bid.
$auction->addEventListener('bid', function($bidderName, $bidAmount){
echo "Got a bid of $bidAmount from $bidderName\n";
});
// Mock some bids.
foreach (['Moe', 'Curly', 'Larry'] as $name) {
$auction->addBid($name, rand());
}
ঠিক আছে, এখন দেখা যাক Auction
বৈশিষ্টগুলি ব্যবহার করার সময় শ্রেণীর প্রয়োগ কীভাবে পৃথক হবে lets
প্রথমত, এখানে # 2 (রচনা ব্যবহার করে) দেখতে কেমন হবে:
class EventEmitter {
private $eventListenersByName = [];
function addEventListener($eventName, callable $listener) {
$this->eventListenersByName[$eventName][] = $listener;
}
function removeEventListener($eventName, callable $listener) {
$this->eventListenersByName[$eventName] = array_filter($this->eventListenersByName[$eventName], function($existingListener) use ($listener) {
return $existingListener === $listener;
});
}
function removeAllEventListeners($eventName) {
$this->eventListenersByName[$eventName] = [];
}
function triggerEvent($eventName, array $eventArgs) {
foreach ($this->eventListenersByName[$eventName] as $listener) {
call_user_func_array($listener, $eventArgs);
}
}
}
class Auction implements Observable {
private $eventEmitter;
public function __construct() {
$this->eventEmitter = new EventEmitter();
}
function addBid($bidderName, $bidAmount) {
$this->eventEmitter->triggerEvent('bid', [$bidderName, $bidAmount]);
}
function addEventListener($eventName, callable $listener) {
$this->eventEmitter->addEventListener($eventName, $listener);
}
function removeEventListener($eventName, callable $listener) {
$this->eventEmitter->removeEventListener($eventName, $listener);
}
function removeAllEventListeners($eventName) {
$this->eventEmitter->removeAllEventListeners($eventName);
}
}
এখানে # 3 (বৈশিষ্ট্যগুলি) দেখতে কেমন হবে:
trait EventEmitterTrait {
private $eventListenersByName = [];
function addEventListener($eventName, callable $listener) {
$this->eventListenersByName[$eventName][] = $listener;
}
function removeEventListener($eventName, callable $listener) {
$this->eventListenersByName[$eventName] = array_filter($this->eventListenersByName[$eventName], function($existingListener) use ($listener) {
return $existingListener === $listener;
});
}
function removeAllEventListeners($eventName) {
$this->eventListenersByName[$eventName] = [];
}
protected function triggerEvent($eventName, array $eventArgs) {
foreach ($this->eventListenersByName[$eventName] as $listener) {
call_user_func_array($listener, $eventArgs);
}
}
}
class Auction implements Observable {
use EventEmitterTrait;
function addBid($bidderName, $bidAmount) {
$this->triggerEvent('bid', [$bidderName, $bidAmount]);
}
}
নোট করুন যে শ্রেণীর ভিতরে থাকা কোডটি EventEmitterTrait
হুবহু একইভাবে EventEmitter
ক্লাসের অভ্যন্তরে যেমন বৈশিষ্ট্যটি triggerEvent()
পদ্ধতিটিকে সুরক্ষিত হিসাবে ঘোষণা করে ঠিক তেমনই is সুতরাং, আপনার কেবলমাত্র পার্থক্যটি দেখতে হবে Auction
শ্রেণীর বাস্তবায়ন ।
এবং পার্থক্য বড়। রচনা ব্যবহার করার সময়, আমরা একটি দুর্দান্ত সমাধান পাই, আমাদের পছন্দমতো EventEmitter
ক্লাস দ্বারা আমাদের পুনরায় ব্যবহার করার অনুমতি দেয় । তবে, প্রধান ত্রুটিটি হ'ল আমাদের কাছে প্রচুর বয়লারপ্লেট কোড রয়েছে যা আমাদের লিখতে ও বজায় রাখতে হবে কারণ Observable
ইন্টারফেসে সংজ্ঞায়িত প্রতিটি পদ্ধতির জন্য আমাদের এটি প্রয়োগ করা এবং বোরিং বয়লারপ্লিট কোড লিখতে হবে যা কেবলমাত্র যুক্তিটিকে সংশ্লিষ্ট পদ্ধতিতে প্রেরণ করে write আমাদের EventEmitter
বস্তু রচনা । এই উদাহরণে বৈশিষ্ট্যটি ব্যবহার করা আমাদের এড়াতে দেয় , বয়লারপ্লেট কোড হ্রাস করতে এবং রক্ষণাবেক্ষণযোগ্যতা উন্নত করতে সহায়তা করে ।
যাইহোক, এমন সময় থাকতে পারে যেখানে আপনি চান না যে আপনার Auction
ক্লাসটি পুরো Observable
ইন্টারফেসটি প্রয়োগ করবে - সম্ভবত আপনি কেবল 1 বা 2 টি পদ্ধতি উদ্ঘাটন করতে চান, বা এমনকি এমনকি কোনওটিই নয় যাতে আপনি নিজের পদ্ধতির স্বাক্ষরগুলি সংজ্ঞায়িত করতে পারেন। এই জাতীয় ক্ষেত্রে, আপনি এখনও রচনা পদ্ধতি পছন্দ করতে পারেন।
তবে, বেশিরভাগ দৃশ্যে বৈশিষ্ট্যটি খুব আকর্ষণীয়, বিশেষত যদি ইন্টারফেসের প্রচুর পদ্ধতি থাকে, যার ফলে আপনি প্রচুর বয়লারপ্লেট লেখেন।
* আপনি আসলে উভয়টিই করতে পারেন - EventEmitter
আপনি যদি কখনও কাঠামোগতভাবে ব্যবহার করতে চান তবে ক্লাসটি সংজ্ঞায়িত করুন এবং EventEmitterTrait
বৈশিষ্ট্যের EventEmitter
অভ্যন্তরে শ্রেণি প্রয়োগটি ব্যবহার করে বৈশিষ্ট্যটিও সংজ্ঞায়িত করুন :)