Observer Design Pattern

ধরো, তুমি একটি জনপ্রিয় ইউটিউব (YouTube) চ্যানেল চালাচ্ছো। প্রতিদিন হাজার হাজার মানুষ তোমার চ্যানেল সাবস্ক্রাইব করছে। এখন তুমি যখনই নতুন কোনো ভিডিও আপলোড করো, তোমার সব সাবস্ক্রাইবারের কাছে স্বয়ংক্রিয়ভাবে একটি নোটিফিকেশন চলে যায়।

একবার ভেবে দেখো, ইউটিউব কীভাবে বোঝে যে কাকে কাকে নোটিফিকেশন পাঠাতে হবে? তুমি কি ম্যানুয়ালি ধরে ধরে সবাইকে মেসেজ পাঠাও? মোটেও না! সাবস্ক্রাইবাররা মূলত নিজেদেরকে তোমার চ্যানেলের সাথে যুক্ত (Attach) করে রেখেছে। যখনই চ্যানেলে নতুন ভিডিও আসে (অর্থাৎ চ্যানেলের State পরিবর্তন হয়), তখন সিস্টেম স্বয়ংক্রিয়ভাবে সবাইকে আপডেট জানিয়ে দেয়।

সফটওয়্যার ইঞ্জিনিয়ারিংয়ে ঠিক এই মেকানিজমটিকেই বলা হয় Observer Design Pattern।

Observer Design Pattern কী?

Observer Pattern হলো একটি Behavioral Design Pattern, যা অবজেক্টগুলোর মধ্যে একটি One-to-Many (একের সাথে বহুর) ডিপেন্ডেন্সি বা সম্পর্ক তৈরি করে। এর ফলে যদি কোনো একটি অবজেক্টের অবস্থার (State) পরিবর্তন ঘটে, তবে তার ওপর নির্ভরশীল বাকি সমস্ত অবজেক্ট স্বয়ংক্রিয়ভাবে নোটিফাইড এবং আপডেটেড হয়ে যায়।

এর মূল উপাদান তিনটি:

১. Subject (Publisher): যার ওপর অন্যেরা নজর রাখে (যেমন: YouTube Channel)। এটি সাবস্ক্রাইবারদের যুক্ত করা, বাদ দেওয়া এবং নোটিফাই করার কাজ মেইনটেইন করে।

২. Observer (Subscriber): যারা পরিবর্তনের জন্য অপেক্ষা করে (যেমন: চ্যানেলের সাবস্ক্রাইবার)।

৩. Update Mechanism: সাবজেক্টের কোনো পরিবর্তন হলে নোটিফিকেশন পাঠানোর মেথড।

কেন এবং কখন এটি ব্যবহার করবে?

সফটওয়্যার ডেভেলপমেন্টে আমরা প্রায়ই এমন পরিস্থিতির মুখোমুখি হই, যেখানে একটি ইভেন্ট ঘটলে সিস্টেমের অন্যান্য অংশে তার রিঅ্যাকশন বা প্রভাব পড়তে হয়। যদি তুমি এই কাজটি হার্ডকোড (Hardcode) করে করো, তবে কোডগুলো হাইলি কাপলড (Tightly Coupled) হয়ে যাবে।

Observer Pattern ব্যবহার করা উচিত যখন:

  • Decoupling প্রয়োজন: তুমি চাও না পাবলিশার জানুক সাবস্ক্রাইবাররা কে বা তারা কীভাবে ডেটা প্রসেস করে।

  • Real-time Updates: স্টক মার্কেটের দাম পরিবর্তন হলে সকল বিনিয়োগকারীর ড্যাশবোর্ড আপডেট করা।

  • Event-Driven Systems: ই-কমার্সে কেউ অর্ডার প্লেস করলে ইনভেন্টরি, শিপিং এবং ইমেইল মডিউলকে একসাথে ট্রিগার করা।

Python Code Example: YouTube Subscription System

Observer Pattern ইমপ্লিমেন্ট করার জন্য আমরা পাইথনের ABC (Abstract Base Class) মডিউল ব্যবহার করে সাবজেক্ট এবং অবজার্ভারের ইন্টারফেস তৈরি করব। (কোডের ভেতরের সবকিছু সম্পূর্ণ ইংরেজিতে রাখা হলো)।

from abc import ABC, abstractmethod

# ==========================================
# Step 1: Define Interfaces (Abstractions)
# ==========================================
class Subject(ABC):
    @abstractmethod
    def subscribe(self, observer):
        pass

    @abstractmethod
    def unsubscribe(self, observer):
        pass

    @abstractmethod
    def notify_subscribers(self, message: str):
        pass

