Factory Design Pattern

ধরো, তুমি একটি বিশাল গাড়ির কোম্পানি খুলেছ, যেখানে Audi, BMW, এবং Toyota-এর মতো বিভিন্ন ব্র্যান্ডের গাড়ি তৈরি হয়। এখন তুমি যদি প্রতিটি গাড়ি বানানোর জন্য আলাদা আলাদা মেকানিক বা কারিগর নিয়োগ করো এবং ক্লায়েন্টকে সরাসরি ওই কারিগরের কাছে গিয়ে গাড়ি বানিয়ে নিতে হয়, তবে পুরো প্রক্রিয়াটি অত্যন্ত বিশৃঙ্খল হয়ে পড়বে।

সফটওয়্যার ইঞ্জিনিয়ারিংয়ে ঠিক একই ঘটনা ঘটে। তুমি যখন কোডের বিভিন্ন জায়গায় সরাসরি new কিওয়ার্ড (বা ক্লাস কল করে) অবজেক্ট তৈরি করো, তখন তোমার মূল লজিকটি ওই নির্দিষ্ট ক্লাসের সাথে টাইটলি কাপলড (Tightly Coupled) হয়ে যায়। এই সমস্যার সমাধান হিসেবেই তৈরি হয়েছে Factory Design Pattern।

এতে ক্লায়েন্টকে জানতে হয় না যে পেছনের মেকানিক কীভাবে গাড়ি বানাচ্ছে; ক্লায়েন্ট শুধু কারখানায় (Factory) গিয়ে বলে তার কোন মডেলটি চাই, আর কারখানা তাকে রেডিমেড গাড়িটি বুঝিয়ে দেয়।

Factory Design Pattern কী?

Factory Pattern হলো একটি Creational Design Pattern। এর মূল কাজ হলো অবজেক্ট তৈরির দায়িত্ব নিজের কাঁধে তুলে নেওয়া। ক্লায়েন্ট কোড (যেখানে অবজেক্ট ব্যবহার করা হবে) সরাসরি ক্লাসের ইনস্ট্যান্স বা অবজেক্ট তৈরি না করে, একটি নির্দিষ্ট "Factory Method" বা "Factory Class"-এর মাধ্যমে অবজেক্ট তৈরি করে নেয়।

সফটওয়্যার ইঞ্জিনিয়ারিংয়ে মূলত এর দুটি রূপ বেশি দেখা যায়: ১. Simple Factory: একটি সেন্ট্রাল ক্লাস থাকে, যা কন্ডিশন (if-else বা switch) চেক করে অবজেক্ট রিটার্ন করে। ২. Factory Method: অবজেক্ট তৈরির জন্য একটি ইন্টারফেস থাকে এবং সাবক্লাসগুলো ঠিক করে যে কোন অবজেক্টটি তৈরি করা হবে। (এটি Open/Closed Principle বেশি ভালোভাবে মেনে চলে)।

কখন এবং কেন Factory Pattern ব্যবহার করবে?

  • অবজেক্ট তৈরির কমপ্লেক্স লজিক লুকাতে: একটি অবজেক্ট তৈরি করতে যদি অনেকগুলো ডিপেন্ডেন্সি বা কনফিগারেশন সেটআপ করতে হয়, তবে ক্লায়েন্ট কোড থেকে সেই জঞ্জাল সরিয়ে Factory-তে নিয়ে যাওয়া ভালো।

  • Loose Coupling অর্জন করতে: ক্লায়েন্ট কোড শুধুমাত্র ইন্টারফেসের ওপর নির্ভর করবে (Dependency Inversion), কোনো নির্দিষ্ট কনক্রিট (Concrete) ক্লাসের ওপর নয়।

  • সেন্ট্রালাইজড ম্যানেজমেন্ট: ভবিষ্যতে যদি নতুন কোনো গাড়ি (যেমন: Tesla) যুক্ত করতে হয়, তবে পুরো প্রজেক্ট না ঘেঁটে শুধু Factory ক্লাসে আপডেট করলেই কাজ হয়ে যায়।

Simple Factory Pattern

নিচে পাইথন (Python) ব্যবহার করে তোমার দেওয়া গাড়ির উদাহরণটি ইমপ্লিমেন্ট করা হলো। (কোড ব্লকের ভেতরে সবকিছু ইংরেজিতে রাখা হয়েছে)।

from abc import ABC, abstractmethod

# Step 1: Parent Interface (Abstraction)
class Car(ABC):
    @abstractmethod
    def get_type(self) -> str:
        pass

# Step 2: Concrete Classes
class Audi(Car):
    def get_type(self) -> str:
        return "This is an Audi Car. Engineered in Germany."

class BMW(Car):
    def get_type(self) -> str:
        return "This is a BMW Car. The Ultimate Driving Machine."

class Toyota(Car):
    def get_type(self) -> str:
        return "This is a Toyota Car. Reliable and Efficient."

# Step 3: Factory Class
class CarFactory:
    @staticmethod
    def create_car(car_type: str) -> Car:
        # Centralized object creation logic
        if car_type.lower() == 'audi':
            return Audi()
        elif car_type.lower() == 'bmw':
            return BMW()
        elif car_type.lower() == 'toyota':
            return Toyota()
        else:
            raise ValueError(f"Error: '{car_type}' is an invalid Car Type")

# Step 4: Client Code
if __name__ == "__main__":
    try:
        # The client does not use Audi() or BMW() directly. 
        # It asks the factory to do the heavy lifting.
        my_first_car = CarFactory.create_car('audi')
        print(my_first_car.get_type())

        my_second_car = CarFactory.create_car('toyota')
        print(my_second_car.get_type())

        # Trying to create an unsupported car
        dream_car = CarFactory.create_car('tesla')
        print(dream_car.get_type())

    except ValueError as e:
        print(e)

আধুনিক ফ্রেমওয়ার্কগুলোতে Factory Pattern-এর ব্যবহার

তুমি যখন বড় কোনো প্রজেক্ট বা ফ্রেমওয়ার্ক নিয়ে কাজ করবে, তখন দেখবে এর কোর আর্কিটেকচারে Factory Pattern কীভাবে জড়িয়ে আছে।

Django তে Factory এর ব্যবহার (Python)

  • ORM QuerySet Factory: জ্যাঙ্গো ওআরএম-এ যখন তুমি User.objects.filter(is_active=True) কল করো, তখন ওই objects (ম্যানেজার) মূলত একটি ফ্যাক্টরি হিসেবে কাজ করে, যা তোমার রিকোয়েস্ট অনুযায়ী নির্দিষ্ট QuerySet অবজেক্ট তৈরি করে রিটার্ন করে।

  • Middleware Factory: জ্যাঙ্গোতে মিডলওয়্যারগুলো ইনিশিয়ালাইজ করার সময় ফ্রেমওয়ার্ক ফ্যাক্টরি প্যাটার্ন অনুসরণ করে প্রতিটি রিকোয়েস্ট ও রেসপন্স হ্যান্ডেল করার জন্য চেইন তৈরি করে।

  • Form Factory (modelform_factory): জ্যাঙ্গোতে মডেল থেকে ডাইনামিকভাবে ফর্ম ক্লাস তৈরি করার জন্য modelform_factory ফাংশন ব্যবহার করা হয়, যা প্যাটার্নটির একটি ক্লাসিক উদাহরণ।

Factory Design Pattern মূলত কোডবেসকে অনেক বেশি ক্লিন এবং মেইনটেইনেবল করে। বড় প্রজেক্টে অবজেক্ট ক্রিয়েশনের এই ঝামেলাগুলো Factory-র হাতে ছেড়ে দিলে তুমি ডেভেলপার হিসেবে মূল বিজনেস লজিকের দিকে নিশ্চিন্তে ফোকাস করতে পারবে।