অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং পরিচিতি(Introduction to OOP)
আশাকরছি সবাই ভালো আছেন। অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং নিয়ে নতুন সিরিজ শুরু করছি। এই লেখায় আলোচনা করব অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং এর পরিচিতি নিয়ে মানে কিছু বেসিক জিনিস জেনে রাখব যা আমাদের এই সিরিজের পরের টিউটোরিয়াল গুলো বুঝতে সহযোগিতা করবে এবং অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং বুঝার জন্য এই টিউটোরিয়াল অত্যন্ত জরুরী। আর অবশ্যই আপনাকে ডাটা টাইপ, অ্যারে এবং ফাংশন সম্পর্কে ভালো ধারণা থাকতে হবে।
Class and object
আমরা প্রথমেই জেনে নেই অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং কি? টিপিক্যাল ডেফিনিশন, "সহজ কথায়, অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং আমাদের কে রিয়্যাল লাইফ অবজেক্ট কে প্রোগ্রামিংয়ে রিপ্রেজেন্ট করার সুবিধা দেয়।" অনেকেই হয়ত বুঝতে পারেন নি কিন্তু এরপরেও আমি বড় বা ক্লিয়ার ডেফিনিশন দিচ্ছি না। মূল ছবিটা না বুঝতে পারলে মনে হয় না কোন ডেফিনিশনই কাজে আসবে। তবে আমি আশাকরছি নিচের লেখা বুঝতে পারলে নিজেই নিজের মত করে একটা ডেফিনিশন বানিয়ে নিতে পারবেন।
আমরা যদি দুজন শিক্ষার্থী Alice এবং Bob এর bangla ও english সাবজেক্ট গুলোর নাম্বার গুলো রাখতে চাই তাহলে আমরা কি করব? যেহেতু আমরা প্রোগ্রামিংয়ের বেসিক জানি তাই এই ডাটা গুলো রাখার জন্য প্রথমেই মাথায় আসবে অ্যারে ডাটা স্ট্রাকচার। ধরি ২ টা সাবজেক্ট আছে তাই তাদের নামে অ্যারে ডিক্লেয়ার করব এবং সাইজ দিব ২। যেমন, int Alice[2]; এখন এখানে Alice অ্যারের শুন্য তম ইনডেক্স মানে bangla, এক তম ইনডেক্স মানে english।
int Alice[2];
Alice[0] = 81; // bangla = 81
Alice[1] = 85; // english = 85
কিন্তু কমেন্ট না থাকলে এই কোড একেবারেই অন্যের কাছে দুর্বোধ্য। এবং যিনি লিখবেন তিনি হয়ত কয়েক মাস পরে ভুলে যাবেন এটাই স্বাভাবিক। এখন বলতে পারেন ২টা সাবজেক্ট আর এমন কি? কিন্তু যদি বলি সাবজেক্ট সংখ্যা আরো বেশি হয়, ১০ টা বা ২০ টা। পরে কি হবে এটা পরের কথা, লিখতেই ত ঝামেলা লাগবে এবং গুলিয়ে যাওয়ার সম্ভাবনা আছে। তাছাড়া ১ নাম্বার ইনডেক্সে কোন সাবজেক্ট এর নাম্বার রেখেছি এসব মুখস্ত করে সময় নষ্ট করবেন? আরেকটি বড় সমস্যা হচ্ছে আমি Alice নামক অ্যারে তে ২ টা সাবজেক্ট এর মার্কস রাখার পাশাপাশি তার নাম ও রাখতে চাই। এটি অ্যারে তে সম্ভব? আমরা জানি অ্যারে ডাটা স্ট্রাকচার শুধু একই টাইপের ডাটা রাখতে পারে। কিন্তু নাম ত string এবং মার্কস ত integer। দুই টাইপ কে এক জায়গায় রাখব কীভাবে?
তাহলে এর সমাধান কি? কেমন হয় যদি Alice.bangla = 81; রাখা যায় এবং Alice.name = "Alice Weasley";? নিশ্চয়ই আগের চেয়ে বুঝতে অনেক সহজ হয়ে যাচ্ছে। কারণ এটা দেখেই বুঝে ফেলা যাচ্ছে এবং ইনডেক্স এর ঝামেলা চলে যাচ্ছে। আর আমরা Alice এর ভিতরেই একের অধিক টাইপের ডাটা রাখতে পারছি।
Alice.name = "Alice Weasley";
Alice.bangla = 81;
Alice.english = 85;
আমরা কিন্তু নির্দিষ্ট ডাটা টাইপের বাইরেও কাস্টম ডাটা টাইপ বানিয়ে এই সুবিধা টি নিতে পারি। কাস্টম ডাটা টাইপ কীভাবে বানাতে হয় চলুন দেখি,
class Student { public: int bangla; int english; string name; }; |
সি++ এ কাস্টম ডাটা টাইপ বানাতে চাইলে আপনি যে নামে বানাতে চাচ্ছেন সেই নামের পূর্বে class লিখতে হয়। ভিতরে ডাটা গুলো public করে রেখেছি যেন class এর বাইরেও এগুলো access করা যায়। public হচ্ছে access modifier। class এর ভিতরের ডাটা গুলো কে বলা হয় attributes। আর অবশ্যই class এর ক্লোজিং ব্র্যাকেটের শেষে ; (সেমিকোলন) দিতে হবে। এখন Student হচ্ছে আমাদের কাস্টম ডাটা টাইপ। আমরা যেমন int দিয়ে ভেরিয়েবল ডিক্লেয়ার করতে পারি তেমনি এখন Student দিয়েও করতে পারব তবে Student দিয়ে যাই ডিক্লেয়ার করবেন তাকে object বলে।
int Alice[3];
Student Alice;
দুটোর কাজ একই কিন্তু object Alice একটু অর্থপূর্ণ এবং বুঝতে সুবিধা হবে এবং Alice অ্যারে তে আমরা নামই ত রাখতে পারব না কারণ এর টাইপ শুধু int। এখন আমরা Alice.bangla = 81; এভাবেই ডাটা স্টোর করতে পারব। এখন আপনার সাবজেক্ট সংখ্যা যতই হোক আপনি class এর ভিতরে তা রেখে দিলেই কাজ করতে পারবেন।
যখন আমরা অ্যারে ব্যবহার করছিলাম তখন কাজ টা একটু জটিল ছিলো এবং string ও int আমরা একই জায়গায় রেখে ব্যবহারই করতে পারছি না কিন্তু এই class এবং object ব্যবহার করায় আমাদের কাজ অনেক সহজ ও বোধগম্য হয়ে গেছে। এটিই হচ্ছে অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং কারণ আমরা এর মাধ্যমে রিয়্যাল ওয়ার্ল্ড অবজেক্ট কে প্রোগ্রামিংয়ে ব্যবহার করে সহজে সমস্যার সমাধান করতে পারছি।
int main() { // Student is custom data type Student Alice; // declare object Alice
// assign informations to Alice object Alice.name = "Alice Weasley"; Alice.bangla = 71; Alice.english = 75;
Student Bob; // declare object Bob
// assign informations to Bob object Bob.name = "Bob Potter"; Bob.bangla = 82; Bob.english = 88;
/* print informations */ // printing informations of Alice cout << "Name: " << Alice.name << endl; cout << "Name: " << Alice.name << endl; cout << "Bangla: " << Alice.bangla << endl; cout << "English: " << Alice.english << endl;
// printing informations of Bob cout << "Name: " << Bob.name << endl; cout << "Name: " << Bob.name << endl; cout << "Bangla: " << Bob.bangla << endl;
return 0; } |
উপরের code এ আমরা আমাদের তৈরি কাস্টম ডাটা টাইপ Student দিয়ে Alice অবজেক্ট ডিক্লেয়ার করেছি। এই Alice অবজেক্ট এখন Student class কে রিপ্রেজেন্ট করবে এবং ঐ class এর ভিতরের attributes গুলো এক্সেস করতে পারবে Alice দিয়ে। এরপর Bob এর জন্যেও তার নামে অবজেক্ট তৈরি করেছি। এখন সহজেই তাদের নাম ও মার্কস স্টোর করতে পারছি এবং প্রয়োজনে ব্যবহার করতে পারছি। এই কাস্টম ডাটা টাইপ কে user defined data type বলা হয়।
Method and constructor
এখন আপনাদের মনে একটা প্রশ্নের উদয় হতে পারে যা আমার মনেও হয়েছিল। প্রশ্নটি হলো, এতে আসলে লাভ কি হলো? কোড ত মনে হচ্ছে আরো বেশিই লিখতে হচ্ছে। এখন আমরা অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিংয়ের সুন্দর একটা জিনিসের সাথে পরিচিত হব তার নাম হচ্ছে method আর হ্যা class এর ভিতরে ফাংশন ও রাখা যায় এবং সেই ফাংশনকেই আসলে method বলে।
class Student { public: int bangla; int english; string name;
void printInfo() { // class method cout << "Name: " << name << endl; cout << "Bangla: " << bangla << endl; cout << "English: " << english << endl; } };
int main() { Student Alice; // declare object Alice
// assign informations of Alice Alice.name = "Alice Weasley"; Alice.bangla = 71; Alice.english = 75;
Student Bob; // declare object Bob
// assign informations of Bob Bob.name = "Bob Potter"; Bob.bangla = 82; Bob.english = 88;
/* print informations */ // printing informations of Alice to call the method Alice.printInfo();
// printing informations of Bob to call the method Bob.printInfo();
return 0; } |
এখানে class এর ভিতরে printInfo() নামে একটি method তৈরি করে রেখেছি যে মেথডের কাজ হচ্ছে informations গুলো প্রিন্ট করে দেওয়া। এখন এই মেথড কে যে অবজেক্টের মাধ্যমে কল করা হবে সে সেই অবজেক্টের informations গুলোই প্রিন্ট করবে। যেমন, Alice.printInfo(); কল করা মানে Alice এর informations প্রিন্ট করা। আশাকরছি বুঝতে পেরেছেন method আমাদের কত সুবিধা দিচ্ছে। আরো ভালো উপলব্ধি করতে পারেন যদি ভেবে দেখেন আগের নিয়মে ১০০ জন শিক্ষার্থীর informations রাখতে হলে কি হত।
এখন আলোচনা করব constructor নিয়ে এবং এর সুবিধা গুলো নিয়ে। constructor হচ্ছে বিশেষ method যা object তৈরি করার সময় আপনা আপনিই কল হয়। এর কোন রিটার্ন টাইপ নেই। constructor এর নাম সবসময় class এর নামে দিতে হবে, এখানে ইচ্ছামত নাম দেওয়ার স্বাধীনতা নেই। constructor সবসময় public রাখতে হবে। তাহলে values এসাইনের কাজ টি আমরা constructor এর ভিতরেও করতে পারি।
class Student { public: int bangla; int english; string name;
Student(string Name, int Bangla, int English) { // constructor name = Name; bangla = Bangla; english = English; }
void printInfo() { // method cout << "Name: " << name << endl; cout << "Bangla: " << bangla << endl; cout << "English: " << english << endl; } };
int main() { // create object and send values to constructor Student Alice("Alice Weasley", 71, 75);
// create object and send values to constructor Student Bob("Bob Potter", 82, 88);
/* print informations */ // printing informations of Alice Alice.printInfo();
// printing informations of Bob Bob.printInfo();
return 0; } |
constructor এর প্যারামিটার সংখ্যা কমবেশি করে আমরা আমাদের সুবিধা মত ব্যবহার করতে পারি। কোন প্যারামিটার পাস না করলেও constructor কল হয় এবং সেটি হয়ে যায় default constructor। এখন একটু ভেবে দেখুন method ও constructor আমাদের কাজ কতটা কমিয়ে দিয়েছে এবং অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং আমাদের কাজ কত সহজ এবং কোড কে অনেক স্বচ্ছ করে দিচ্ছে।
Access modifier
এখন আমরা access modifier নিয়ে আলোচনা করব। এটিও অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিংয়ের গুরুত্বপূর্ণ একটি বিষয়। access modifier ৩ প্রকার,
১। public,
২। private এবং
৩। protected।
যেসব attributes এবং method গুলো public রাখা হবে তার সবই ঐ class এর বাইরে থেকেও access করা যাবে, আর যেসব attributes এবং method গুলো private রাখা হবে তার সবই ঐ class এর বাইরে থেকে access করা যাবে না, এবং যেসব protected রাখা হবে তা শুধু inherited করা class এর ভিতরে থেকে access করা যাবে। protected আমরা inheritance শেখার সময় ভালো করে বুঝতে পারব। public ত দেখিয়েছিই এখন private এর কাজ টি দেখব।
এখন দেখেন, আমাদের name কিন্তু public সুতরাং class এর বাইরেও যেকোন জায়গা থেকে name কিন্তু পরিবর্তন করে ফেলা যাচ্ছে। কিন্তু আমরা চাই authorized না এমন কেও এগুলো পরিবর্তন করতে পারবে না। তাহলে attributes গুলো private করে দিব। method গুলো public ই রাখতে হবে কারণ এগুলো ত class এর বাইরে থেকে access করতে হবে।
class Student { private: // these attributes are private now int bangla; int english; string name;
public: // method and constructor remain public Student(string Name, int Bangla, int English) { // constructor name = Name; bangla = Bangla; english = English; }
void printInfo() { // method cout << "Name: " << name << endl; cout << "Bangla: " << bangla << endl; cout << "English: " << english << endl; } };
int main() { Student Alice("Alice Weasley", 71, 75);
// attribute name is private so, it will cause an error Alice.name = "Princess Daisey";
/* print informations */ Alice.printInfo();
return 0; } |
Alice.name = "Princess Daisey"; এই লাইন টি এখন error দিবে কারণ name attribute private থাকায় এখন আর এটি আমরা class এর বাইরে থেকে access করতে পারব না। কিন্তু আমরা ত বলেছি যে authorized এমন কেও চাইলে তার নাম update করতে পারবে। তাহলে এটি করব কীভাবে? আমরা attributes update করার জন্য একটি method লিখে রাখতে পারি যা শুধু authorized এমন কেও ব্যবহার করতে পারবে। কে authorized এবং কে না এগুলো নিয়ে এখন তেমন মাধা গরম করার দরকার নেই। এগুলো যখন ডেভেলপমেন্টে যাবেন তখন ভালো বুঝতে পারবেন।
class Student { private: // these attributes are private now int bangla; int english; string name;
public: // method and constructor remain public // constructor Student(string Name, int Bangla, int English) { name = Name; bangla = Bangla; english = English; }
// methods void updateName(string Name) { name = Name; }
void printInfo() { cout << "Name: " << name << endl; cout << "Bangla: " << bangla << endl; cout << "English: " << english << endl; } };
int main() { Student Alice("Alice Weasley", 71, 75);
// print before update Alice.printInfo();
// update name Alice.updateName("Alice Daisey");
// print after update Alice.printInfo();
return 0; } |
আশাকরি বুঝতে পেরেছেন। তবে এটা সত্যি এরপরেও হয়ত কারো মনে স্যাটিসফ্যাকশন নাও আসতে পারে। সমস্যা নেই। এটি ভালো করে পড়ে পড়ে কোড গুলো নিজে লিখে প্র্যাক্টিস করে নিন ভালো করে। পরের টপিক গুলো কিছু পড়লেই আশাকরি অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিংয়ের গুরুত্ব ভালো করে অনুধাবন করতে পারবেন। কিছু বুঝতে সমস্যা হলে অবশ্যই কমেন্ট করতে পারেন। Happy reading...
পরের পর্বঃ এনক্যাপসুলেশন(Encapsulation)
No comments