大话设计模式:第14章 观察者模式

第14章:观察者模式

观察者模式

观察者(observer)模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自已。

在这里插入图片描述

Subject类:主题或抽象通知者,一般用一个抽象类或者一个接口实现。它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。

在这里插入图片描述

Observer类:抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者一般用一个抽象类或者一个接口实现。更新接口通常包含一个更新方法Update()方法。

在这里插入图片描述

ConcreteSubject类:具体主题或具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。

在这里插入图片描述

ConcreteObserver类:具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。具体观察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。

在这里插入图片描述

客户端代码

在这里插入图片描述

结果显示

在这里插入图片描述

from abc import ABC, abstractmethod
from typing import Text
class Observer(ABC):
    
    @abstractmethod
    def update(self):
        pass
        
class Subject(ABC):
    
    def __init__(self) -> None:
        self.__observers = []
        
    def attach(self, observer: Observer) -> None:
        """增加观察者"""
        self.__observers.append(observer)
        
    def detach(self, observer: Observer) -> None:
        """移除观察者"""
        self.__observers.remove(observer)
        
    def notify(self) -> None:
        """通知"""
        for observer in self.__observers:
            observer.update()
            
class ConcreteSubject(Subject):
    
    def __init__(self) -> None:
        super(ConcreteSubject, self).__init__()
        self.__subject_state = None
        
    @property
    def subject_state(self) -> Text:
        return self.__subject_state
    @subject_state.setter
    def subject_state(self, value: Text) -> None:
        self.__subject_state = value
        
class ConcreteObserver(Observer):
    
    def __init__(self, subject: ConcreteSubject, name: Text) -> None:
        self.__name = name
        self.__observer_state = None
        self.__subject = subject
        
    def update(self) -> None:
        self.__observer_state = self.__subject.subject_state
        print("观察者{}的新状态是{}".format(self.__name, self.__observer_state))
        
    @property
    def subject(self) -> ConcreteSubject:
        return self.__subject
    @subject.setter
    def subject(self, value: ConcreteSubject) -> None:
        self.__subject = value
        
if __name__ == "__main__":
    
    s = ConcreteSubject()
    
    s.attach(ConcreteObserver(subject=s, name="X"))
    s.attach(ConcreteObserver(subject=s, name="Y"))
    s.attach(ConcreteObserver(subject=s, name="Z"))
    
    s.subject_state = "ABC"
    s.notify()
    
观察者X的新状态是ABC
观察者Y的新状态是ABC
观察者Z的新状态是ABC

观察者模式特点

观察者模式的动机:将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性门我们不希望为了维持一致性而使各类紧密锅合甲这样会给维护、扩展和重用都带来不便。

观察者模式的关键对象是主题Subject和观察者Observer,一个Subject可以有任意目的依赖于它的Observer,一旦Subject的状态发生了改变,所有的Observer都可以得到通知。Subject发出通知时并不需要知道谁是它的观察者。而任何一个具体观察者不知道也不需要知道其他观察者的存在

观察者模式的使用

  1. 当一个对象的改变需要同时改变其他对象的时候时,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式

  2. 当一个抽象模型有两个方面,其中一方面依赖于另一方面。这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。

观察者模式所做的工作是在解除耦合,让耦合双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的变化。

观察者模式示例

任务:前台监督老板是否已经到来,并通知同事

在这里插入图片描述

from abc import ABC, abstractmethod
from typing import Text
class Observer(ABC):
    
    def __init__(self, name: Text, sub: object) -> None:
        self._name = name
        self._sub = sub
    
    @abstractmethod
    def update(self) -> None:
        pass
class Subject(ABC):
    
    def __init__(self) -> None:
        self._subject_state = None
    
    @abstractmethod
    def attach(self, observer: Observer) -> None:
        pass
    
    @abstractmethod
    def detach(self, observer: Observer) -> None:
        pass
    
    @abstractmethod
    def notify(self) -> None:
        pass
    
    @property
    def subject_state(self) -> Text:
        return self._subject_state
    @subject_state.setter
    def subject_state(self, value: Text) -> None:
        self._subject_state = value
class Boss(Subject):
    
    def __init__(self):
        # 同事列表
        self.__observers = []
        self.__action = ""
        super(Boss, self).__init__()
        
    def attach(self, observer: Observer) -> None:
        """
        增加
        """
        self.__observers.append(observer)
        
    def detach(self, observer: Observer) -> None:
        """
        减少
        """
        self.__observers.remove(observer)
        
    def notify(self) -> None:
        """
        通知
        """
        for o in self.__observers:
            o.update()
            
    @property
    def action(self) -> Text:
        return self.__action
    @action.setter
    def action(self, value: Text) -> None:
        self.__action = value
        
        
class Secretary(Subject):
    
    def __init__(self):
        # 同事列表
        self.__observers = []
        self.__action = ""
        super(Secretary, self).__init__()
        
    def attach(self, observer: Observer) -> None:
        """
        增加
        """
        self.__observers.append(observer)
        
    def detach(self, observer: Observer) -> None:
        """
        减少
        """
        self.__observers.remove(observer)
        
    def notify(self) -> None:
        """
        通知
        """
        for o in self.__observers:
            o.update()
            
    @property
    def action(self) -> Text:
        return self.__action
    @action.setter
    def action(self, value: Text) -> None:
        self.__action = value
        
class StockObserver(Observer):
    def __init__(self, name: Text, sub: Subject) -> None:
        super(StockObserver, self).__init__(name, sub)
        
    def update(self) -> None:
        print(
            "{}{}关闭股票行情,继续工作!".format(
                self._sub.subject_state, self._name
            )
        )
        
class NBAObserver(Observer):
    def __init__(self, name: Text, sub: Subject) -> None:
        super(NBAObserver, self).__init__(name, sub)
        
    def update(self) -> None:
        print(
            "{}{}关闭NBA直播,继续工作!".format(
                self._sub.subject_state, self._name
            )
        )
if __name__ == "__main__":
    
    # 前台小姐童子喆
    tongzizhe = Secretary()
    
    # 看股票的同事
    tongshi1 = StockObserver("魏关姹", tongzizhe)
    # 看NBA的同事
    tongshi2 = NBAObserver("易管查", tongzizhe)
    
    # 前台记下两位同事
    tongzizhe.attach(tongshi1)
    tongzizhe.attach(tongshi2)
    # 发现老板回来了
    tongzizhe.subject_state = "老板回来了!"
    # 发出通知
    tongzizhe.notify()
    
    # 前台未能发出通知    
    # 老板胡汉三
    huhansan = Boss()
    
    # 看股票的同事
    tongshi1 = StockObserver("魏关姹", huhansan)
    # 看NBA的同事
    tongshi2 = NBAObserver("易管查", huhansan)
    
    huhansan.attach(tongshi1)
    huhansan.attach(tongshi2)
    # 魏关姹未注意到老板回来
    huhansan.detach(tongshi1)
    
    # 老板回来了
    huhansan.subject_state = "我胡汉三又回来了!"
    # 发出通知
    huhansan.notify()
    
老板回来了!魏关姹关闭股票行情,继续工作!
老板回来了!易管查关闭NBA直播,继续工作!
我胡汉三又回来了!易管查关闭NBA直播,继续工作!

观察者模式的不足

尽管使用了依赖倒转原则,但是“抽象通知者”还是依赖“抽象观察者”,即万一没有抽象观察者这样的接口,通知的功能无法完成,此外,具体观察者不一定要调用“更新”方法。

事件委托

委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的‘类’,委托的实例将代表一个具体的函数。

一个委托可以搭载多个方法,所有方法被依次唤起。委托对象所搭载的方法并不需要属于同一个类。

委托的前提:委托对象所搭载的所有方法必须具有相同的原形和形式,即拥有相同的参数列表和返回值类型。

事件委托示例

from abc import ABC, abstractmethod, abstractproperty
from typing import Text

声明一个委托,名称叫EventHandler(事件处理程序),无参数,无返回值。

在这里插入图片描述

from typing import Callable

class EventHandler(object):
    
    def __init__(self) -> None:
        self.__events = []
    
    def __call__(self) -> None:
        for event in self.__events:
            event()
    def add(self, handler: Callable):
        self.__events.append(handler)
class Subject(ABC):
    
    @abstractmethod
    def notify(self) -> None:
        pass
    
    @abstractproperty
    def subject_state(self) -> Text:
        pass
    @subject_state.setter
    def subject_state(self, value: Text) -> None:
        pass
class Boss(Subject):
    def __init__(self) -> None:
        self.__action = None
        self.update = EventHandler()
        
    def notify(self) -> None:
        self.update()
        
    def subject_state(self) -> Text:
        return self.__action
    def subject_state(self, value: Text):
        self.__action = value
        
class Secretary(Subject):
    def __init__(self) -> None:
        self.__action = None
        self.update = EventHandler()
        
    def notify(self) -> None:
        self.update()
        
    def subject_state(self) -> Text:
        return self.__action
    def subject_state(self, value: Text):
        self.__action = value
        
class StockObserver(object):
    def __init__(self, name: Text, sub: Subject) -> None:
        self.__name = name
        self.__sub = sub
        
    def close_stock_market(self) -> None:
        print(
            "{}{}关闭股票行情,继续工作!".format(
                self.__sub.subject_state, self.__name
            )
        )
        
class NBAObserver(object):
    def __init__(self, name: Text, sub: Subject) -> None:
        self.__name = name
        self.__sub = sub
        
    def close_nba_direct_seeding(self) -> None:
        print(
            "{}{}关闭NBA直播,继续工作!".format(
                self.__sub.subject_state, self.__name
            )
        )
if __name__ == "__main__":
    
    # 前台小姐童子喆
    tongzizhe = Secretary()
    
    # 看股票的同事
    tongshi1 = StockObserver("魏关姹", tongzizhe)
    # 看NBA的同事
    tongshi2 = NBAObserver("易管查", tongzizhe)
    
    # 前台记下两位同事
    tongzizhe.update.add(tongshi1.close_stock_market)
    tongzizhe.update.add(tongshi2.close_nba_direct_seeding)
    # 发现老板回来了
    tongzizhe.subject_state = "老板回来了!"
    # 发出通知
    tongzizhe.notify()
    
    # 前台未能发出通知    
    # 老板胡汉三
    huhansan = Boss()
    
    # 看股票的同事
    tongshi1 = StockObserver("魏关姹", huhansan)
    # 看NBA的同事
    tongshi2 = NBAObserver("易管查", huhansan)
    
    # 将“看股票者”的“关闭股票程序”方法和
    # “看NBA者”的“关闭NBA直播”方法挂钩到“老板”的“更新”上,
    # 也就是将两不同类的不同方法委托给“老板”类的“更新”了
    huhansan.update.add(tongshi1.close_stock_market)
    huhansan.update.add(tongshi2.close_nba_direct_seeding)
    
    # 老板回来了
    huhansan.subject_state = "我胡汉三又回来了!"
    # 发出通知
    huhansan.notify()
    
老板回来了!魏关姹关闭股票行情,继续工作!
老板回来了!易管查关闭NBA直播,继续工作!
我胡汉三又回来了!魏关姹关闭股票行情,继续工作!
我胡汉三又回来了!易管查关闭NBA直播,继续工作!

猜你喜欢

转载自blog.csdn.net/zhaoyin214/article/details/105924389