Observer — مفاهیم کلیدی الگوی اشتراک در تغییرات

نویسنده: IT Sectr منتشر شده: 2026-02-17 زمان مطالعه: 7 دقیقه

Observer — یک الگوی رفتاری که در آن یک شیء (ناشر) چندین مشترک را از تغییرات وضعیت خود مطلع می‌کند. در توسعه موبایل، Observer اساس مکانیک‌های واکنش‌گرا را تشکیل می‌دهد: UI در تغییرات داده مشترک می‌شود و به‌طور خودکار به‌روز می‌شود. این الگو در NotificationCenter در iOS و LiveData/Flow در Android پیاده‌سازی شده است. بیشتر — در Refactoring Guru: Observer.

نکات اصلی

  • Observer — الگوی اشتراک: یک ناشر، چندین مشترک
  • NotificationCenter — پیاده‌سازی داخلی Observer در iOS/macOS
  • Flow و LiveData — پیاده‌سازی‌های واکنش‌گرای Observer در Android
  • Push vs Pull — ناشر می‌تواند داده ارسال کند یا درباره رویدادها اطلاع دهد
  • نشت حافظه — مشترکان باید برای جلوگیری از نشت حافظه لغو اشتراک کنند

Observer چیست: ماهیت الگوی ناظر؟

Observer (ناظر) — الگوی رفتاری GoF که وابستگی «یک به چند» بین اشیاء را تعریف می‌کند. هنگامی که یک شیء (Subject یا Observable) وضعیت خود را تغییر می‌دهد، تمام اشیاء وابسته (Observers) به‌طور خودکار مطلع و به‌روز می‌شوند. این الگو اتصال ضعیف را پیاده‌سازی می‌کند: ناشر کلاس‌های خاص مشترکان را نمی‌داند — فقط می‌داند که آنها رابط Observer را پیاده‌سازی می‌کنند.

ساختار Observer شامل رابط Subject با متدهای attach()، detach()، notify() و رابط Observer با متد update() است. 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 برای حجم‌های بزرگ داده که مشترک ممکن است نخواهد دریافت کند، کارآمدتر است.

Observer در iOS: NotificationCenter، Combine و KVO

NotificationCenter — مکانیزم داخلی iOS/macOS برای پیاده‌سازی Observer. ناشر Notification را از طریق NotificationCenter.default.post(name:, object:, userInfo:) ارسال می‌کند. مشترک از طریق addObserver(forName:, queue:, using:) ثبت‌نام می‌کند. NotificationCenter از اعلان‌های نام‌گذاری شده (Notification.Name) پشتیبانی می‌کند و می‌تواند هر داده‌ای را در userInfo منتقل کند. UIKeyboardWillShowNotification، UIApplicationDidEnterBackgroundNotification — نمونه‌های سیستمی.

swift
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 framework — جایگزین واکنش‌گرای مدرن برای NotificationCenter، از iOS 13 در دسترس است. Publisher (NotificationCenter، URLSession.Timer) — ناشر، Subscriber (sink، assign) — مشترک. Combine برای تبدیل جریان داده عملگرهایی (map، filter، combineLatest) اضافه می‌کند. @Published — property wrapper که به‌طور خودکار مشترکان را از تغییرات مطلع می‌کند. در MVVM با SwiftUI، Combine جایگزین NotificationCenter برای اتصال ViewModel و View می‌شود.

KVO (Key-Value Observing) — مکانیزم قدیمی ObjC/Swift برای مشاهده ویژگی‌های فردی اشیاء. @objc dynamic var name: String — ویژگی قابل مشاهده. observe(.name) — اشتراک. KVO فقط با کلاس‌های سازگار با @objc و میراث ObjC کار می‌کند. Apple در پروژه‌های جدید به جای KVO، Combine و @Published را توصیه می‌کند. KVO برای سازگاری با UIKit در پروژه‌های ترکیبی همچنان مرتبط است.

Observer در Android: LiveData، StateFlow و SharedFlow

LiveData — مؤلفه Android Architecture Components برای پیاده‌سازی Observer. کلاس Observable که مشترکان را از تغییرات داده مطلع می‌کند. LiveData چرخه حیات را در نظر می‌گیرد: مشترکان (LifecycleOwner) به‌طور خودکار هنگام نابودی لغو اشتراک می‌کنند. LiveData مدل Push است: داده در observe() منتقل می‌شود. LiveData بلوک ساختمانی پایه MVVM در Android قبل از معرفی Jetpack Compose است.

kotlin
// 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 که جایگزین LiveData در Jetpack Compose شدند. StateFlow — state holder قابل مشاهده با مقدار جاری ثابت. SharedFlow — hot flow قابل تنظیم بدون حالت، مناسب برای رویدادهای یک‌بار مصرف (ناوبری، toastها). هر دو نوع به‌طور نزدیک با Compose یکپارچه شده‌اند: collectAsState()، collectAsEffect(). StateFlow در پروژه‌های مدرن Android با Compose اجباری است.

LiveData vs StateFlow — LiveData به Android Lifecycle وابسته است، StateFlow مستقل از پلتفرم است. StateFlow از coroutines، عملگرها (map، filter) پشتیبانی می‌کند و بدون وابستگی‌های Android آزمایش می‌شود. LiveData برای سازگاری با Java ساده‌تر است. Google برای پروژه‌های جدید با Kotlin + Compose StateFlow و برای پشتیبانی از پروژه‌های قدیمی یا کد Java، LiveData را توصیه می‌کند.

مدیریت اشتراک‌ها و نشت حافظه

نشت حافظه (memory leaks) — مشکل اصلی Observer بدون مدیریت صحیح اشتراک‌ها. اگر مشترک (Activity، Fragment، UIViewController) نابود شده باشد اما لغو اشتراک نکرده باشد، ناشر همچنان به آن ارجاع نگه می‌دارد و garbage collector نمی‌تواند حافظه را آزاد کند. در Android، LifecycleOwner (Activity/Fragment) باید removeObserver() را فراخوانی کند یا از observe(viewLifecycleOwner) استفاده کند. در iOS — removeObserver در deinit یا disposeBag در Combine.

پلتفرممکانیزم Observerلغو اشتراک خودکارلغو اشتراک دستی
iOSNotificationCenterخیرremoveObserver() در deinit
iOSCombine (sink)خیرstore(in: &bag) — DisposeBag
iOSKVOخیرremoveObserver() در deinit
AndroidLiveDataبله (LifecycleOwner)removeObserver() اختیاری
AndroidStateFlowاز طریق viewModelScopecancel() Job هنگام لغو اشتراک
AndroidRxJavaخیرdispose() در CompositeDisposable

ارجاع ضعیف (weak reference) در مشترکان — در بلوک اشتراک از [weak self] در Swift و به scope lifecycle در Kotlin ارجاع دهید. LiveData به‌طور خودکار اشتراک را از طریق LifecycleOwner مدیریت می‌کند — اشتراک فقط زمانی فعال است که Lifecycle در وضعیت STARTED یا RESUMED باشد. StateFlow در Compose از collectAsState() با در نظر گرفتن lifecycle استفاده می‌کند. NotificationCenter در iOS نیاز به [weak self] صریح دارد، زیرا closure به self ارجاع قوی دارد.

Observer vs Publisher-Subscriber: تفاوت در چیست

Observer (GoF) و Publisher-Subscriber (PubSub) — الگوهای مشابه اما متفاوت. در Observer، ناشر مستقیماً با فراخوانی متدهایشان مشترکان را مطلع می‌کند. ناشر از مشترکان آگاه است (فهرست را ذخیره می‌کند). در PubSub، ناشر و مشترک از یکدیگر بی‌خبرند — واسطه‌ای (Event Bus، Message Queue، NotificationCenter) بین آنها قرار دارد. ناشر پیام را به کانال می‌فرستد، مشترک به کانال گوش می‌دهد. PubSub اتصال ضعیف‌تری دارد.

نمونه‌های PubSub در توسعه موبایل — NotificationCenter در iOS را می‌توان PubSub در نظر گرفت: ناشر مشترکان را نمی‌شناسد — فقط اعلان را ارسال می‌کند. EventBus یا Otto در Android (منسوخ شده). SharedFlow با BroadcastChannel — PubSub در دنیای Kotlin. در سیستم‌های توزیع‌شده، PubSub از طریق RabbitMQ، Kafka، Google PubSub پیاده‌سازی می‌شود. برای توسعه موبایل، PubSub در معماری ماژولار مفید است، جایی که ماژول‌ها نباید به یکدیگر وابسته باشند.

چه چیزی انتخاب کنیم — برای به‌روزرسانی UI (ViewModel → View) از Observer استفاده کنید (LiveData، StateFlow، @Published). برای رویدادهای بین‌ماژولی (احراز هویت، خروج از حساب، تغییر تم) — PubSub (SharedFlow، NotificationCenter، EventBus). Observer در یک صفحه ساده‌تر و کارآمدتر است، PubSub برای رویدادهای سراسری انعطاف‌پذیرتر اما به دلیل وابستگی‌های ضمنی در اشکال‌زدایی دشوارتر است.

سوالات متداول

StateFlow چه تفاوتی با LiveData دارد؟

StateFlow یک نوع مستقل از پلتفرم از Kotlin Coroutines است، LiveData به Android Lifecycle وابسته است. StateFlow از coroutines و عملگرها پشتیبانی می‌کند و بدون Android آزمایش می‌شود. LiveData اشتراک را از طریق LifecycleOwner به‌طور خودکار مدیریت می‌کند. Google برای پروژه‌های جدید با Kotlin + Compose StateFlow و برای سازگاری با Java LiveData را توصیه می‌کند.

چگونه از نشت حافظه با NotificationCenter جلوگیری کنیم؟

در closure handler از [weak self] استفاده کنید و removeObserver() را در deinit فراخوانی کنید. به observer (NSObjectProtocol) ارجاع نگه دارید و هنگام نابودی شیء آن را حذف کنید. در Combine از AnyCancellable و store(in:) برای لغو اشتراک خودکار هنگام آزادسازی DisposeBag استفاده کنید.

آیا می‌توان از Observer در SwiftUI بدون Combine استفاده کرد؟

بله، SwiftUI از ObservableObject با @Published و @StateObject/@ObservedObject پشتیبانی می‌کند — این یک پیاده‌سازی داخلی Observer است. @Published به‌طور خودکار View را از تغییرات مطلع می‌کند. Combine الزامی نیست: ObservableObject از Publisher objectWillChange که در SwiftUI تعبیه شده استفاده می‌کند. Combine برای تبدیل جریان‌ها عملگرهایی اضافه می‌کند.

چه زمانی به جای StateFlow از SharedFlow استفاده کنیم؟

SharedFlow — برای رویدادهای یک‌بار مصرف (ناوبری، toastها، Snackbar) که به مقدار جاری نیاز ندارند. StateFlow — برای وضعیت UI (فهرست داده، وضعیت بارگذاری) که به snapshot جاری نیاز است. SharedFlow ویژگی value ندارد و آخرین مقدار را به مشترکان جدید برنمی‌گرداند.

تفاوت بین KVO و Combine در iOS چیست؟

KVO یک مکانیزم قدیمی ObjC است، نیاز به @objc dynamic دارد و فقط با کلاس‌های ارث‌برده از NSObject کار می‌کند. Combine یک فریم‌ورک مدرن Swift است، نوع‌امن، با عملگرها و یکپارچگی با SwiftUI. Combine جایگزین KVO و NotificationCenter می‌شود. Apple برای پروژه‌های جدید Combine و فقط برای پشتیبانی از کد قدیمی KVO را توصیه می‌کند.

خلاصه

  • Observer — الگوی رفتاری برای اطلاع‌رسانی به مشترکان درباره تغییرات
  • iOS NotificationCenter — پیاده‌سازی PubSub با اعلان‌های نام‌گذاری شده
  • iOS Combine — فریم‌ورک واکنش‌گرا با Publisher و Subscriber
  • Android LiveData — Observer آگاه از چرخه حیات از Android Architecture Components
  • Android StateFlow — state holder واکنش‌گرا برای Compose و کوروتین‌ها
  • مدیریت حافظه — لغو اشتراک اجباری برای جلوگیری از نشت
  • Observer vs PubSub — اشتراک مستقیم vs واسطه برای اتصال ضعیف

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید