Observer — একটি আচরণগত প্যাটার্ন যেখানে একটি অবজেক্ট (প্রকাশক) তার অবস্থার পরিবর্তন সম্পর্কে একাধিক সাবস্ক্রাইবারকে অবহিত করে। মোবাইল ডেভেলপমেন্টে, Observer রিঅ্যাকটিভ মেকানিজমের ভিত্তি: UI ডেটা পরিবর্তনে সাবস্ক্রাইব করে এবং স্বয়ংক্রিয়ভাবে আপডেট হয়। প্যাটার্নটি iOS-এ NotificationCenter এবং Android-এ LiveData/Flow-এ বাস্তবায়িত। আরও বিস্তারিত Refactoring Guru: Observer-এ।
মূল পয়েন্ট
Observer — একটি GoF আচরণগত প্যাটার্ন যা অবজেক্টগুলির মধ্যে এক-থেকে-অনেক নির্ভরতা সংজ্ঞায়িত করে। যখন একটি অবজেক্ট (Subject বা Observable) তার অবস্থা পরিবর্তন করে, তখন সমস্ত নির্ভরশীল অবজেক্ট (Observers) স্বয়ংক্রিয়ভাবে অবহিত এবং আপডেট হয়। প্যাটার্নটি শিথিল সংযুক্তি বাস্তবায়ন করে: প্রকাশক সাবস্ক্রাইবারদের নির্দিষ্ট ক্লাস জানে না — শুধু যে তারা Observer ইন্টারফেস বাস্তবায়ন করে।
Observer গঠন-এ attach(), detach(), notify() মেথড সহ Subject ইন্টারফেস এবং update() মেথড সহ Observer ইন্টারফেস অন্তর্ভুক্ত। ConcreteSubject অবস্থা এবং সাবস্ক্রাইবার তালিকা সংরক্ষণ করে। ConcreteObserver update() বাস্তবায়ন করে এবং পরিবর্তনে সাড়া দেয়। মোবাইল ডেভেলপমেন্টে, GoF-এর ক্লাসিক বাস্তবায়ন বিরল — এটি অন্তর্নির্মিত প্রক্রিয়া দ্বারা প্রতিস্থাপিত হয়: NotificationCenter, Combine, Flow, LiveData, যা আধুনিক API-এর সাথে একই ধারণা বাস্তবায়ন করে।
Push vs Pull মডেল — Push মডেলে, Subject সমস্ত সাবস্ক্রাইবারকে ডেটা পাঠায় (NotificationCenter.post)। Pull মডেলে, Subject শুধু অবহিত করে, এবং সাবস্ক্রাইবার নিজেই ডেটা অনুরোধ করে। Android LiveData Push ব্যবহার করে (ডেটা observe()-এ পাস করা হয়), RxJava/Flow উভয় মডেল সমর্থন করে। পছন্দ কাজের উপর নির্ভর করে: Push UI আপডেটের জন্য সহজ, Pull ডেটার বড় ভলিউমের জন্য বেশি কার্যকর যা সাবস্ক্রাইবার গ্রহণ করতে নাও চাইতে পারে।
NotificationCenter — Observer বাস্তবায়নের জন্য iOS/macOS-এ একটি অন্তর্নির্মিত প্রক্রিয়া। প্রকাশক NotificationCenter.default.post(name:, object:, userInfo:) এর মাধ্যমে একটি Notification পাঠায়। সাবস্ক্রাইবার addObserver(forName:, queue:, using:) এর মাধ্যমে নিবন্ধন করে। NotificationCenter নামকৃত বিজ্ঞপ্তি (Notification.Name) সমর্থন করে এবং userInfo-তে যেকোনো ডেটা পাস করতে পারে। UIKeyboardWillShowNotification, UIApplicationDidEnterBackgroundNotification — সিস্টেম উদাহরণ।
extension Notification.Name {
static let userDidLogin = Notification.Name("userDidLogin")
}
// প্রকাশক
NotificationCenter.default.post(
name: .userDidLogin,
object: nil,
userInfo: ["userId": "123"]
)
// সাবস্ক্রাইবার
class ProfileViewModel {
private var observers: [NSObjectProtocol] = []
func startObserving() {
let observer = NotificationCenter.default.addObserver(
forName: .userDidLogin,
object: nil,
queue: .main
) { [weak self] notification in
guard let userId = notification.userInfo?["userId"] as? String else { return }
// সাবস্ক্রাইবার ইভেন্টে সাড়া দেয়
self?.loadProfile(userId: userId)
}
observers.append(observer)
}
func stopObserving() {
observers.forEach { NotificationCenter.default.removeObserver($0) }
observers.removeAll()
}
}
Combine ফ্রেমওয়ার্ক — NotificationCenter-এর একটি আধুনিক রিঅ্যাকটিভ বিকল্প, যা iOS 13-এ প্রবর্তিত। Publisher (NotificationCenter, URLSession, Timer) — প্রকাশক, Subscriber (sink, assign) — সাবস্ক্রাইবার। Combine ডেটা স্ট্রিম রূপান্তরের জন্য অপারেটর (map, filter, combineLatest) যোগ করে। @Published — একটি প্রপার্টি র্যাপার যা স্বয়ংক্রিয়ভাবে সাবস্ক্রাইবারদের পরিবর্তন সম্পর্কে অবহিত করে। SwiftUI-এর সাথে MVVM-এ, Combine ViewModel এবং View-কে সংযুক্ত করার জন্য NotificationCenter-এর স্থান নেয়।
KVO (Key-Value Observing) — অবজেক্টের পৃথক বৈশিষ্ট্য পর্যবেক্ষণের জন্য একটি পুরানো ObjC/Swift প্রক্রিয়া। @objc dynamic var name: String — একটি পর্যবেক্ষণযোগ্য বৈশিষ্ট্য। observe(.name) — সাবস্ক্রিপশন। KVO শুধুমাত্র @objc-সামঞ্জস্যপূর্ণ ক্লাস এবং ObjC উত্তরাধিকারের সাথে কাজ করে। Apple নতুন প্রজেক্টে KVO-এর পরিবর্তে Combine এবং @Published সুপারিশ করে। KVO হাইব্রিড প্রজেক্টে UIKit সামঞ্জস্যের জন্য প্রাসঙ্গিক রয়ে গেছে।
LiveData — Observer বাস্তবায়নের জন্য Android Architecture Components-এর একটি উপাদান। একটি পর্যবেক্ষণযোগ্য ক্লাস যা সাবস্ক্রাইবারদের ডেটা পরিবর্তন সম্পর্কে অবহিত করে। LiveData লাইফসাইকেল-সচেতন: সাবস্ক্রাইবাররা (LifecycleOwner) ধ্বংস হলে স্বয়ংক্রিয়ভাবে সাবস্ক্রিপশন বাতিল করে। LiveData Push মডেল ব্যবহার করে: ডেটা observe()-এ পাস করা হয়। Jetpack Compose-এর আগে Android-এ LiveData MVVM-এর মৌলিক বিল্ডিং ব্লক।
// ViewModel — প্রকাশক
class UserViewModel : ViewModel() {
private val _user = MutableLiveData<User?>(null)
val user: LiveData<User?> = _user
fun loadUser(id: String) {
viewModelScope.launch {
val result = userRepository.getUser(id)
_user.value = result
}
}
}
// Fragment — সাবস্ক্রাইবার
class UserFragment : Fragment() {
private val viewModel: UserViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.user.observe(viewLifecycleOwner) { user ->
// সাবস্ক্রাইবার পরিবর্তনে সাড়া দেয়
userName.text = user?.name
userEmail.text = user?.email
}
}
}
StateFlow এবং SharedFlow — Kotlin Coroutines-এর রিঅ্যাকটিভ টাইপ যা Jetpack Compose-এ LiveData-কে প্রতিস্থাপন করেছে। StateFlow — একটি নির্দিষ্ট বর্তমান মান সহ পর্যবেক্ষণযোগ্য অবস্থা ধারক। SharedFlow — অবস্থা ছাড়া একটি কনফিগারযোগ্য হট ফ্লো, এককালীন ইভেন্টের (ন্যাভিগেশন, টোস্ট) জন্য উপযুক্ত। উভয় টাইপ Compose-এর সাথে নিবিড়ভাবে সংহত: collectAsState(), collectAsEffect()। Compose-এর সাথে আধুনিক Android প্রজেক্টে StateFlow বাধ্যতামূলক।
LiveData বনাম StateFlow — LiveData Android Lifecycle-এর সাথে আবদ্ধ, StateFlow প্ল্যাটফর্ম-স্বাধীন। StateFlow coroutines, অপারেটর (map, filter) সমর্থন করে এবং Android নির্ভরতা ছাড়া পরীক্ষা করা যায়। LiveData Java সামঞ্জস্যের জন্য সহজ। Google Kotlin + Compose-এ নতুন প্রজেক্টের জন্য StateFlow এবং পুরানো প্রজেক্ট বা Java কোডের জন্য LiveData সুপারিশ করে।
মেমরি লিক — সঠিক সাবস্ক্রিপশন ব্যবস্থাপনা ছাড়া Observer-এর প্রধান সমস্যা। যদি কোনো সাবস্ক্রাইবার (Activity, Fragment, UIViewController) ধ্বংস হয় কিন্তু সাবস্ক্রিপশন বাতিল না হয়, তাহলে প্রকাশক তার রেফারেন্স ধরে রাখে এবং আবর্জনা সংগ্রহকারী মেমরি মুক্ত করতে পারে না। Android-এ, LifecycleOwner (Activity/Fragment) কে removeObserver() কল করা উচিত বা observe(viewLifecycleOwner) ব্যবহার করা উচিত। iOS-এ — deinit-এ removeObserver বা Combine-এ disposeBag।
| প্ল্যাটফর্ম | Observer প্রক্রিয়া | স্বয়ংক্রিয় সাবস্ক্রিপশন বাতিল | ম্যানুয়াল সাবস্ক্রিপশন বাতিল |
|---|---|---|---|
| iOS | NotificationCenter | না | deinit-এ removeObserver() |
| iOS | Combine (sink) | না | store(in: &bag) — DisposeBag |
| iOS | KVO | না | deinit-এ removeObserver() |
| Android | LiveData | হ্যাঁ (LifecycleOwner) | removeObserver() ঐচ্ছিক |
| Android | StateFlow | viewModelScope-এর মাধ্যমে | বাতিলে cancel() Job |
| Android | RxJava | না | CompositeDisposable-এ dispose() |
সাবস্ক্রাইবারে দুর্বল রেফারেন্স — সাবস্ক্রিপশন ব্লকে ক্লোজার ব্যবহার করার সময়, Swift-এ [weak self] ব্যবহার করুন এবং Kotlin-এ লাইফসাইকেল স্কোপ উল্লেখ করুন। LiveData LifecycleOwner-এর মাধ্যমে স্বয়ংক্রিয়ভাবে সাবস্ক্রিপশন পরিচালনা করে — সাবস্ক্রিপশন শুধু সক্রিয় থাকে যখন Lifecycle STARTED বা RESUMED অবস্থায় থাকে। Compose-এ StateFlow লাইফসাইকেল-সচেতনতার সাথে collectAsState() ব্যবহার করে। iOS-এ NotificationCenter-এর স্পষ্ট [weak self] প্রয়োজন কারণ ক্লোজার self-এর শক্তিশালী রেফারেন্স রাখে।
Observer (GoF) এবং প্রকাশক-সাবস্ক্রাইবার (PubSub) — অনুরূপ কিন্তু ভিন্ন প্যাটার্ন। Observer-এ, প্রকাশক সরাসরি সাবস্ক্রাইবারদের তাদের মেথড কল করে অবহিত করে। প্রকাশক সাবস্ক্রাইবারদের সম্পর্কে জানে (একটি তালিকা সংরক্ষণ করে)। PubSub-এ, প্রকাশক এবং সাবস্ক্রাইবার একে অপরকে জানে না — তাদের মধ্যে একজন মধ্যস্থতাকারী (Event Bus, Message Queue, NotificationCenter) থাকে। প্রকাশক একটি চ্যানেলে বার্তা পাঠায়, সাবস্ক্রাইবার চ্যানেল শোনে। PubSub-এ শিথিল সংযুক্তি থাকে।
মোবাইল ডেভেলপমেন্টে PubSub-এর উদাহরণ — iOS-এ NotificationCenter-কে PubSub বিবেচনা করা যেতে পারে: প্রকাশক সাবস্ক্রাইবারদের জানে না — সে কেবল একটি বিজ্ঞপ্তি পোস্ট করে। Android-এ EventBus বা Otto (অপ্রচলিত)। BroadcastChannel-এর সাথে SharedFlow — Kotlin বিশ্বে PubSub। বিতরণকৃত সিস্টেমে, PubSub RabbitMQ, Kafka, Google PubSub-এর মাধ্যমে বাস্তবায়িত হয়। মোবাইল ডেভেলপমেন্টের জন্য, PubSub মডুলার আর্কিটেকচারে উপযোগী যেখানে মডিউলগুলি একে অপরের উপর নির্ভর করা উচিত নয়।
কী বেছে নেবেন — UI আপডেটের (ViewModel → View) জন্য, Observer ব্যবহার করুন (LiveData, StateFlow, @Published)। ক্রস-মডিউল ইভেন্টের (প্রমাণীকরণ, লগআউট, থিম পরিবর্তন) জন্য — PubSub (SharedFlow, NotificationCenter, EventBus)। Observer একটি স্ক্রিনের মধ্যে সহজ এবং বেশি কার্যকর, PubSub বিশ্বব্যাপী ইভেন্টের জন্য বেশি নমনীয় কিন্তু অন্তর্নিহিত নির্ভরতার কারণে ডিবাগ করা কঠিন।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
StateFlow Kotlin Coroutines-এর একটি প্ল্যাটফর্ম-স্বাধীন টাইপ, যেখানে LiveData Android Lifecycle-এর সাথে আবদ্ধ। StateFlow coroutines এবং অপারেটর সমর্থন করে এবং Android ছাড়া পরীক্ষা করা যায়। LiveData LifecycleOwner-এর মাধ্যমে স্বয়ংক্রিয়ভাবে সাবস্ক্রিপশন পরিচালনা করে। Google Kotlin + Compose-এ নতুন প্রজেক্টের জন্য StateFlow এবং Java সামঞ্জস্যের জন্য LiveData সুপারিশ করে।
হ্যান্ডলার ক্লোজারে [weak self] ব্যবহার করুন এবং deinit-এ removeObserver() কল করুন। observer (NSObjectProtocol)-এর রেফারেন্স সংরক্ষণ করুন এবং অবজেক্ট ধ্বংস হলে তা সরিয়ে ফেলুন। Combine-এ, DisposeBag মুক্তি পেলে স্বয়ংক্রিয় সাবস্ক্রিপশন বাতিলের জন্য AnyCancellable এবং store(in:) ব্যবহার করুন।
হ্যাঁ, SwiftUI @Published এবং @StateObject/@ObservedObject-সহ ObservableObject সমর্থন করে — এটি Observer-এর অন্তর্নির্মিত বাস্তবায়ন। @Published স্বয়ংক্রিয়ভাবে View-কে পরিবর্তন সম্পর্কে অবহিত করে। Combine প্রয়োজনীয় নয়: ObservableObject SwiftUI-তে নির্মিত objectWillChange Publisher ব্যবহার করে। Combine স্ট্রিম রূপান্তরের জন্য অপারেটর যোগ করে।
SharedFlow — এককালীন ইভেন্টের (ন্যাভিগেশন, টোস্ট, Snackbar) জন্য যেখানে বর্তমান মান প্রয়োজন নেই। StateFlow — UI অবস্থার (ডেটা তালিকা, লোডিং অগ্রগতি) জন্য যেখানে বর্তমান স্ন্যাপশট প্রয়োজন। SharedFlow-এর value বৈশিষ্ট্য নেই এবং এটি নতুন সাবস্ক্রাইবারকে শেষ মান ফেরত দেয় না।
KVO একটি পুরানো ObjC প্রক্রিয়া, যার জন্য @objc dynamic প্রয়োজন এবং এটি শুধুমাত্র NSObject থেকে উত্তরাধিকারসূত্রে প্রাপ্ত ক্লাসের সাথে কাজ করে। Combine একটি আধুনিক Swift ফ্রেমওয়ার্ক, টাইপ-সেফ, অপারেটর এবং SwiftUI সংহতকরণ সহ। Combine KVO এবং NotificationCenter-কে প্রতিস্থাপন করে। Apple নতুন প্রজেক্টের জন্য Combine এবং শুধুমাত্র লিগ্যাসি সমর্থনের জন্য KVO সুপারিশ করে।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন