Observer Pattern trong Swift

Mở đầu

Mục tiêu của bài viết nhằm:

  • Giới thiệu về Observer Pattern, một trong những kỹ thuật của Design Pattern.
  • Mô hình và code ví dụ để thực thi Observer Pattern trong swift
  • Observer Partern trong class NSNotificationCenter.

Observer Pattern là gì?

Observer Pattern nằm trong nhóm pattern bahavior, xây dựng cho mối quan hệ one to many, nhằm mục đích cho phép các đối tượng (các Observer) nhận biết được thay đổi từ một đối tượng khác (Subject) và có xử lý tương ứng khi đối tượng (Subject) đó thay đổi.

Các xử lý cơ bản cần có để thực thi Observer Pattern:

  • Bổ sung thêm một observer (Add an Observer): Cho phép một đối tượng (Observer) đăng ký để nhận được sự kiện khi một đối tượng khác (Subject) thay đổi
  • Thông báo với Observer (Notify the Observer): Thông báo với các Observer khi Subject thay đổi.
  • Loại bỏ một Observer (Remove the Observer): Cho phép loại bỏ một Observer không nhận notify từ subject khi có thay đổi.

Mô hình và ví dụ

Lấy một ví dụ mô tả như sau: muốn xây dựng một chương trình có chức năng như sau, khi người dùng thay đổi giá trị của một số X, thì sẽ tự động hiển thị giá trị của X ở dạng Binary, Octal và Hex. Khi đó biến số X sẽ đống vai trò là Subject, còn các đối tượng xử lý hiển thị giá tri của X ở dạng Binary, Octal, Hex sẽ đóng vai trò là các Observer

Mô hình của chương trình sẽ có dạng như sau:

Ta sẽ định nghĩa một Observer Protocol bao gồm:

  • id: để phân biệt giữa các Observer
  • hàm update() là interface chung để xử lý khi Subject thay đổi
protocol Observer{
    var id : Int{ get }
    func update()
}

Định nghĩa class Subject, đóng vai trò thông báo cho các Observer khi nào biến số X sẽ thay đổi, khi đó nó sẽ gọi hàm update() của các Observer đã đăng ký. Khi một Observer đăng ký nhận notify từ Subject, Observer đó sẽ được lưu trữ vào mảng observerArray

class Subject{
    
    private var observerArray = [Observer]()
    private var _number = Int()
    var number : Int {
        set {
            _number = newValue
            notify()
        }
        get {
            return _number
        }
    }
    
    func attachObserver(observer : Observer){
        observerArray.append(observer)
    }
    
    func removeObserver(observer : Observer) {
        observerArray = observerArray.filter{ $0.id != observer.id }
    }
    
    private func notify(){
        for observer in observerArray {
            observer.update()
        }
    }
    
}

Các Observer sẽ thực thi Observer protocol để có xử lý tương ứng khi Subject thay đổi.

Thực thi của Binary Observer

class BinaryObserver : Observer{
    
    private var subject = Subject()
    var id = Int()

    init(subject : Subject, id : Int) {
        self.subject = subject
        self.subject.attachObserver(observer: self)
        self.id = id
    }
    
    func update(){
        print("Binary: \(String(subject.number, radix: 2))")
    }
    
}

Thực thi của Hexa Observer

class HexaObserver : Observer{
    
    private var subject = Subject()
    var id = Int()
    
    init(subject : Subject, id : Int) {
        self.subject = subject
        self.subject.attachObserver(observer: self)
        self.id = id
    }
    
    func update(){
        print("Hex: \(String(subject.number, radix: 16))")
    }
    
}

Thực thi của Octal Observer

class OctalObserver : Observer{
    
    private var subject = Subject()
    var id = Int()

    init(subject : Subject, id : Int) {
        self.subject = subject
        self.subject.attachObserver(observer: self)
        self.id = id
    }
    
    func update(){
        print("Octal: \(String(subject.number, radix: 8))")
    }
    
}

Ta có thể chạy thử toàn bộ những định nghĩa trên bằng đoạn code dưới đây, mỗi lần thay đổi giá trị của Subject thì sẽ tự động in ra màn hình giá trị Binary, Hexa, Octal tương ứng .

let subject = Subject()

let binary = BinaryObserver(subject: subject, id: 1)
let octal = OctalObserver(subject: subject, id: 2)
let hex = HexaObserver(subject: subject, id: 3)

subject.number = 15
subject.removeObserver(observer: binary)
subject.number = 2

Kết quả đầu ra tương ứng:

Binary: 1111
Octal: 17
Hex: f
Octal: 2
Hex: 2
Program ended with exit code: 0

Observer Pattern trong NSNotification

Observer Pattern được áp dụng rất nhiều tại thực tế, trong bài viết này đề cập tới NotificationCenter
NSNotificationCenter: cung cấp cơ chế thông báo toàn cục cho các đối tượng trong phạm vi ứng dụng

  • Add Observer thông qua hàm: func addObserver(notificationObserver: AnyObject, selector notificationSelector: Selector, name notificationName: String?, object notificationSender: AnyObject?) Trong đó: + notificationObserver: Đối tượng đăng ký là observer để nhận notify + notificationSelector: làm xử lý (tương đương với hàm update ở ví dụ trên) khi nhận được notify thay đổi từ subject, hàm có một tham số là đối tượng của NSNotification + NotificationName: Tên của notify mà Observer đăng ký sẽ nhận được. + notificationSender: Đối tượng mà Observer muốn nhận notify.
  • Gửi thông báo cập nhật tới các Observer thông qua hàm: func postNotificationName(notificationName: String, object notificationSender: AnyObject?) Trong đó: + notificationName: Tên của notify sẽ gửi tới các observer + notificationSender: Đối tượng chứa notify được gửi tới các observer
  • Remove Observer thông qua hàm: func removeObserver(notificationObserver:AnyObject) + notificationObserver: đối tượng đã được đăng ký là Obserer trước đó.

Kết luận

Qua bài viết này rất mong mọi người có cái nhìn rõ hơn về Observer Partern, và có thể áp dụng một cách hiệu quả trong các dự án tương lại của mình.

Nguồn thao khảo: https://medium.com/design-patterns-in-swift/design-patterns-in-swift-observer-pattern-51274d34f9e3 http://masteringswift.blogspot.com/2015/05/swift-and-observer-design-pattern.html


All Rights Reserved