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 — ทางเลือกเชิงรับที่ทันสมัยสำหรับ 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 คลาสที่สังเกตได้ซึ่งแจ้งให้ผู้สมัครสมาชิกทราบเกี่ยวกับการเปลี่ยนแปลงข้อมูล 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 — ตัวเก็บสถานะที่สังเกตได้พร้อมค่าปัจจุบันคงที่ SharedFlow — โฟลว์ร้อนที่กำหนดค่าได้โดยไม่มีสถานะ เหมาะสำหรับเหตุการณ์ครั้งเดียว (การนำทาง, โทสต์) ทั้งสองชนิดถูกรวมเข้ากับ Compose อย่างใกล้ชิด: collectAsState(), collectAsEffect() StateFlow เป็นข้อบังคับในโปรเจ็กต์ Android สมัยใหม่กับ Compose

LiveData vs StateFlow — LiveData ผูกกับวงจรชีวิต Android, StateFlow ไม่ขึ้นกับแพลตฟอร์ม StateFlow รองรับ coroutines, ตัวดำเนินการ (map, filter) และสามารถทดสอบได้โดยไม่ต้องพึ่งพา Android LiveData ง่ายกว่าสำหรับความเข้ากันได้กับ Java Google แนะนำ StateFlow สำหรับโปรเจ็กต์ใหม่บน Kotlin + Compose, LiveData สำหรับการบำรุงรักษาโปรเจ็กต์เก่าหรือโค้ด Java

การจัดการการสมัครสมาชิกและหน่วยความจำรั่ว

หน่วยความจำรั่ว — ปัญหาหลักของ Observer หากไม่มีการจัดการการสมัครสมาชิกที่เหมาะสม หากผู้สมัครสมาชิก (Activity, Fragment, UIViewController) ถูกทำลายแต่ไม่ได้ยกเลิกการสมัคร ผู้เผยแพร่จะยังคงเก็บการอ้างอิงถึงมันและตัวเก็บขยะไม่สามารถปล่อยหน่วยความจำได้ ใน 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

การอ้างอิงแบบอ่อนในผู้สมัครสมาชิก — เมื่อใช้ closure ในบล็อกการสมัครสมาชิก ให้ใช้ [weak self] ใน Swift และอ้างอิงขอบเขตวงจรชีวิตใน Kotlin LiveData จัดการการสมัครสมาชิกโดยอัตโนมัติผ่าน LifecycleOwner — การสมัครสมาชิกจะทำงานเฉพาะเมื่อ Lifecycle อยู่ในสถานะ STARTED หรือ RESUMED StateFlow ใน Compose ใช้ collectAsState() โดยคำนึงถึงวงจรชีวิต NotificationCenter ใน iOS ต้องใช้ [weak self] อย่างชัดเจนเนื่องจาก closure เก็บการอ้างอิงแบบแข็งไปยัง self

Observer vs ผู้เผยแพร่-ผู้สมัครสมาชิก: ความแตกต่าง

Observer (GoF) และผู้เผยแพร่-ผู้สมัครสมาชิก (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 StateFlow รองรับ coroutines และตัวดำเนินการ และสามารถทดสอบได้โดยไม่มี Android LiveData จัดการการสมัครสมาชิกโดยอัตโนมัติผ่าน LifecycleOwner Google แนะนำ StateFlow สำหรับโปรเจ็กต์ใหม่บน Kotlin + Compose และ LiveData สำหรับความเข้ากันได้กับ Java

จะหลีกเลี่ยงหน่วยความจำรั่วกับ NotificationCenter ได้อย่างไร?

ใช้ [weak self] ใน closure ตัวจัดการและเรียก 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 — สำหรับเหตุการณ์ครั้งเดียว (การนำทาง, โทสต์, Snackbar) ที่ไม่ต้องการค่าปัจจุบัน StateFlow — สำหรับสถานะ UI (รายการข้อมูล, ความคืบหน้าการโหลด) ที่ต้องการภาพรวมปัจจุบัน 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 — ตัวเก็บสถานะเชิงรับสำหรับ Compose และ coroutines
  • การจัดการหน่วยความจำ — การยกเลิกการสมัครบังคับเพื่อป้องกันการรั่วไหล
  • Observer vs PubSub — การสมัครโดยตรง vs ตัวกลางสำหรับการเชื่อมโยงแบบหลวม

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม