ইন্টারফেস ও অ্যাবস্ট্রাকশান (Interface and Abstraction)
ইন্টারফেস কি?
অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং (OOP) এ ইন্টারফেস (interface) বলতে চুক্তি করা বোঝায়, যা অন্য ক্লাস ইমপ্লিমেন্ট (Implement) করবে।
ইন্টারফেসে শুধুমাত্র চুক্তি বা শর্ত হিসাবে মেথড সিগনেচার (Method Signature) থাকে, কিন্তু মেথডের ডেফিনেশন বা ইমপ্লিমেন্টশন (Implementation) থাকে না। ইন্টারফেস ইমপ্লিমেন্টে করে এমন প্রত্যেক ক্লাসগুলোকে ইন্টারফেসের সব গুলো মেথড অবশ্যই ইমপ্লিমেন্টে (Implement) করতে হবে, এটাই শর্ত পূরণ।
তাহলে অ্যাবস্ট্রাকশান কি?
ইমপ্লিমেন্টেশান হাইড করার মাধ্যমে ইমপ্লিমেন্টেশানের উপর নির্ভরতা না রাখার কারণেই Abstraction-কে এক কথায় বলা হয় ইমপ্লিমেন্টেশান হাইডিং।
মনে করি, কোন মেথড (ধরি, testPlay) আর্গুমেন্ট হিসেবে এই ইন্টারফেস রেফারেন্সকে নেয়। এর মানে হলো ইন্টারফেস ইমপ্লিমেন্ট করা সব ক্লাসগুলোর জন্য ওই মেথড (testPlay) কল করার কোনও ডিপেন্ডেন্সি নাই। এখানে testPlay মেথড এ আমরা Upcasting করছি।
একইভাবে Upcasting ব্যবহার করে, যে মেথড প্যারেন্ট ক্লাসকে রেফারেন্স হিসাবে অ্যাকসেপ্ট বা গ্রহণ করে সেই মেথডে চাইল্ড ক্লাসে পাঠিয়ে অ্যাবস্ট্রাকশন অর্জন করা সম্ভব। সেক্ষেত্রে আমাদের বিভিন্ন চাইল্ড ক্লাসের অবজেক্ট পাঠানো লাগবে।
ইন্টারফেসের অ্যাবস্ট্রাকশান – ছোট উদাহরণ
আমরা নিচে কিছু ইমপ্লিমেন্টেশান ক্লাসের (যা ইনহেরিট করে না কিন্তু ইমপ্লিমেন্ট করে) – যেমন মিউজিক প্লেয়ার, আলিম প্লেয়ার, ভিভাসফট প্লেয়ার) নিয়ে কাজ করব যা একটি টেস্টপ্লে (testPlay) মেথডে এক্সিকিউট হয় এবং সেই মেথডে Implementation এর উপর আমরা নির্ভর করিনা, বরং ইন্টারফেসের (playable) উপর নির্ভর করি। নতুন কোনও ক্লাস যার এই ইন্টারফেসের মেথডগুলোর ইমপ্লিমেন্টেশান ডিফারেন্ট, তার অবজেক্ট দিয়ে কল দিলেও ঐ মেথডে কোনও চেইঞ্জ না এনেই শুধু নতুন ক্লাস লিখেই কাজ করা যাবে।
এই যে নির্ভরতা নাই করে ফেলা, এটাই অ্যাবস্ট্রাকশান। অ্যাবস্ট্রাকশান না থাকলে প্রতিটা ক্লাসের জন্য আমার ডিফারেন্টভাবে মেথড (testPlay) লিখতে হত। এভাবেই অ্যাবস্ট্রাকশান ব্যবহার করে অ্যাপ্লিকেশন কে ডি-কাপল (De-couple) করা যায়, যার মাধ্যমে এপ্লিকেশনে লো লেভেল ডিপেন্ডেন্সি (যা কি না – কনক্রিট (Concrete) ক্লাসে) বাদ দিয়ে হাই লেভেল ডিপেন্ডেন্সি তথা অ্যাবস্ট্রাকশানের মাধ্যমে কাজ করা যায়।
লিংকঃ http://tpcg.io/_RQR8YA
//জাভা (Java) – Interface interface Playable { void play(); }
//জাভা (Java) – Different Implementation class MusicPlayer implements Playable { public void play() { System.out.println(“Music player is playing music.”); } } class VivasoftPlayer implements Playable { public void play() { System.out.println(“Vivasoft player is playing video.”); } } class AlimPlayer implements Playable { public void play() { System.out.println(“Alim player is playing audio.”); } } public class App { public static void main(String[] args) { Playable[] playables = { new MusicPlayer(), new VivasoftPlayer(), new AlimPlayer() }; for (Playable p : playables) { testPlay(p); } } // The upcasting method, shows decoupling, // no dependency on MusicPlayer, AlimPlayer, or VivasoftPlayer public static void testPlay(Playable p) { p.play(); } }
Output:
output Music player is playing music.\ Vivasoft player is playing video. Alim player is playing audio.
ইন্টারফেস ও অ্যাবস্ট্র্যাক ক্লাস কে নিউ (new) কিওয়ার্ড দিয়ে ইনস্ট্যান্টশিয়েট বা ক্রিয়েট করা যায় না । ইন্টারফেস ও অ্যাবস্ট্র্যাক ক্লাস কে পূর্ণ বা কনক্রিট (Concrete) ক্লাসে (উদাহরণ MusicPlayer, AlimPlayer) রূপান্তরিত করার পর নিউ (new) কীওয়ার্ড ব্যবহার করে তৈরি (Create) করা যাবে। এ সময় শর্ত বা চুক্তি হল সব অ্যাবস্ট্রাক (abstract) মেথড সিগনেচার (Method Signature) উদাহরণ – play method ইমপ্লিমেন্ট (Implement) করতে হবে।
একটি ইন্টারফেস মাল্টিপল ইন্টারফেসকে ইনহেরিট করতে পারে, কিন্তু একটি ক্লাস মাল্টিপল ক্লাসকে ইনহেরিট করতে পারেনা (Java, C# ইত্যাদিতে প্রোগ্রামিং ল্যাঙ্গুয়েজ গুলো যারা মাল্টিপল ইনহেরিটেন্স সমর্থন করে না)। অপরদিকে একটি ক্লাস বা অ্যাবস্ট্রাক ক্লাস (abstract class) মাল্টিপল ইন্টারফেসকে ইমপ্লিমেন্ট করতে পারে।
আপকাস্টিং এর মাধ্যমে প্যারেন্ট ক্লাস থেকে চাইল্ড ক্লাসে অ্যাবস্ট্রাকশানের উদাহরণ
লিংকঃ http://tpcg.io/_GFV8Q3
// জাভা (Java) – Different Implementation class Parent { public void greet() { System.out.println(“Hello from Parent”); } } class Child1 extends Parent { // Override public void greet() { System.out.println(“Hello from Child1”); } } class Child2 extends Parent { // Override public void greet() { System.out.println(“Hello from Child2”); } } public class App { public static void greetParentUsingUpcasting(Parent parent) { parent.greet(); } public static void main(String[] args) { Child1 child1 = new Child1(); Child2 child2 = new Child2(); greetParentUsingUpcasting(child1); // Upcast child1 greetParentUsingUpcasting(child2); // Upcast child2 } }
Output:
//জাভা (Java) – Output Hello from Child1 Hello from Child2
এটি ক্লাস অ্যাবস্ট্রাকশনের খুব ভালো একটি উদাহরণ, জাভাতে যে কোন ক্লাসের মেথড ভার্চুয়াল কিবোর্ড দিয়ে মার্ক করতে হয় না প্রতি ক্লাসের প্রতিটি মেথডকে চাইল্ড ক্লাস থেকে ওভাররাইড করা যায়, উদাহরণ পলিমরফিজম এ দেখানো হয়েছে।
কিন্তু সি# এর ক্ষেত্রে এটি করা সম্ভব হয় না এবং এজন্যই সি# এ সাধারণত শুধু অ্যাবস্ট্রাক্ট ক্লাসের অ্যাবস্ট্রাক্ট মেথড অথবা ইন্টারফেসকেই Upcasting এর মাধ্যমে অ্যাবস্ট্রাকশন হিসেবে বোঝানো হয়।
এর আরেকটি ব্যাখ্যা হচ্ছে ইউনিট টেস্টিং লাইব্রেরীগুলো সি শার্পে শুধুমাত্র ভার্চুয়াল মার্ক মেথড গুলোকেই মক করতে পারে, এজন্যই সাধারণত ইন্টারফেস বা অ্যাবস্ট্রাক্ট ক্লাসের অ্যাবস্ট্রাক্ট মেথড ব্যবহার করলে মক করাটি সহজ হয়। এ নিয়ে বিস্তর আলোচনা আমরা ইউনিট টেস্টিং এর বুট ক্যাম্পে শিখব