class Observer(ABC):
    @abstractmethod
    def update(self, message: str):
        pass

# ==========================================
# Step 2: Concrete Subject (Publisher)
# ==========================================
class YouTubeChannel(Subject):
    def __init__(self, channel_name: str):
        self.channel_name = channel_name
        self._subscribers = [] # List to hold all observers

    def subscribe(self, observer: Observer):
        if observer not in self._subscribers:
            self._subscribers.append(observer)
            print(f"[SYSTEM] A new user subscribed to {self.channel_name}")

    def unsubscribe(self, observer: Observer):
        if observer in self._subscribers:
            self._subscribers.remove(observer)
            print(f"[SYSTEM] A user unsubscribed from {self.channel_name}")

    def notify_subscribers(self, message: str):
        print(f"\n--- {self.channel_name} is broadcasting a new update! ---")
        for subscriber in self._subscribers:
            subscriber.update(message)

# ==========================================
# Step 3: Concrete Observers (Subscribers)
# ==========================================
class RegisteredUser(Observer):
    def __init__(self, username: str):
        self.username = username

    def update(self, message: str):
        print(f"Hey {self.username}, Notification: {message}")

# ==========================================
# Step 4: Testing the Pattern
# ==========================================
if __name__ == "__main__":
    # Create the publisher
    tech_channel = YouTubeChannel("Tech Backend Masterclass")

    # Create subscribers
    user1 = RegisteredUser("Rahim")
    user2 = RegisteredUser("Karim")
    user3 = RegisteredUser("Sumon")

    # Users subscribe to the channel
    tech_channel.subscribe(user1)
    tech_channel.subscribe(user2)
    tech_channel.subscribe(user3)

    # Publisher uploads a new video (State changes)
    tech_channel.notify_subscribers("New Video Uploaded: Understanding Python Design Patterns!")

    # User2 decides to unsubscribe
    print("\n")
    tech_channel.unsubscribe(user2)

    # Publisher uploads another video
    tech_channel.notify_subscribers("Live Stream: Q&A on Backend Architecture!")

আউটপুট থেকে কী শিখলাম? যখন প্রথম ভিডিওটি আপলোড হলো, তখন Rahim, Karim এবং Sumon তিনজনেই নোটিফিকেশন পেয়েছে। কিন্তু যখন Karim আনসাবস্ক্রাইব করল, তখন দ্বিতীয় ভিডিওর নোটিফিকেশন শুধুমাত্র Rahim এবং Sumon পেয়েছে। এখানে YouTubeChannel ক্লাসটি জানেই না RegisteredUser কীভাবে মেসেজটি প্রসেস করছে, এটি শুধু ডেটা পুশ (Push) করে দিচ্ছে। এটাই Low Coupling-এর চমৎকার একটি উদাহরণ।

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

তুমি যদি মডার্ন ব্যাকএন্ড ফ্রেমওয়ার্ক নিয়ে কাজ করো, তবে দেখবে এই প্যাটার্নটি ফ্রেমওয়ার্কের কোর আর্কিটেকচারে দারুণভাবে মেশানো আছে:

  • Django Signals (Python): জ্যাঙ্গোতে মডেল সেভ বা ডিলিট হওয়ার সময় (যেমন: post_save, pre_delete) সিগন্যাল ফায়ার হয়। তুমি আলাদা ফাইলে রিসিভার (লিসেনার/অবজার্ভার) লিখে রাখতে পারো, যা ওই সিগন্যাল পেলেই নির্দিষ্ট কাজ করবে।

  • Spring Boot ApplicationEvents (Java): স্প্রিং ফ্রেমওয়ার্কে তুমি কাস্টম ইভেন্ট তৈরি করে তা পাবলিশ করতে পারো এবং @EventListener অ্যানোটেশন ব্যবহার করে অন্য সার্ভিস থেকে সেই ইভেন্ট লিসেন করতে পারো।

  • Frontend State Management: Vue.js, React.js বা Angular-এ স্টেট ম্যানেজমেন্ট (যেমন: Redux, Vuex) মূলত এই প্যাটার্নের ওপর ভিত্তি করেই কাজ করে। স্টেট পরিবর্তন হলে সমস্ত রিলেটেড কম্পোনেন্ট স্বয়ংক্রিয়ভাবে রি-রেন্ডার হয়।

Observer Pattern বুঝতে পারা মানেই হলো রিয়েল-টাইম নোটিফিকেশন এবং ইভেন্ট-ড্রিভেন (Event-driven) স্কেলেবল আর্কিটেকচার তৈরি করার সক্ষমতা অর্জন করা।