Lesson ১০৭ মিনিট পড়া

ইন্টারফেসেস এবং অ্যাবস্ট্রাক্ট ক্লাসেস (Interfaces & Abstract Classes)

এমন একটি প্রমিস (promise) বা কথা দিন, যা আপনার কোডকে অবশ্যই মেনে চলতে হবে

ইন্টারফেস কী? (What Is an Interface?)

একটি ইন্টারফেসকে (interface) এক ধরনের চুক্তি (contract) হিসেবে ভাবতে পারেন। এটি বলে যে, "তুমি যদি এই চুক্তিতে সই করো, তবে তোমাকে কথা দিতে হবে যে তোমার কাছে এই নির্দিষ্ট মেথডগুলো (methods) এবং প্রোপার্টিগুলো (properties) থাকবে।" এটি আপনাকে কখনোই বলে দেয় না যে মেথডগুলো কীভাবে কাজ করবে — শুধু বলে দেয় যে আপনাকে অবশ্যই সেগুলো তৈরি করতে হবে।

একে একটি কাজের বিবরণী বা জব ডেসক্রিপশনের (job description) মতো ভাবতে পারেন। একজন "ড্রাইভারকে" অবশ্যই গাড়ি StartEngine(), Steer() এবং Stop() করতে পারতে হবে। সে গাড়ি, বাস নাকি মহাকাশযান (spaceship) চালাচ্ছে, তা এখানে গুরুত্বপূর্ণ নয় — তাদের সবাইকে একই কাজ করতে হয় বা একই চুক্তি পালন করতে হয়।

এটি কেন এত দরকারি? কারণ আপনি যখন এমন কোনো কোড লেখেন যা কিনা ওই ইন্টারফেসকে ইমপ্লিমেন্ট করা (implement) যেকোনো অবজেক্টের সাথেই কাজ করতে পারে, তখন আপনাকে সেই অবজেক্টের নির্দিষ্ট ধরন (type) নিয়ে আর ভাবতে হয় না। আপনার কোড শুধু বলে, "আমাকে এমন কিছু দাও যা চলতে (drive) পারে" আর তখন এটি নিজে থেকেই গাড়ি, বাস এবং স্পেসশিপ সবগুলোর সাথেই ঠিকঠাক কাজ করে।

ইন্টারফেসগুলো তৈরি করা এবং ইমপ্লিমেন্ট করা (Defining & Implementing Interfaces)

// Interface — the contract
interface IPlayable
{
string Title { get; } // must have a Title
double Duration { get; } // must have a Duration (in minutes)
void Play(); // must be able to Play
}
// Song implements IPlayable
class Song : IPlayable
{
public string Title { get; }
public string Artist { get; }
public double Duration { get; }
public Song(string title, string artist, double duration)
{
Title = title;
Artist = artist;
Duration = duration;
}
public void Play()
=> Console.WriteLine($"♪ Playing '{Title}' by {Artist} ({Duration} min)");
}
// Podcast also implements IPlayable
class Podcast : IPlayable
{
public string Title { get; }
public string Host { get; }
public double Duration { get; }
public Podcast(string title, string host, double duration)
{
Title = title;
Host = host;
Duration = duration;
}
public void Play()
=> Console.WriteLine($"🎙 Playing '{Title}' hosted by {Host} ({Duration} min)");
}
// Works with ANY IPlayable!
void PlayAll(IPlayable[] playlist)
{
double total = 0;
foreach (var item in playlist)
{
item.Play();
total += item.Duration;
}
Console.WriteLine($"Total time: {total} minutes");
}
IPlayable[] myPlaylist = {
new Song("Bohemian Rhapsody", "Queen", 5.9),
new Podcast("Code Talk", "Dev Dan", 45.0),
new Song("Imagine", "John Lennon", 3.1)
};
PlayAll(myPlaylist);
Output
♪ Playing 'Bohemian Rhapsody' by Queen (5.9 min)
🎙 Playing 'Code Talk' hosted by Dev Dan (45 min)
♪ Playing 'Imagine' by John Lennon (3.1 min)
Total time: 54 minutes

একাধিক ইন্টারফেস — একই সাথে অনেকগুলো দায়িত্ব পালন (Multiple Interfaces — Wear Many Hats)

একটি ক্লাস কেবল একটিমাত্র প্যারেন্ট ক্লাস (single inheritance) থেকে ইনহেরিট (inherit) করতে পারে, কিন্তু এটি চাইলে যেকোনো সংখ্যক ইন্টারফেসকে (interfaces) ইমপ্লিমেন্ট (implement) করতে পারে। এটি অনেকটা এমন একজন মানুষের মতো, যিনি একই সাথে একজন "সাঁতারু", একজন "দৌড়বিদ" এবং একজন "রাঁধুনি" — তিনি একই সাথে এই সবগুলো কাজের চুক্তি বা দায়িত্ব পালন করেন।

সি শার্পের ৮ম ভার্সন (C# 8) থেকে ইন্টারফেসগুলোতে ডিফল্ট ইমপ্লিমেন্টেশন (default implementations) যুক্ত করা হয়েছে — যার মানে হলো আপনি ইন্টারফেসের ভেতরেই সরাসরি কোনো মেথডের বডি (body) বা গঠন লিখে দিতে পারবেন। যেসব ক্লাস ওই ইন্টারফেসটিকে ইমপ্লিমেন্ট (implement) করে, তারা মেথডটি একদম বিনা পরিশ্রমে বা ডিফল্টভাবেই (default) পেয়ে যায়, তবে তারা চাইলে নিজেদের মতো করে মেথডটিকে পরিবর্তন বা ওভাররাইড (override) করে নিতে পারে।

একাধিক ইন্টারফেস এবং ডিফল্ট মেথডস (Multiple Interfaces & Default Methods)

interface IPrintable
{
void Print();
}
interface ISaveable
{
void Save(string path);
// Default implementation (C# 8+)
void AutoSave()
{
Save("./auto-backup.txt");
Console.WriteLine("Auto-saved!");
}
}
interface IShareable
{
void Share(string recipient);
}
// Document implements ALL THREE interfaces
class Document : IPrintable, ISaveable, IShareable
{
public string Content { get; set; }
public Document(string content) => Content = content;
public void Print()
=> Console.WriteLine($"Printing: {Content}");
public void Save(string path)
=> Console.WriteLine($"Saved to {path}");
public void Share(string recipient)
=> Console.WriteLine($"Shared with {recipient}");
}
var doc = new Document("My Report");
doc.Print();
doc.Save("/documents/report.txt");
doc.Share("[email protected]");
// Access the default method through the interface
ISaveable saveable = doc;
saveable.AutoSave();
Output
Printing: My Report
Saved to /documents/report.txt
Shared with [email protected]
Saved to ./auto-backup.txt
Auto-saved!

অ্যাবস্ট্রাক্ট ক্লাস বনাম ইন্টারফেস — কখন কোনটি ব্যবহার করবেন? (Abstract Class vs Interface — When to Use Which?)

এদের দুজনকে দেখতে অনেকটা একই রকম মনে হলেও, নিচে এদের মূল পার্থক্যগুলো দেওয়া হলো:

  • ইন্টারফেস (Interface): এটি হলো একটি খাঁটি চুক্তি (Pure contract)। এর নিজস্ব কোনো স্টেট (state) বা অবস্থা থাকে না (C# 8 এর ডিফল্টগুলো বাদ দিলে)। একটি ক্লাস চাইলে অনেকগুলো ইন্টারফেস ইমপ্লিমেন্ট করতে পারে। যখন একে অপরের সাথে সম্পর্কহীন ক্লাসগুলোর একই ধরনের ক্ষমতার প্রয়োজন হয় (যেমন- IPrintable), তখন এটি ব্যবহার করা উচিত।
  • অ্যাবস্ট্রাক্ট ক্লাস (Abstract class): এটি হলো একটি আংশিক বা অর্ধেক তৈরি হওয়া ব্লুপ্রিন্ট (blueprint)। এর নিজস্ব ফিল্ডস (fields), কনস্ট্রাক্টর (constructors) এবং ইমপ্লিমেন্ট করা ও অ্যাবস্ট্রাক্ট (abstract) মেথড — উভয়ই থাকতে পারে। একটি ক্লাস কেবল একটিমাত্র অ্যাবস্ট্রাক্ট ক্লাস থেকে ইনহেরিট করতে পারে। যখন ক্লাসগুলোর মূল পরিচয় একই হয় (যেমন- সব ধরনের শেইপ বা Shapes), তখন এটি ব্যবহার করা উচিত।

সাধারণ নিয়ম (Rule of thumb): যদি সম্পর্কটি "কী করতে পারে (can do)" এমন হয় (যেমন- প্রিন্ট করতে পারে, সেভ করতে পারে), তবে ইন্টারফেস ব্যবহার করুন। আর যদি সম্পর্কটি "কী হয় (is a)" এমন হয় (যেমন- এটি একটি আকৃতি বা shape, এটি একটি প্রাণী বা animal), তবে অ্যাবস্ট্রাক্ট ক্লাস ব্যবহার করুন।

Note: 🤝 ইন্টারফেসের নাম লেখার নিয়ম: সি শার্পে (C#) ইন্টারফেসের নাম সব সময় বড় হাতের আই (I) দিয়ে শুরু হয় — যেমন IPlayable, IDisposable, IComparable। এর ফলে কোড দেখার সাথে সাথেই এরা আলাদাভাবে চোখে পড়ে। এটি সি শার্প কম্পাইলারের (compiler) কোনো বাধ্যবাধকতা নয়, কিন্তু প্রতিটি সি শার্প ডেভেলপার এটাই আশা করেন।
চ্যালেঞ্জ

ছোট কুইজ

একটি ক্লাস (class) সর্বোচ্চ কয়টি ইন্টারফেস (interfaces) ইমপ্লিমেন্ট (implement) করতে পারে?
Inheritance & PolymorphismCollections & Generics