Saladpuk.com
🏆 เนื้อหาหลัก
🏆 เนื้อหาหลัก
  • 💖สลัดผัก
  • 📰มีอะไรใหม่บ้าง
    • 2020
      • 2020-11
      • 2020-10
      • 2020-09
      • 2020-08
      • 2020-03
      • 2020-02
      • 2020-01
    • 2019
      • 2019-12
      • 2019-11
      • 2019-10
      • 2019-09
      • 2019-08
  • 🤔อ่านเรื่องไรดี ?
  • มือใหม่หัดเขียนโค้ด
    • 👶เขียนโค้ดด้วยภาษา C#
      • เกิดมาไม่เคยเขียนโค้ดมาก่อนเบย
      • 👶พื้นฐาน
        • 1.โปรแกรมที่ต้องลง
        • 2.โครงสร้างของโค้ด
        • 3.ชนิดของข้อมูล
        • 4.การสร้างตัวแปร
        • 5.คำสั่งพื้นฐาน
        • 6.การแปลงข้อมูล
        • 7.การเปรียบเทียบค่า
        • 8.การตัดสินใจด้วย IF statements
        • 9.การตัดสินใจด้วย Switch statements
        • 10.การทำงานซ้ำๆด้วย While
        • 11.การทำงานซ้ำๆด้วย Do While
        • 12.การทำงานซ้ำๆด้วย For
        • 13.การแก้โจทย์จากรูป
        • 14.มารู้จักกับ Array กัน
      • 🧑ระดับกลาง
        • 15.Value type vs Reference type
        • 16.ลดงานซ้ำๆด้วย Method
        • 17.มารู้จักกับ Class & Field กัน
        • 18.มารู้จักกับ Constructor กันบ้าง
        • 19.มาเขียน Method ใน Class กัน
        • 20.มารู้จักกับ Property กัน
        • 21.ลองใช้คลาสแบบจริงจังบ้าง
        • 22.การสืบทอด Inheritance
        • 23.Polymorphism
        • 24.Abstract Class
        • 25.Interface
        • 26.Namespace
        • 27.Enum
        • 28.Exception handler
        • 29.ลงลึกกับ string
        • 30.StringBuilder เพื่อนคู่ string
      • 👨⏳ระดับสูง
        • Generic
        • Delegates
        • Action & Func
        • Lambda expression
        • LINQ
        • พระคัมภีร์การใช้คำสั่ง LINQ
      • 💡Tips
        • 💡C# version 8.0
        • 💡Boxing & Unboxing
    • 👶Algorithm
      • 👾Algorithm Big-O
      • 👽Algorithm P & NP
    • 👦OOP
      • 💖Abstraction
      • 💖Encapsulation
      • 🏆Abstraction & Encapsulation
      • 💖Inheritance
      • 💖Polymorphism
      • 🏆Inheritance & Polymorphism
      • 📝ลองเขียน OOP ดูดิ๊
      • 👑OOP + Power of Design
      • 🥰เทคนิคในการออกแบบ
    • 👶บทสรุปฐานข้อมูล
      • เก็บรูปในฐานข้อมูล
      • Database indexing
      • การลบข้อมูล
    • 👦Communication Patterns
    • 👦Design Patterns
      • 🤰Creational Patterns
        • 🏭Factory Method
        • 🏭Abstract Factory
        • ☝️ Singleton Pattern
        • 🏗️ Builder Pattern
        • 🎎Prototype Pattern
      • 🧱Structural Patterns
        • 🔌Adapter Pattern
        • 📪Proxy Pattern
  • Puzzle
    • 🧠Challenges
      • 🐴Google ม้า 25 ตัว
      • 🌉Amazon เสา 2 ต้น
      • 🥇ทองเก๊
      • 💊ยาต้านโควิด
      • 🎩CP หมวก 5 ใบ
      • 🧓Einstein's Riddle 01
  • พื้นฐานที่ควรต้องรู้
    • 🐳Docker
      • 📦Docker Containers
      • 🃏Docker Exercise 01
      • 🛠️ Docker Tools
      • 🗃️ Docker Registry
      • 🖼️ Container Image
      • 📢Docker Push
      • 🔄WSL
    • 👶Clean Code
      • 🧓Uncle Bob - Clean Code
      • 🧓Uncle Bob - Comments
      • 🧓Uncle Bob - Naming
      • 🧓Uncle Bob - Mindset
      • 🧓Uncle Bob - TDD
    • 👶Code Smells
    • 👶สิ่งที่คนเขียนโค้ดมักเข้าใจผิด
    • 👶AI พื้นฐาน
    • 👶Git พื้นฐาน
      • Git branching strategy
    • 👶Cloud พื้นฐาน
    • 👶UML พื้นฐาน
      • Activity Diagram
      • Class Diagram
      • Sequence Diagram
      • Use case Diagram
      • บทสรุปการใช้ UML
    • 👶Data Scientist
      • การเลือก Algorithms ให้ AI (1/5)
      • การเตรียมข้อมูลให้ AI (2/5)
      • หลักการตั้งคำถามให้ AI (3/5)
      • แฉความลับของ AI Model (4/5)
      • หัดเขียน AI จาก AI ของคนอื่น (5/5)
    • 👶DevOps พื้นฐาน
    • 👶Docker ขั้นพื้นฐาน
      • Image and Container
      • แชร์ Docker Image ที่สร้างไว้
    • 👶Microservices พื้นฐาน
      • Microservices ที่ดีมีลักษณะยังไง
      • Microservices Tips
      • จาก Monolith สู่ Microservices
    • 👶ความรู้พื้นฐานในการทำเว็บ
    • 👦Bottlenecks of Software
      • หัวใจที่สำคัญที่สุดของฐานข้อมูล
    • 👦Agile Methodology
      • Agile in a Nutshell
      • Software Development Life Cycle
      • Code Review
    • 👦Security พื้นฐาน
      • การเก็บรหัสผ่านที่ถูกต้อง
      • Security in actions
        • Hash function
      • Security Principles
      • 😎The Matrix 1
      • 😎The Matrix 2
      • HTTPS in a nutshell
    • 👦SOLID Design Principles
      • มารู้จักกับ SOLID กันดีกว่า
      • Single-Responsibility Principle
      • Open/Closed Principle
      • Liskov Substitution Principle
      • Interface Segregation Principle
      • Dependency-Inversion Principle
  • Cloud Computing
    • 👶Microsoft Azure 101
      • สมัคร Microsoft Azure
      • รู้จักกับ Resource Groups
      • สร้างเว็บตัวแรกกัน
      • สร้าง Virtual Machine กัน
      • ประเภทของคลาว์เซอร์วิส
      • มาสร้าง Logic App กัน
      • มาสร้าง Function App กัน
      • คลาว์คิดเงินยังไง ?
      • Cloud Native
      • Guideline for Cloud scaling
      • Auto Scaling
    • 👶Azure App Services
    • 👶App Service Plan
    • 👶Azure Storage
      • Blob storage
        • ลองสร้างที่เก็บไฟล์กันเลย
        • เข้าใจ Blob storage ให้มากขึ้น
        • ลองเขียนโค้ดอัพโหลดไฟล์กันบ้าง
        • สร้างเว็บจากที่ฝากไฟล์บนคลาว์
    • 👶Azure Bot Service
      • Bot เข้าใจเราได้ยังไงกันนะ
    • 👶Azure Cognitive Services
      • การสร้าง Cognitive Services
      • การ Login ด้วยใบหน้า
      • อ่านลายมือจากรูปเป็นตัวอักษร (OCR)
      • เขียน AI แยกของต่างๆทำยังไง?
      • เขียนแอพ ทายอายุ บอกเพศ ง่ายจิ๊ดเดียว
      • เขียนแอพให้ AI อธิบายรูปเป็นภาษาคน
    • 👶Machine Learning Studio
      • มาสร้าง AI ของแท้ตัวแรกของเรากัน
      • สร้าง AI ตัดสินใจอนุมัติบัตรเครดิต 💳
      • ลองเรียกใช้ AI ของเรากัน
    • 👶Azure Service Fabric
      • สร้าง Service Fabric กัน
    • 👶Blockchain
      • Blockchain ทำงานยังไง ?
      • Consensus Algorithm คืออะไร ?
      • สร้าง Blockchain ใช้เองกัน !
      • หัดเขียน Smart Contract กัน
    • 👶Power BI
    • 👶Azure Web App
      • เซิฟเวอร์บนคลาว์ ราคา? ต่าง?
    • 👶Azure DevOps
      • เล่น Azure DevOps กัน
      • เล่นกับ Repository
      • ลองทำ Continuous Integration (CI)
      • ลองทำ Continuous Delivery (CD)
      • เล่น Kanban Board
    • 🤠Cloud Playground
      • การป้องกันความลับหลุดตอนที่ 1
      • การป้องกันความลับหลุดตอนที่ 2
      • การป้องกันความลับหลุดตอนที่ 3
      • การป้องกันความลับหลุดตอนจบ
  • Software Testing
    • 👦Test-First Design
    • 👦Test-Driven Development
      • 1.มารู้จักกับ TDD กันดีกว่า
      • 2.Test cases เขาเขียนกันยังไงนะ
      • 3.เครื่องมือในการทดสอบ
      • 4.การใช้ Theory และ InlineData
      • 5.โค้ดที่ทดสอบได้
      • 6.Mantra of TDD
      • 7.Functional & None-Functional testing
      • 8.Manual vs Automation testing
      • 9.Automation Frameworks in .NET
      • 10.Mock Framework
      • 11.มาเรียนการใช้ Moq กันเถอะ
      • 12.สรุป
  • Web
    • 👦Web API
      • 1.Web API คืออะไร
      • 2.ติดตั้ง .NET Core SDK
      • 3.สร้าง Web API ตัวแรกกัน
      • 4.Verbs
      • 5.Swagger เพื่อคู่ API
      • 6.การใช้ Model
      • 7.เรียก Web API ผ่าน Postman
      • 8.มาจัดกลุ่ม API กัน (1/2)
      • 9.มาจัดกลุ่ม API กัน (2/2)
  • Software Design
    • 🤴Design Patterns
      • 🦈Creational patterns
        • Abstract Factory
        • Builder
        • Factory Method
        • Prototype
        • Singleton
      • 🦈Structural patterns
        • Adapter
        • Bridge
        • Decorator
        • Facade
        • Proxy
      • 🦈Behavioral patterns
        • Chain of Responsibility
        • Command
        • Iterator
        • Mediator
        • Memento
        • Observer
        • State
        • Strategy
        • Template Method
        • Visitor
Powered by GitBook
On this page
  • Observer
  • 🎯 เป้าหมายของ pattern นี้
  • ✌ หลักการแบบสั้นๆ
  • 😢 ปัญหา
  • 😄 วิธีแก้ไข
  • 📌 โครงสร้างของ pattern นี้
  • 🛠 ตัวอย่างการนำไปใช้งาน
  • 👍 ข้อดี
  • 👎 ข้อเสีย
  • ‍‍📝 Code ตัวอย่าง

Was this helpful?

Export as PDF
  1. Software Design
  2. Design Patterns
  3. Behavioral patterns

Observer

PreviousMementoNextState

Last updated 5 years ago

Was this helpful?

Observer

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

🎯 เป้าหมายของ pattern นี้

สร้างกลไกในการแจ้งเตือนให้กับ object ต่างๆที่สนใจ

✌ หลักการแบบสั้นๆ

  1. สร้างตัวกลางในการลงทะเบียนให้กับคนที่ต้องการ ติดตามข่าว/ยกเลิกติดตามข่าว ขึ้นมา

  2. สร้าง interface กลางสำหรับคนติดตามข่าว เพื่อให้ตัวกลางทำงานร่วมได้

  3. คนที่ต้องการติดตามข่าวจะต้อง implement interface นั้น

  4. เมื่อมีข่าวใหม่ๆเกิดขึ้น ตัวกลางก็จะส่งข่าวไปให้กลับคนที่ลงทะเบียนไว้

😢 ปัญหา

สมมุติว่าเราเขียนแอพขายของบนมือถือตัวนึงอยู่ ซึ่งโค้ดของเรามี class อยู่ 2 ตัวคือ Customer และ Store

เมื่อเรามีสินค้าใหม่ๆเข้ามา เราก็จะอัพเดทสินค้าลงใน database ส่วนถ้าลูกค้าอยากรู้ว่ามีสินค้าอะไรใหม่เข้ามาบ้าง ก็จะต้องไปถามจาก Store อีกที (เช่นอุปกรณ์บริหารนิ้วมือท่านชาย ที่ขายเกลื่อนบนลาซาด้า)

แต่ทุกครั้งที่ Customer เข้ามาดึงข้อมูลจาก Store ก็ไม่ได้หมายความว่ามันจะมีสินค้าใหม่เข้ามาทุกครั้ง ทำให้ในหลายๆครั้งที่ไปดึงข้อมูลมันจะทำงานฟรี ทั้ง Customer และ Store เลย

เกร็ดความรู้ - ไม่อ่านก็ได้แค่งอนนิดๆ ทุกๆครั้งที่ client ขอให้เซิฟเวอร์ทำงาน นั่นหมายถึงเซิฟเวอร์จะต้องเสียความสามารถในการรับ request จาก client ไป (เป็นเหตุผลว่าทำไมบางเว็บเราไปรุมกด refresh รัวๆแล้วมันถึงล่ม, แต่เบื้องหลังจริงๆเซิฟเวอร์ไม่ได้กากแบบนั้นหรอก ที่มันล่มเพราะมันมีตัวแม่ทัพใช้ IoT ยิงมาถล่มจากหลังฉากต่างหาก) ซึ่งข้อเสียของมันคือ ทำให้เซิฟเวอร์และ client เสียแรงทำงานฟรี

และในทางกลับกัน ถ้าทุกครั้งที่มีสินค้าใหม่เข้ามา ระบบก็จะแจ้งไปหา Customer ทุกคนแทนละ ?? (นี่มันระบบ Spam ชัดๆ) คงมีลูกค้าบางคนแฮปปี้ แต่เสียงตอบรับส่วนใหญ่น่าจะกร่นด่าเป็นแน่แท้ ตามรูปเลย

ดูเหมือนว่าเราจะเจอปัญที่เป็นงูกินหางแล้วละ ว่าจะให้ลูกค้าเสียเวลามาเช็คของเองเรื่อยๆ ทั้งๆที่ส่วนใหญ่ไม่มีอะไรอัพเดท หรือเราจะส่งข้อความไปแจ้งลูกค้าทุกคน ทั้งๆที่มีแค่ลูกค้าส่วนน้อยเท่านั้นที่สนใจ

😄 วิธีแก้ไข

วิธีการแก้นั้นแสนจะง่าย ก่อนอื่นเรามากำหนดคำที่ใช้เรียกสิ่งต่างๆกันก่อนเลยดีกว่า

  1. อะไรก็แล้วแต่ที่มีคนสนใจอยากรู้สถานะของมัน เราจะเรียกมันว่า Subject (ในตัวอย่างนี้คือ สถานะว่ามีสินค้าใหม่หรือเปล่า)

  2. เมื่อไหร่ก็ตามที่ Subject มีการเปลี่ยนแปลง ดังนั้นทำให้เราต้องทำการส่งข้อความแจ้งเตือนออกไป เราจะเรียกเจ้าตัวที่คอยส่งการแจ้งเตือนออกไปว่า Publisher (ในตัวอย่างนี้คือ Store)

  3. ใครก็ตามที่สนใจอยากรู้ว่า Subject มีการเปลี่ยนแปลงไหม เราจะเรียกเจ้าพวกนี้ว่า Subscriber (ในตัวอย่างนี้คือ Customer)

กลับมาที่หลักการของ Observer Pattern ของเราต่อบ้าง ซึ่งเจ้า pattern นี้เสนอว่า ตัว Publisher จะต้องมีช่องทางให้คนที่สนใจ(Subscriber) สามารถขอเข้ามาติดตาม(subscribe) หรือ ยกเลิกการติดตาม(unsubscribe) ได้

จากหลักการที่ว่ามา เลยทำให้เจ้า Publisher มี method 2 ตัว คือ Subscribe และ Unsubscribe เพื่อคอยเก็บว่า ใครบ้างที่สนใจจะรับข่าวสาร และ ใครบ้างที่ยกเลิกการขอรับข่าวสารตามรูปเลย

คราวนี้เมื่อตัว Subject มีการอัพเดทเกิดขึ้น เจ้า Publisher ก็จะส่งการแจ้งเตือนให้กับเหล่า Subscriber ที่ได้ขอเข้ามาติดตามข่าวสารนั่นเอง ตามรูปเลย

สุดท้ายเจ้า Publisher ที่คอยจำว่ามีใครบ้างที่สนใจจะรับข่าวสาร มันจะไม่จำ Subscriber เป็น concrete class (เพราะเราไม่อยากทำให้เกิด coupling ขึ้น) ดังนั้น พวก Subscriber จะต้อง implement interface เดียวกัน ทำให้ Publisher ทำงานกับ Subscriber ผ่านทาง interface เท่านั้น

สรุปคือ เราสามารถสร้างช่องทางการแจ้งเตือน ให้กับ object ที่สนใจในจะรับฟังจริงๆเท่านั้น และไม่ทำให้ client ต้องมาทำงานฟรีๆเพราะไม่มีข้อมูลใหม่อัพเดทอีกด้วย :D

📌 โครงสร้างของ pattern นี้

อธิบาย 1.Publisher - คอยแจ้งเตือนให้กับเหล่า subscriber เมื่อ subject มีการอัพเดท และรู้จักกับเหล่า subscriber ผ่านทาง interface เท่านั้น 2.เมื่อ subject มีการอัพเดท มันจะไปดูว่ามี subscriber ไหนบ้าง ที่ขอรับการแจ้งเตือน แล้วทำการแจ้งเตือนไปให้กับ subscriber เหล่านั้น 3.Subscriber - เป็น interface กลางให้กับ concrete subscriber ซึ่งตัวมันจะมี method สำหรับรับการแจ้งเตือน เพื่อให้ Publisher เรียกใช้ ซึ่ง Publisher จะรู้จักแค่ตัวนี้เท่านั้น 4.Concrete Subscribers - ใครก็ตามที่สนใจอยากจะรับการแจ้งเตือน จะต้อง implement Subscriber Interface แล้วคอยดำเนินการอื่นๆต่อเมื่อได้รับการแจ้งเตือนนั้นมาแล้ว 5.ในบางที subscriber อาจจะต้องการ context ด้วย เพื่อให้มันทำงานได้ถูกต้อง ดังนั้นในบางที Publisher ก็อาจจะส่งข้อมูลเข้ามาเป็น parameter ด้วยก็ได้ 6.Client - เป็นคนส่ง subscriber ให้กับ Publisher เพื่อระบุว่า object ไหน สนใจ/ไม่สนใจ ที่จะรับข่าวสารแล้ว

🛠 ตัวอย่างการนำไปใช้งาน

ในรอบนี้เราจะมาลองเขียนโปรแกรมส่งข้อความไปให้กับนักเรียนและอาจารย์ภายในโรงเรียนกันบ้าง โดยใช้ Observer Pattern เข้ามาช่วย ปะไปดูโค้ดตัวอย่างกันเลย

👍 ข้อดี

  • ส่งการแจ้งเตือนให้กับคนที่สนใจจะรับข่าวสารนั้นจริงๆ

👎 ข้อเสีย

  • ในแต่ละภาษาส่วนใหญ่จะรองรับเรื่องพวกนี้อยู่แล้ว ไปศึกษาภาษาที่ตัวเองใช้จะดีกว่า

  • ถ้าจะส่งให้เป็นลำดับ จะต้องไปเขียนเพิ่ม

‍‍📝 Code ตัวอย่าง

using System;
using System.Collections.Generic;

// Subscriber Interface
interface ISubscriber
{
    void Update(string msg);
}

// Concrete Subscribers
class Student : ISubscriber
{
    public void Update(string msg)
        => Console.WriteLine($"นักเรียนได้รับข้อความใหม่ว่า, {msg}");
}
class Teacher : ISubscriber
{
    public void Update(string msg)
        => Console.WriteLine($"อาจารย์ได้รับข้อความใหม่ว่า, {msg}");
}

// Publisher
class SchoolMessager
{
    private IList<ISubscriber> subscribers;

    public SchoolMessager()
        => subscribers = new List<ISubscriber>();

    public void Subscribe(ISubscriber newSubscriber)
        => subscribers.Add(newSubscriber);
    
    public void Unsubscribe(ISubscriber newSubscriber)
        => subscribers.Remove(newSubscriber);

    public void SendMessage(string msg)
    {
        foreach(var it in subscribers)
        {
            it.Update(msg);
        }
    }
}

// Client
class Program
{
    static void Main(string[] args)
    {
        var student = new Student();
        var teacher = new Teacher();

        var publisher = new SchoolMessager();
        publisher.Subscribe(student);
        publisher.Subscribe(teacher);

        Console.WriteLine("โรงเรียนประกาศข้อความออกไป");
        publisher.SendMessage("ขณะนี้ฝุ่น 2.9 ระบาดในโรงเรียนแล้วนะจุ๊");

        Console.WriteLine("นักเรียนไม่ต้องการรับข่าวสารอีกต่อไป");
        publisher.Unsubscribe(student);

        Console.WriteLine("โรงเรียนประกาศข้อความออกไป");
        publisher.SendMessage("ขอให้คุณครูทุกคนจับเด็กเอาไว้ก่อน อย่าพึ่งปล่อยให้มันหนีไป");
    }
}

Output

โรงเรียนประกาศข้อความออกไป
นักเรียนได้รับข้อความใหม่ว่า, ขณะนี้ฝุ่น 2.9 ระบาดในโรงเรียนแล้วนะจุ๊
อาจารย์ได้รับข้อความใหม่ว่า, ขณะนี้ฝุ่น 2.9 ระบาดในโรงเรียนแล้วนะจุ๊
นักเรียนไม่ต้องการรับข่าวสารอีกต่อไป
โรงเรียนประกาศข้อความออกไป
อาจารย์ได้รับข้อความใหม่ว่า, ขอให้คุณครูทุกคนจับเด็กเอาไว้ก่อน อย่าพึ่งปล่อยให้มันหนีไป

Note สำหรับภาษา C# นั้นทีมพัฒนาได้มีคำสั่งในการทำงานกับของพวกนี้อยู่แล้ว นั่นคือ นั่นเอง โยมไม่ต้องไปเขียนใหม่ให้เมื่อยมือหรอก และยังมีพวก ไม่ก็ อีก กดที่ชื่อพวกนั้นเพื่อไปหาศึกษาดูเอาเองนะจ๊ะ

🤴
🦈
event
IObserver, IObservable
Rx
img
img
img
img
img