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 συνιστά Combine και @Published αντί για KVO σε νέα έργα. Το 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 συνιστά StateFlow για νέα έργα με Kotlin + Compose, LiveData — για υποστήριξη παλαιών έργων ή κώδικα Java.

Διαχείριση συνδρομών και διαρροές μνήμης

Διαρροές μνήμης (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 και αναφερθείτε στο lifecycle scope σε 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 συνιστά StateFlow για νέα έργα με Kotlin + Compose, LiveData — για συμβατότητα Java.

Πώς να αποφύγετε διαρροές μνήμης με το NotificationCenter;

Χρησιμοποιήστε [weak self] στο closure του handler και καλέστε 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 προσθέτει τελεστές για μετασχηματισμό ροών.

Πότε να χρησιμοποιήσετε SharedFlow αντί για StateFlow;

SharedFlow — για εφάπαξ γεγονότα (πλοήγηση, toast, Snackbar) όπου δεν απαιτείται τρέχουσα τιμή. StateFlow — για κατάσταση UI (λίστα δεδομένων, πρόοδος φόρτωσης) όπου απαιτείται τρέχον στιγμιότυπο. Το SharedFlow δεν έχει ιδιότητα value και δεν επιστρέφει την τελευταία τιμή σε νέους συνδρομητές.

Ποια είναι η διαφορά μεταξύ KVO και Combine σε iOS;

Το KVO είναι ένας παρωχημένος μηχανισμός ObjC, απαιτεί @objc dynamic και λειτουργεί μόνο με κλάσεις που κληρονομούν από NSObject. Το Combine είναι ένα σύγχρονο Swift framework, type-safe, με τελεστές και ενσωμάτωση με SwiftUI. Το Combine αντικαθιστά το KVO και το NotificationCenter. Η Apple συνιστά Combine για νέα έργα, KVO — μόνο για υποστήριση παλαιού κώδικα.

Περίληψη

  • Observer — πρότυπο συμπεριφοράς για ειδοποίηση συνδρομητών σχετικά με αλλαγές
  • iOS NotificationCenter — υλοποίηση PubSub με ονομασμένες ειδοποιήσεις
  • iOS Combine — αντιδραστικό framework με Publisher και Subscriber
  • Android LiveData — lifecycle-aware Observer από το Android Architecture Components
  • Android StateFlow — αντιδραστικός κάτοχος κατάστασης για Compose και κορουτίνες
  • Διαχείριση μνήμης — υποχρεωτική απεγγραφή για την αποφυγή διαρροών
  • Observer vs PubSub — άμεση συνδρομή vs διαμεσολαβητής για χαλαρή σύζευξη

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης