Beobachtermuster in iOS-Swift (Behavioral Design Pattern)

Jan 09 2023
In dieser Geschichte werde ich über das Observer-Entwurfsmuster schreiben. Derzeit verwenden die meisten Entwickler RXSwift oder Combine, um dieses Entwurfsmuster zu implementieren, und manchmal haben wir nicht darüber nachgedacht, was hinter diesen Tools passieren wird.

In dieser Geschichte werde ich über das Observer-Entwurfsmuster schreiben.
Derzeit verwenden die meisten Entwickler RXSwift oder Combine, um dieses Entwurfsmuster zu implementieren, und manchmal haben wir nicht darüber nachgedacht, was hinter diesen Tools passieren wird. Ich werde Observer-Muster erklären und einen Beispielcode ohne RXSwift oder Combine schreiben, um die Musteridee zu demonstrieren.
Das Observer-Entwurfsmuster ermöglicht es einer Gruppe von Objekten, sogenannten Beobachtern, über die Zustandsänderung eines anderen Objekts, das als Subjekt bezeichnet wird, benachrichtigt zu werden.
Die Beobachter registrieren sich mit dem Subjekt. Das Subjekt aktualisiert alle registrierten Beobachter, wenn sich sein Status ändert.
Wenn ein Beobachter benachrichtigt wird, kann er den Themenstatus abrufen, an dem er interessiert ist.

Dieser Ansatz vermeidet die enge Kopplung zwischen den Beobachtern und dem Subjekt.
Das Subjekt kennt nur das gemeinsame Protokoll. Dem Betreff werden keine weiteren Implementierungsdetails mitgeteilt.
Stellen Sie sicher, dass die Beobachter vom Thema abgemeldet werden, bevor Sie sie freilassen. Andernfalls behält das Subjekt den Verweis auf die Beobachterinstanz, die hätte zerstört werden sollen, bei und aktualisiert sie weiterhin, was zu Fehlern und unerwartetem Verhalten führt.

Beginnen wir mit der Implementierung des Observer-Musters.

Zuerst erstelle ich das Beobachterprotokoll. Typen müssen diesem Protokoll entsprechen, wenn sie benachrichtigt werden möchten, wenn sich das Thema ändert. und das Protokoll deklariert eine einzelne Methode, notify.

protocol Observer {
    func notify()
    var uid: Int { get }
}

Dann benötigen wir das Betreffprotokoll. Ich definiere das Methodenregister, das es Beobachtern ermöglicht, Benachrichtigungen vom Subjekt zu abonnieren.

protocol Subject {
    mutating func register(_ observer: Observer)
    mutating func unregister(_ observer: Observer)
}

Das war's, jetzt sehen wir es uns in Aktion an.

Ich werde die UI-Beschriftung mithilfe einer Erweiterung an das Beobachterprotokoll anpassen.

extension UILabel: Observer {
    func notify() {
        self.text = "Subject state changed"
    }
    
    var uid: Int {
        return ObjectIdentifier(self).hashValue
    }
}

Als Nächstes werde ich die UI-Schaltfläche mithilfe einer Erweiterung an das Betreffprotokoll anpassen.

extension UIButton: Subject {
    private static var observers = [Observer]()
    
    func register(_ observer: Observer) {
        UIButton.observers.append(observer)
    }
    
    func unregister(_ observer: Observer) {
        UIButton.observers = UIButton.observers.filter{$0.uid != observer.uid}
    }
}

Die Registermethode sollte den Eingabeparameter an die Liste der Beobachter anhängen.

Und für die Unregister-Methode verlasse ich mich auf die Filter-Array-Methode, die die Elemente der Beobachterliste zurückgibt, die das gegebene Prädikat erfüllen.

UIButton entspricht jetzt vollständig dem Subjektprotokoll.

func onStateChanged() {
    UIButton.observers.forEach { (observer) in
        observer.notify()
    }
}

Jetzt lasst uns alles zusammenfügen.

protocol Observer {
    func notify()
    var uid: Int { get }
}

protocol Subject {
    mutating func register(_ observer: Observer)
    mutating func unregister(_ observer: Observer)
}

extension UILabel: Observer {
    func notify() {
        self.text = "Subject state changed"
    }

    var uid: Int {
        return ObjectIdentifier(self).hashValue
    }
}

extension UIButton: Subject {
    private static var observers = [Observer]()

    func register(_ observer: Observer) {
        UIButton.observers.append(observer)
    }

    func unregister(_ observer: Observer) {
        UIButton.observers = UIButton.observers.filter{$0.uid != observer.uid}
    }

    func onStateChanged() {
        UIButton.observers.forEach { (observer) in
            observer.notify()
        }
    }
}

Strukturelles Designmuster – Adapter in iOS-Swift

Hoffentlich finden Sie es nützlich und können es in Ihrem Projekt verwenden. Ich würde mich über Feedback dazu freuen.

Netzwerkerreichbarkeit mit Combine und Alamofire