ITPub博客

首页 > 数据库 > 数据库开发技术 > python 面向对象设计模式实践篇(16)-行为型:观察者模式(订阅发布模式)

python 面向对象设计模式实践篇(16)-行为型:观察者模式(订阅发布模式)

原创 数据库开发技术 作者:程序员小钟同学 时间:2021-03-26 15:42:47 0 删除 编辑

行为型模式概述

定义:前篇初期中,我们讲过行为型模式主要解决的问题是:

用于在不同的实体建进行通信,为实体之间的通信提供更容易,更灵活的通信方法。

特性:

  • 1:关注对象之间的交互和对象的响应
  • 2:对象的交互过程中能保持松散耦合
  • 3:不同的对象之间划分责任和算法的抽象化

观察者模式(订阅发布模式)


所属分类

  • 行为型模式

意图

  • 它定义了对象之间的一对多的依赖关系,从而使得一个对象中的任何更改都将自动通知其他依赖对象。

角色对象


  1. 主题(Subject):被观察者监听的事件消息,提供可以对观察者对象注册添加或删除的接口。

    1. 观察者(Observer)抽象类:定义了具体的观察者再接收到获得相关主题消息后,需要操作处理的逻辑。

    1. 具体观察者(ConcreteObserver):实现观察者(Observer)抽象类具体的方法。

    具体的角色职责:

    • 多个观察者对象同时监听某一个主题对象
    • 当这个主题对象的状态发生变化,则会通知所有关联的观察者对象,
    • 观察者对象可以感知状态变化并作出相应的逻辑做出。

    实践

    模拟一个新闻消息,订阅了这个新闻消息的人,都可以接收到这消息,并且根据消息做出自己的反应!

    #!/usr/bin/evn python
    # coding=utf-8

    from abc import ABCMeta, abstractmethod


    class ObserverMetaclass(metaclass=ABCMeta):
        '''
        抽象观察者
        '
    ''

        def __init__(self, observer_name=None, subject_even=None):
            self.observer_name = observer_name  # 观察者名称
            self.subject_event = subject_even # 关注的主题对象(一个主题对象里面存在一个列表,可以存很多的观察者)
            # 添加到一个主题事件列表里面---作为其中一员
            self.subject_event.add_observer(self)

        @abstractmethod
        def dosomething_change(self,event_name):pass # 接收主题消息通知后我们响应变化逻辑处理

    class SubjectEvent(metaclass=ABCMeta):
        '''
        主题对象方法抽象
        '
    ''

        def __init__(self, event_name=None):
            # 所有的观察者对象
            self.all_observer = []
            self.event_name = event_name

        # 观察者注册---事件关注
        @abstractmethod
        def add_observer(self, observer): pass

        # 观察者注销--取消事件关注
        @abstractmethod
        def del_observer(self, observer): pass

        # 事件通知
        @abstractmethod
        def event_notify(self): pass



    # ===================================================================================


    # 娱乐新闻事件
    class YuleiNews(SubjectEvent):

        # 观察者注册---事件关注
        def add_observer(self, observer):
            self.all_observer.append(observer)

        # 观察者注销--取消事件关注
        def del_observer(self, observer):
            self.all_observer.remove(observer)

        # 事件通知
        def event_notify(self):
            print("广播通知主题消息", self.event_name)
            for observer in self.all_observer:
                observer.dosomething_change(self.event_name)


    class Xiaozhongtongxue(ObserverMetaclass):
        '''
        具体观察者对象
        '
    ''
        def dosomething_change(self,event_name):
            print("%s接收到主题消息%s"%(self.observer_name,event_name),"开始震惊了!!!!")


    class Xiaoaitongxue(ObserverMetaclass):
        '''
        具体观察者对象
        '
    ''
        def dosomething_change(self,event_name):
            print("%s接收到主题消息%s"%(self.observer_name,event_name),"开始哭了!!!!")

    # 定义一个新闻主题事件对象
    jiehun_enent = YuleiNews(event_name="XXXX结婚了!")


    # # 我关注了娱乐新闻主题频道
    Xiaozhongtongxue(observer_name="小钟同学",subject_even=jiehun_enent)
    # # 小爱关注了娱乐新闻主题频道
    Xiaoaitongxue(observer_name="小爱同学",subject_even=jiehun_enent)


    # 开始主题时间新闻的发布:
    jiehun_enent.event_notify()

    输出结果:

    广播通知主题消息 XXXX结婚了!
    小钟同学接收到主题消息XXXX结婚了! 开始震惊了!!!!
    小爱同学接收到主题消息XXXX结婚了! 开始哭了!!!!

    上面这种方式是一种推消息的方法。

    还有一种拉消息的方式,由观察者去拉取主题消息

    #!/usr/bin/evn python
    # coding=utf-8

    from abc import ABCMeta, abstractmethod


    class ObserverMetaclass(metaclass=ABCMeta):
        '''
        抽象观察者
        '
    ''

        def __init__(self, observer_name=None, subject_event=None):
            self.observer_name = observer_name  # 观察者名称
            self.subject_event = subject_event # 关注的主题对象(一个主题对象里面存在一个列表,可以存很多的观察者)
            # 添加到一个主题事件列表里面---作为其中一员
            self.subject_event.add_observer(self)

        def get_subject_event(self):
            print("拉取通知主题消息,且开始接收,又全部广播一次")
            # 遍历所有的主题执行主题广播
            self.subject_event.event_notify()

        @abstractmethod
        def dosomething_change(self,event_name):pass # 接收主题消息通知后我们响应变化逻辑处理



    class SubjectEvent(metaclass=ABCMeta):
        '''
        主题对象方法抽象
        '
    ''

        def __init__(self, event_name=None):
            # 所有的观察者对象
            self.all_observer = []
            self.event_name = event_name

        # 观察者注册---事件关注
        @abstractmethod
        def add_observer(self, observer): pass

        # 观察者注销--取消事件关注
        @abstractmethod
        def del_observer(self, observer): pass

        # 事件通知
        @abstractmethod
        def event_notify(self): pass



    # ===================================================================================


    # 娱乐新闻事件
    class YuleiNews(SubjectEvent):

        # 观察者注册---事件关注
        def add_observer(self, observer):
            self.all_observer.append(observer)

        # 观察者注销--取消事件关注
        def del_observer(self, observer):
            self.all_observer.remove(observer)

        # 事件通知
        def event_notify(self):
            print("广播通知主题消息", self.event_name)
            for observer in self.all_observer:
                observer.dosomething_change(self.event_name)


    class Xiaozhongtongxue(ObserverMetaclass):
        '''
        具体观察者对象
        '
    ''
        def dosomething_change(self,event_name):
            print("%s接收到主题消息%s"%(self.observer_name,event_name),"开始震惊了!!!!")


    class Xiaoaitongxue(ObserverMetaclass):
        '''
        具体观察者对象
        '
    ''
        def dosomething_change(self,event_name):
            print("%s接收到主题消息%s"%(self.observer_name,event_name),"开始哭了!!!!")


    class Langtongxue(ObserverMetaclass):
        '''
        具体观察者对象
        '
    ''
        def dosomething_change(self,event_name):
            print("%s接收到主题消息%s"%(self.observer_name,event_name),"开始不安分了!!!!")



    # 定义一个新闻主题事件对象
    jiehun_enent = YuleiNews(event_name="XXXX结婚了!")


    # # 我关注了娱乐新闻主题频道
    Xiaozhongtongxue(observer_name="小钟同学",subject_event=jiehun_enent)
    # # 小爱关注了娱乐新闻主题频道
    Xiaoaitongxue(observer_name="小爱同学",subject_event=jiehun_enent)


    # 开始主题时间新闻的发布:
    jiehun_enent.event_notify()

    print("*"*30)
    # # 小爱关注了娱乐新闻主题频道
    Langtongxue(observer_name="lang同学",subject_event=jiehun_enent).get_subject_event()

    输出结果:

    广播通知主题消息 XXXX结婚了!
    小钟同学接收到主题消息XXXX结婚了! 开始震惊了!!!!
    小爱同学接收到主题消息XXXX结婚了! 开始哭了!!!!
    ******************************
    拉取通知主题消息,且开始接收,又全部广播一次
    广播通知主题消息 XXXX结婚了!
    小钟同学接收到主题消息XXXX结婚了! 开始震惊了!!!!
    小爱同学接收到主题消息XXXX结婚了! 开始哭了!!!!
    lang同学接收到主题消息XXXX结婚了! 开始不安分了!!!!

    总结特性

    • 主题对观察者唯一了解的就是实现一个特定的接口。
    • 主题不需要了解具体的观察者类的实现。
    • 可以随时添加任意的新观察者。
    • 添加新观察者,不需要修改主题,只需订阅主题
    • 观察者和主题没有绑定一起,可以彼此独立使用
    • 观察者中的变化不会主题消息发布,互不影响。

    优点和缺点

    优点:

    • 主题和观察者彼此交互的对象之间保持松耦合。
    • 看随时新增新观察者,无需对主题或观察者进行任何修改

    缺点:

    • 通知可能不可靠,或延迟或不一致

    适用场景

    • 消息发布和订阅机制。和我们的redis的发布订阅机制一样的模式。

    个人其他博客地址

    简书:https://www.jianshu.com/u/d6960089b087

    掘金:https://juejin.cn/user/2963939079225608

    小钟同学 | 文 【原创】| QQ:308711822

    • 1:本文相关描述主要是个人的认知和见解,如有不当之处,还望各位大佬指正。
    • 2:关于文章内容,有部分内容参考自互联网,如有链接会声明标注;如没有及时标注备注的链接的,如有侵权请联系,我会立即删除处理哟。


    原文作者:程序员小钟同学;如有侵权,请联系管理员删除。

    请登录后发表评论 登录
    全部评论

    注册时间:2021-02-20

    • 博文量
      224
    • 访问量
      111734