Abstraction

অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিংয়ে (OOP) Abstraction (অ্যাবস্ট্রাকশন) হলো এমন একটি নীতি, যা কোনো জটিল সিস্টেমের পেছনের অপ্রয়োজনীয় বা ইন্টারনাল মেকানিজম লুকিয়ে রেখে শুধুমাত্র ব্যবহারকারীর জন্য প্রয়োজনীয় ফিচার বা বাহ্যিক আচরণগুলো (Essential Behavior) উন্মুক্ত করে।

সহজ কথায়, "সিস্টেমটি কী করে (What it does)" তার ওপর ফোকাস করা হয়, "কীভাবে করে (How it does it)" তা আড়াল করা হয়।

ধরো, তুমি একটি গাড়ি চালাচ্ছো। তুমি শুধু স্টিয়ারিং হুইল, ব্রেক এবং গ্যাস প্যাডেল ব্যবহার করছো। ইঞ্জিনের ভেতরে কীভাবে স্পার্ক প্লাগ কাজ করছে, গিয়ারবক্স কীভাবে ঘুরছে বা ব্রেক হাইড্রোলিক্স কীভাবে চাপ প্রয়োগ করছে—এসব জটিল প্রক্রিয়া সম্পূর্ণভাবে তোমার (ইউজারের) কাছ থেকে লুকানো থাকে (Hidden Implementation)। এখানে, গাড়ি হলো একটি Class, আর প্যাডেল বা স্টিয়ারিং হলো Public Methods বা Interface। এটাই মূলত Abstraction।

Abstraction বনাম Encapsulation

এই দুটি কনসেপ্ট প্রায়শই একসাথে ব্যবহৃত হলেও এদের মূল লক্ষ্য ভিন্ন:

বৈশিষ্ট্য

Encapsulation (এনক্যাপসুলেশন)

Abstraction (অ্যাবস্ট্রাকশন)

মূল ফোকাস

ডেটা হাইডিং (Data Hiding)।

ইমপ্লিমেন্টেশন ডিটেইলস হাইডিং (Implementation Details Hiding)।

কীভাবে অর্জন করা হয়

Access Modifiers (Private, Protected) এবং Getter/Setter এর মাধ্যমে।

Abstract Class এবং Interface এর মাধ্যমে।

উদ্দেশ্য

ডেটাকে সুরক্ষিত রাখা এবং বাইরের অনাকাঙ্ক্ষিত পরিবর্তন রোধ করা (Security & Control)।

সিস্টেমের জটিলতা কমানো এবং শুধুমাত্র প্রয়োজনীয় ইন্টারফেস দেখানো (Simplicity)।

উদাহরণ

BankAccount ক্লাসের balance ফিল্ড প্রাইভেট রাখা।

PaymentGateway এর pay() মেথড, যার ভেতরের API লজিক লুকানো।

Abstraction কেন প্রয়োজন?

সফটওয়্যার ইঞ্জিনিয়ারিংয়ে বড় এবং স্কেলেবল সিস্টেম বানাতে অ্যাবস্ট্রাকশন অপরিহার্য:

  • জটিলতা হ্রাস (Reduce Complexity): ইউজার বা অন্য কোনো মডিউল শুধু প্রয়োজনীয় মেথডগুলো দেখে, ফলে বিশাল কোডবেস বুঝতে সহজ হয়।

  • মেইনটেইনেবিলিটি (Maintainability): ব্যাকএন্ডের ইমপ্লিমেন্টেশন লজিক পরিবর্তন করলেও (যেমন ডেটাবেস মাইএসকিউএল থেকে পোস্টগ্রেএসকিউএলে নিলে) বাইরের বা ফ্রন্টএন্ডের কোড ব্রেক করে না, কারণ ইন্টারফেস একই থাকে।

  • রিইউজেবিলিটি (Reusability): অ্যাবস্ট্রাক্ট ক্লাস বা ইন্টারফেস তৈরি করে রাখলে অন্যান্য সাব-ক্লাসে খুব সহজেই সেগুলো রিইউজ বা এক্সটেন্ড করা যায়।

  • পলিমরফিজম সাপোর্ট (Polymorphism): একটি কমন ইন্টারফেস ব্যবহার করে বিভিন্ন অবজেক্টের ভিন্ন ভিন্ন রূপ (Behavior) হ্যান্ডেল করা যায়।

Abstraction কীভাবে ইমপ্লিমেন্ট করা হয়?

জাভা বা পাইথনের মতো অবজেক্ট-ওরিয়েন্টেড ভাষায় অ্যাবস্ট্রাকশন মূলত দুটি উপায়ে বাস্তবায়ন করা হয়:

১. Abstract Class (অ্যাবস্ট্রাক্ট ক্লাস)

অ্যাবস্ট্রাক্ট ক্লাস হলো এমন একটি ক্লাস যা আংশিকভাবে ইমপ্লিমেন্ট করা থাকে। এতে সাধারণ মেথড (যার বডি আছে) এবং অ্যাবস্ট্রাক্ট মেথড (যার বডি নেই) উভয়ই থাকতে পারে। কোনো ক্লাস যখন একে ইনহেরিট করে, তখন অবশ্যই অ্যাবস্ট্রাক্ট মেথডগুলোকে ওভাররাইড বা ইমপ্লিমেন্ট করতে হয়।

২. Interface (ইন্টারফেস)

ইন্টারফেস হলো একটি সম্পূর্ণ ব্লুপ্রিন্ট, যেখানে কোনো লজিক থাকে না (যদিও জাভা ৮ এর পর থেকে ডিফল্ট মেথড সাপোর্ট করে)। এটি শুধু মেথড সিগনেচার ডিক্লেয়ার করে।

Abstract Class বনাম Interface

বৈশিষ্ট্য

Abstract Class

Interface

ইমপ্লিমেন্টেশন

অ্যাবস্ট্রাক্ট এবং নন-অ্যাবস্ট্রাক্ট (কংক্রিট) উভয় মেথড থাকতে পারে।

মূলত শুধু অ্যাবস্ট্রাক্ট মেথড থাকে (সম্পূর্ণ বিমূর্ত)।

স্টেট বা ভ্যারিয়েবল

ইনস্ট্যান্স ভ্যারিয়েবল (State) এবং কনস্ট্রাক্টর থাকতে পারে।

ইনস্ট্যান্স ভ্যারিয়েবল থাকে না (জাভাতে সব ভ্যারিয়েবল public static final হয়)।

ইনহেরিটেন্স

একটি ক্লাস কেবল একটি অ্যাবস্ট্রাক্ট ক্লাসকে ইনহেরিট (extends) করতে পারে।

একটি ক্লাস একই সাথে একাধিক ইন্টারফেস ইমপ্লিমেন্ট (implements) করতে পারে।

Java Implementation

জাভাতে abstract কিওয়ার্ড ব্যবহার করে অ্যাবস্ট্রাক্ট ক্লাস ও মেথড তৈরি করা হয়। নিচে গাড়ির উদাহরণটি জাভাতে দেওয়া হলো:

// Abstract class hiding the common logic and exposing a contract
public abstract class Vehicle {
    protected int speed;

    // Concrete method: Implementation is shared among child classes
    public void setSpeed(int speed) {
        this.speed = speed;
    }

    // Abstract method: Hides HOW it moves, forces child classes to define it
    public abstract void move();
}

// Child class providing specific implementation
public class Car extends Vehicle {
    @Override
    public void move() {
        System.out.println("Car is moving on 4 wheels at " + this.speed + " km/h");
    }
}

// Child class providing another specific implementation
public class Bike extends Vehicle {
    @Override
    public void move() {
        System.out.println("Bike is moving on 2 wheels at " + this.speed + " km/h");
    }
}

public class Main {
    public static void main(String[] args) {
        // Users interact with the abstraction (Vehicle), not worrying about internals
        Vehicle myCar = new Car();
        myCar.setSpeed(100);
        myCar.move(); // Output: Car is moving on 4 wheels at 100 km/h

        Vehicle myBike = new Bike();
        myBike.setSpeed(50);
        myBike.move(); // Output: Bike is moving on 2 wheels at 50 km/h
    }
}

Python Implementation

পাইথনে বিল্ট-ইন abstract কিওয়ার্ড নেই। এর পরিবর্তে abc (Abstract Base Classes) মডিউল ব্যবহার করে অ্যাবস্ট্রাকশন বাস্তবায়ন করতে হয়।

from abc import ABC, abstractmethod


class Vehicle(ABC):
    """Abstract base class representing a generic vehicle."""

    def __init__(self) -> None:
        self._speed = 0

    # Concrete method shared by all vehicles
    def set_speed(self, speed: int) -> None:
        self._speed = speed

    # Abstract method acting as a blueprint
    @abstractmethod
    def move(self) -> None:
        pass


class Car(Vehicle):
    """Concrete implementation for a Car."""

    def move(self) -> None:
        print(f"Car is moving on 4 wheels at {self._speed} km/h")


class Bike(Vehicle):
    """Concrete implementation for a Bike."""

    def move(self) -> None:
        print(f"Bike is moving on 2 wheels at {self._speed} km/h")


if __name__ == "__main__":
    # vehicle = Vehicle() # TypeError: Can't instantiate abstract class

    car = Car()
    car.set_speed(100)
    car.move()

    bike = Bike()
    bike.set_speed(50)
    bike.move()