
অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং শেখার সময় বেশিরভাগ শিক্ষার্থী সংজ্ঞা মুখস্থ করে ফেলেন। ক্লাস মানে নকশা, অবজেক্ট মানে সেই নকশা থেকে বানানো জিনিস, এই কথাগুলো সবাই বলতে পারেন। কিন্তু প্রশ্ন করলে বেশিরভাগই বলতে পারেন না, ফিল্ডটি private রাখলে বাস্তবে কী লাভ হলো, বা Inheritance না থাকলে কোন সমস্যায় পড়তাম।
এই টিউনে আমরা সংজ্ঞা দিয়ে শুরু করব না। বরং একটি ছোট ব্যাংক অ্যাকাউন্ট প্রোগ্রাম ধাপে ধাপে বানাব, আর প্রতিবার যখন কোনো সমস্যায় পড়ব তখন OOP এর একটি করে বৈশিষ্ট্য এনে সেই সমস্যার সমাধান করব। শেষে আপনার হাতে একটি চলমান প্রোগ্রাম থাকবে এবং কেন OOP দরকার সেই উত্তরটিও থাকবে।
আমাদের প্রোগ্রামে থাকবে দুই ধরনের ব্যাংক অ্যাকাউন্ট। সাধারণ অ্যাকাউন্টে টাকা জমা ও উত্তোলন করা যাবে, আর সেভিংস অ্যাকাউন্টে বাড়তি নিয়ম থাকবে, সেখানে সুদ যোগ হবে এবং সবসময় একটি ন্যূনতম টাকা রাখতেই হবে।
ক্লাস হলো নকশা আর অবজেক্ট হলো সেই নকশা মেনে বানানো আসল জিনিস। একটি ক্লাস একবার লিখে আপনি হাজারটি অ্যাকাউন্ট বানাতে পারবেন, প্রতিটির তথ্য আলাদা থাকবে।
class BankAccount {private final String accountNumber; private final String holderName; private double balance;}Constructor হলো সেই বিশেষ মেথড যা অবজেক্ট তৈরির মুহূর্তে চলে। এর কাজ হলো নিশ্চিত করা যে অবজেক্টটি জন্মের সময়ই বৈধ অবস্থায় থাকে, অর্ধেক তথ্য নিয়ে যেন তৈরি না হয়।
public BankAccount(String accountNumber, String holderName, double openingBalance) {this.accountNumber = accountNumber; this.holderName = holderName; this.balance = openingBalance;}এখন সবচেয়ে গুরুত্বপূর্ণ অংশ। ব্যালেন্স যদি public হতো, তাহলে প্রোগ্রামের যেকোনো জায়গা থেকে কেউ লিখে দিতে পারত ব্যালেন্স সমান দশ লাখ। Encapsulation মানে হলো ডেটা লুকিয়ে রেখে শুধু নিয়ন্ত্রিত পথে তাতে হাত দিতে দেওয়া।
public void deposit(double amount) {if (amount <= 0) {System.out.println("জমার পরিমাণ শূন্যের বেশি হতে হবে"); return;} balance = balance + amount; System.out.println(amount + " টাকা জমা হয়েছে");} public void withdraw(double amount) {if (amount > balance) {System.out.println("ব্যালেন্স যথেষ্ট নয়"); return;} balance = balance - amount; System.out.println(amount + " টাকা উত্তোলন হয়েছে");} public double getBalance() {return balance;} public String getHolderName() {return holderName;}ব্যালেন্স বদলানোর একমাত্র রাস্তা এখন deposit ও withdraw মেথড, আর সেই দুই রাস্তাতেই পাহারা বসানো আছে। ভবিষ্যতে যদি নিয়ম বদলায়, যেমন প্রতিবার উত্তোলনে দশ টাকা চার্জ কাটতে হবে, তাহলে শুধু একটি মেথডে পরিবর্তন করলেই পুরো প্রোগ্রামে সেটি কার্যকর হবে।
অবজেক্ট সরাসরি ছাপালে জাভা ক্লাসের নাম আর একটি হেক্সাডেসিমেল কোড দেখায়, যা পড়ে কিছু বোঝা যায় না। toString মেথডটি নিজের মতো করে লিখে নিলে সমস্যাটি মিটে যায়।
@Override public String toString() {return holderName + " (" + accountNumber + ") ব্যালেন্স " + balance;}সেভিংস অ্যাকাউন্টেও জমা, উত্তোলন আর ব্যালেন্স লাগবে। পুরো কোড আবার লেখার বদলে আমরা BankAccount ক্লাসটিকে extends করব, ফলে সব সুবিধা এমনিতেই পাওয়া যাবে, শুধু নতুন নিয়মটুকু যোগ করলেই হবে।
class SavingsAccount extends BankAccount {private final double interestRate; public SavingsAccount(String accountNumber, String holderName, double openingBalance, double interestRate) {super(accountNumber, holderName, openingBalance); this.interestRate = interestRate;} public void addInterest() {double interest = getBalance() * interestRate / 100; deposit(interest);} @Override public void withdraw(double amount) {if (getBalance() - amount < 500) {System.out.println("সেভিংস অ্যাকাউন্টে অন্তত ৫০০ টাকা রাখতে হবে"); return;} super.withdraw(amount);}দুটি ক্লাস আলাদা হলেও দুটোই BankAccount ধরনের। তাই একই অ্যারেতে দুটোকেই রাখা যায়, আর লুপ চালালে জাভা নিজেই বুঝে নেয় কোন অবজেক্টের কোন মেথডটি চালাতে হবে।
public class BankApp {public static void main(String[] args) {BankAccount current = new BankAccount("CA-1001", "নাছিরুল", 2000); SavingsAccount savings = new SavingsAccount("SA-2001", "রুমানা", 5000, 5); current.deposit(1500); current.withdraw(1000); savings.withdraw(4800); savings.addInterest(); BankAccount[] accounts = {current, savings}; for (BankAccount account : accounts) {System.out.println(account);}প্রোগ্রামটি রান করলে কনসোলে নিচের লেখাগুলো আসবে। সেভিংস অ্যাকাউন্ট থেকে ৪৮০০ টাকা তোলার চেষ্টা আটকে গেছে, কারণ তাতে ব্যালেন্স ৫০০ এর নিচে নেমে যেত।
1500.0 টাকা জমা হয়েছে 1000.0 টাকা উত্তোলন হয়েছে সেভিংস অ্যাকাউন্টে অন্তত ৫০০ টাকা রাখতে হবে 250.0 টাকা জমা হয়েছে নাছিরুল (CA-1001) ব্যালেন্স 2500.0 রুমানা (SA-2001) ব্যালেন্স 5250.0
প্যারেন্ট ক্লাসে যদি প্যারামিটারসহ Constructor থাকে, তাহলে চাইল্ড ক্লাসে super দিয়ে সেটি ডাকা বাধ্যতামূলক। না ডাকলে কম্পাইলার বলবে প্যারেন্ট ক্লাসে খালি Constructor নেই। super এর লাইনটি অবশ্যই Constructor এর একদম প্রথম লাইনে বসাতে হবে।
account.balance লিখলে কম্পাইলার বলবে balance has private access। এটি ভুল নয়, বরং এটাই Encapsulation কাজ করছে তার প্রমাণ। মান দরকার হলে getBalance ব্যবহার করুন, বদলাতে চাইলে deposit বা withdraw ব্যবহার করুন।
শেখার জন্য double ঠিক আছে, কিন্তু বাস্তব আর্থিক প্রজেক্টে দশমিকের হিসাবে সামান্য ভুল জমতে থাকে। সেখানে BigDecimal ব্যবহার করাই নিয়ম, অথবা টাকার হিসাব পয়সায় রূপ দিয়ে long টাইপে রাখা হয়।
খেয়াল করে দেখুন, আমরা একবারও OOP এর সংজ্ঞা মুখস্থ করিনি। তবু ক্লাস, অবজেক্ট, Constructor, Encapsulation, Inheritance আর Polymorphism, ছয়টি ধারণাই ব্যবহার হয়ে গেছে এবং প্রতিটির পেছনে একটি বাস্তব কারণ ছিল। এভাবে শিখলে পরীক্ষার খাতায় নয়, আসল প্রজেক্টেও কাজে লাগবে।
এবার আপনি নিজে চেষ্টা করুন, একটি LoanAccount ক্লাস বানান যেখানে ব্যালেন্স ঋণাত্মক হতে পারে। কোথায় আটকে যাচ্ছেন টিউমেন্টে জানান। এই প্রোগ্রামটি রান করে নিজেই নতুন নিয়ম যোগ করুন, তাহলেই OOP এর সুবিধাটি হাতে কলমে ধরা পড়বে।
আমি নাছিরুল হক। বিশ্বের সর্ববৃহৎ বিজ্ঞান ও প্রযুক্তির সৌশল নেটওয়ার্ক - টেকটিউনস এ আমি 15 ঘন্টা 26 মিনিট যাবৎ যুক্ত আছি। টেকটিউনস আমি এ পর্যন্ত 9 টি টিউন ও 0 টি টিউমেন্ট করেছি। টেকটিউনসে আমার 0 ফলোয়ার আছে এবং আমি টেকটিউনসে 0 টিউনারকে ফলো করি।