iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 23
1
Software Development

Learning Design Pattern in 30 real-case practices系列 第 23

察言觀色! 敵不動,我不動! (Observer 觀察者模式)

  • 分享至 

  • xImage
  •  

Observer 觀察者模式

定義

定義對象之間的一對多依賴關係,當一個對象更改狀態時,會自動通知並更新其所有依賴的對象。(WIKI)

UML

  1. Observer : 觀察者,必須有讓Subject可以Notify的方法。
  2. Subject:可以訂閱、取消訂閱Observer,並有Notify所有訂閱的Observer的方法。

我們在
Day20.Visitor訪問者模式ObjectStructure
以及
Day22.Command命令模式Invoker
皆使用了觀察者模式的特性。

底下的範例,是在使用者申請一張請假單時,電子表單系統於請假日當天

  1. 通知交換機自動指定轉接給代理人員
  2. 通知Mail Server將收到的eMail副本給代理人員

Observer

  • C#
public interface IObserver
{
        void Update(string absence, string designee);
}
public class ObserverPbx : IObserver
{
    public void Update(string absence, string designee)
    {
        Trace.WriteLine($"[PBX] 已指定轉接{absence}的來電給{designee}!");
    }
}
public class ObserverMailServer : IObserver
{
    public void Update(string absence, string designee)
    {
        Trace.WriteLine($"[Mail Server] 已設定將{absence}的信副本給{designee}!");
    }
}
  • Python
from abc import ABC, abstractmethod

class Observer(ABC):

    @abstractmethod
    def update(self,absence:str, designee:str):
        pass

class ObserverPbx(Observer):

    def update(self,absence:str, designee:str):
        print("[PBX] 已指定轉接{0}的來電給{1}!".format(absence, designee))

class ObserverMailServer(Observer):

    def update(self,absence:str, designee:str):
        print("[Mail Server] 已設定將{0}的信副本給{1}!".format(absence, designee))

Subject

  • C#
public interface ISubject
{
    List<IObserver> Observers { get; set; }
    void Attach(IObserver observer);
    void Detach(IObserver observer);
    void Notify(string absence, string designee);
}

public class SubjectEflow:ISubject
{
    public List<IObserver> Observers { get; set; }
    public SubjectEflow()
    {
        this.Observers = new List<IObserver>();
    }
    public void Attach(IObserver observer)
    {
        if (!this.Observers.Contains(observer))
            this.Observers.Add(observer);
    }
    public void Detach(IObserver observer)
    {
        if (this.Observers.Contains(observer))
            this.Observers.Remove(observer);
    }
    public void Notify(string absence, string designee)
    {
        foreach (IObserver observer in this.Observers)
        {
            observer.Update(absence, designee);
        }
    }
}
  • Python
from abc import ABC, abstractmethod
from Observers import Observer

class Subject(ABC):

    def __init__(self):
        self.observers=[]

    @abstractmethod
    def attach(self,observer: Observer): 
        pass

    def detach(self,observer: Observer):
        pass

    def notify(self, absence:str, designee:str):
        pass

class SubjectEflow(Subject):

    def __init__(self):
        super().__init__()

    def attach(self,observer: Observer): 
        self.observers.append(observer)

    def detach(self,observer: Observer):
        self.observers.remove(observer)

    def notify(self, absence:str, designee:str):
        for observer in self.observers:
            observer.update(absence, designee)

主程式如下。

  • C#
//Create observers
IObserver pbx = new ObserverPbx();
IObserver ms = new ObserverMailServer();

//Create subject
ISubject subject = new SubjectEflow();
subject.Attach(pbx);
subject.Attach(ms);

//Notify when JB is leave of absence
subject.Notify("JB", "Hachi");
  • Python
# Create observers
pbx = ObserverPbx()
ms = ObserverMailServer()
    
# Create subject
subject = SubjectEflow()
subject.attach(pbx)
subject.attach(ms)

# Notify when JB is leave of absence
subject.notify("JB", "Hachi")

輸出結果:

[PBX] 已指定轉接JB的來電給Hachi
[Mail Server] 已設定將JB的信副本給Hachi!

Sample Codes

  1. C#
  1. Python

上一篇
讓你當一天艾森豪,來指揮諾曼地登陸作戰! (Command 命令模式)
下一篇
別再因為發號碼牌重複被客訴! (Singleton 單例模式)
系列文
Learning Design Pattern in 30 real-case practices30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0

林正英曰:敵不動,我不動。
洪金寶:如果兩個都不動,豈不是很容易站到年卅晚上。

我要留言

立即登入留言