PHP OOP Part-5: Abstraction and Interface

Jamir Hossain
5 min readNov 28, 2023

--

আমরা জানি অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং এ Abstraction একটি গুরুত্বপূর্ণ বিষয়। এখন এই Abstraction আসলে কি? আসলে Abstraction বলতে আমরা তাকেই বলতে পারি যেখানে কোন একটি প্রোগ্রামের Implementation hide থাকবে শুধুমাত্র সেই প্রোগ্রামের ফাংশনালিটিগুলো দেখা যাবে।

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

class Vehicle
{
public function getBaseFare()
{
// implementation
}

public function getPerKiloFare()
{
// implementation
}

public function getTotalFare()
{
// implementation
}
}


class Car extends Vehicle
{
// Car implementation
}

class Bike extends Vehicle
{
// Bike implementation
}

আমরা এখানে দেখতে পাচ্ছি যে Vehicle ক্লাস কে Car এবং Bike ক্লাস ইনহেরিট করতেছে। এর ফলে Vehicle ক্লাসের মধ্যে যে সকল Method রয়েছে সেগুলোর Access এই উভয় ক্লাসের মধ্যে পেয়ে গেল।কিন্তু এখানে একটা সমস্যা হল যে প্যারেন ক্লাসের মধ্যে থাকা মেথরের মধ্যে যে ইমপ্লিমেন্টেশন রয়েছে সেই ইমপ্লিমেন্টেশন Child ক্লাস গুলো পাবে। এর ফলে সব চাইল্ড ক্লাসের মধ্যে একটা কমন ইমপ্লিমেন্টেশন থাকবে আর এই Common ইমপ্লিমেন্টেশনের ফলে সবগুলোই Same behave করবে। কিন্তু এমনটা তো হওয়া উচিত না কারণ Car এর জন্য আলাদা behave করতে হবে আবার Biker এর জন্য আলাদা behave করতে হবে। কিন্তু যেহেতু আমরা প্যারেন ক্লাস থেকে মেথড গুলোকে ইনহেরিট করে নিয়ে এসেছি তাই এগুলো উভয়ের জন্য Same behave করতেছে।

কিন্তু এই Common মেথড গুলো ইনহেরিট করার পরেও যদি আমরা চাই এগুলো প্রত্যেকটা ক্লাসের জন্য আলাদা আলাদা behave করবে তাহলে সেক্ষেত্রে আমরা কি করতে পারি?

এই কি সমস্যা সমাধান করার জন্য পিএইচপির Abstract class ক্লাস ব্যবহার করতে করা হয়। Abstract class ক্লাস কি?

Abstract class ক্লাস হলেও এমন এক ধরনের ক্লাস যেখানে Abstract মেথডও থাকতে পারে আবার Non-abstract মেথডও থাকতে পারে। এখন Abstract এবং Non-abstract মেথড কি?

অবস্ট্রাক্ট মেথড হল যেখানে শুধুমাত্র মেথডের ডেফিনেশন টা থাকবে কিন্তু ইমপ্লিমেন্টেশন থাকবে না। এর ফলে যখন কোন Child ক্লাস এই Parent ক্লাস কে ইনহেরিট করবে তখন Child ক্লাসে অবশ্যই এই Parent ক্লাসের Abstract মেথড এর ইমপ্লিমেন্টেশন করতে হবে।

আর Non-abstract মেথড হলো ঐ সকল মেথড যেগুলোর ডেফিনেশন এবং ইমপ্লিমেন্টেশন প্যারেন্ট ক্লাসের মধ্যেই থাকে। চাইল্ড ক্লাসের মধ্যে শুধুমাত্র ইনহিট করে আমরা তাদেরকে ব্যবহার করতে পারি।

এখন আমরা Abstract class ক্লাসের মাধ্যমে উপরের সমস্যাটির সমাধান করার চেষ্টা করব।

abstract class Vehicle
{
abstract public function getBaseFare();

abstract public function getPerKiloFare();

public function getTotalFare()
{
echo $this->getBaseFare() + $this->getPerKiloFare() . "\n";
}
}


class Car extends Vehicle
{
public function getBaseFare()
{
return 20;
}

public function getPerKiloFare()
{
return 10;
}
}

class Bike extends Vehicle
{
public function getBaseFare()
{
return 10;
}

public function getPerKiloFare()
{
return 5;
}
}

$car = new Car();
$car->getTotalFare();

$bike = new Bike();
$bike->getTotalFare();

এখানে আমরা দেখতে পাচ্ছি Vehicle নামে একটা ক্লাস রয়েছে। যদি আমরা কোনো ক্লাসকে Abstract করতে চাই তাহলে সেই ক্লাসের পুর্বে abstract keyword ব্যবহার করতে হয়। তাই Vehicle ক্লাসটি মূলত একটি Abstract class। একইভাবে যদি Abstract class ক্লাসের কোন মেথডকে আমরা abstract করতে চাই তাহলে সেই মেথরের নামের পূর্বে আমাদেরকে abstract keyword ইউজ করতে হবে। আর এখানে মনে রাখতে হবে যে যদি আমরা কোন ক্লাসের কোন মেম্বারকে abstract করতে চাই তাহলে অবশ্যই সে ক্লাসকে abstract ক্লাস হতে হবে।

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

এখন আমাদের মনে প্রশ্ন আসতে পারে যে আমরা তো চাইলেই getBaseFare এবং getPerKiloFare এই দুটি মেথডকে চাইল্ড ক্লাসের মধ্যে স্বাভাবিকভাবেই ইমপ্লিমেন্টেশন করতে পারতাম, এদেরকে আমরা কেন আবার প্যারেন্টের মধ্যে এবস্ট্রাক করলাম?

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

এখানে মনে রাখতে হবে Abstract class এর সরাসরি কোনো Object বা Instance তৈরি করা যায় না বরং Child ক্লাস এর মাধ্যমে এদেরকে Access করা যায় এবং Abstract class থেকে ইনহেরিট করা Abstract মেথডগুলোর ইমপ্লিমেন্টেশন অবশ্যই চাইল্ড ক্লাসে করতেই হবে তা না হলে child class এর কোন কিছুই কাজ করবে না। আশা করি Abstract ক্লাসের ব্যবহার সম্পর্কে কিছুটা ধারণা হয়েছে।

What is Interface in PHP?

উপরের আলোচনায় আমরা এবস্ট্রাক্ট ক্লাস নিয়ে আলোচনা করেছি। সেখান থেকে আমরা জেনেছি যে Abstract class থেকে ইনহেরিট করা Abstract মেথডগুলোর ইমপ্লিমেন্টেশন অবশ্যই চাইল্ড ক্লাসে করতেই হবে তা না হলে child class এর কোন কিছুই কাজ করবে না।

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

এই ক্ষেত্রে আমরা ইন্টারফেসের ব্যবহার করতে পারি। ইন্টারফেস কি? ইন্টারনেট হল Abstract ক্লাসের মতোই কিন্তু Abstract ক্লাস fully abstracted না কেননা আমরা জানি Abstract class এর মধ্যে Abstract এবং Non-abstract উভয় প্রকার Member থাকতে পারে।

অপরদিকে ইন্টারফেস এর মধ্যে শুধুমাত্র Abstract Member গুলোই থাকতে পারে। যার ফলে ইন্টারফেসকে fully abstracted ক্লাস বলা হয়।

এখন ইন্টারফেস ব্যবহার করে আমরা উপরের সমস্যাটির সমাধান করার চেষ্টা করব।

interface HourlyRentable
{
public function getHourlyRate();
}

abstract class Vehicle
{
abstract public function getBaseFare();

abstract public function getPerKiloFare();

public function getTotalFare()
{
echo $this->getBaseFare() + $this->getPerKiloFare() . "\n";
}
}


class Car extends Vehicle implements HourlyRentable
{
public function getBaseFare()
{
return 20;
}

public function getPerKiloFare()
{
return 10;
}

public function getHourlyRate()
{
echo "Hourly 2 Dollar";
}
}

class Bike extends Vehicle
{
public function getBaseFare()
{
return 10;
}

public function getPerKiloFare()
{
return 5;
}
}

$car = new Car();
$car->getTotalFare();

$bike = new Bike();
$bike->getTotalFare();

এখানে ইন্টারফেস এর মধ্যে আমরা দেখতে পাচ্ছি getHourlyRate এই ফাংশন এর Declaration রয়েছে। তারপর Car ক্লাসের মধ্যে আমরা এই ইন্টারফেসকে ইউজ(ইমপ্লিমেন্ট বা ইনহেরিট) করে এই ইন্টারফেসের মধ্যে থাকা Abstract মেথডের ইমপ্লিমেন্টেশন করেছি। কিন্তু Bike ক্লাসে এই মেথডকে ইমপ্লিমেন্ট করতে হয়নি কারণ আমরা এই ইন্টারফেসকে Bike ক্লাসে ইউজ(ইমপ্লিমেন্ট বা ইনহেরিট) করিনি। কিন্তু যদি Abstract ক্লাসের মধ্যে এই Abstract মেথড থাকতো তাহলে কিন্তু আমাদেরকে এই উভয় চাইল্ড ক্লাসের মধ্যে যদি প্রয়োজন নাও হয় তার পরেও এই মেথডের ইমপ্লিমেন্টেশন করতে হতো যা একটি Bad ডিজাইন হতো। এছাড়াও ইন্টারফেসের আরও বিভিন্ন ইউজ কেস রয়েছে।

আশা করি এই পর্বের আলোচিত বিষয় গুলো সম্পর্কে আপনাদের প্রাথমিক ধারণা হয়েছে। তাহলে আজ এই পর্যন্তই, কথা হবে পরবর্তী লেছনে।

--

--