前言

要学好编程,或者说是软件开发,学好设计模式也是重要的一关(亲身体会!!!对于框架少的一些小众语言得自己去搭框架,不论开发还是维护,还是很费劲得),即便是有很多现成的框架可以使用,学好设计模式对框架优化或性能提升还是有帮助得。下面开始学习python下得观察者模式。
在这里插入图片描述


一、观察者模式是什么?

观察者模式属于行为模式,核心包含观察者(Subject)、被观察者(Observer),用于一对多的场景,当要将数据发给多个目标时,通过被观察者,它会发送给所有观察者。

在这里插入图片描述

核心方法:

  • 观察者:数据发布方法 update()
  • 被观察者:
    数据订阅方法 attach()
    取消订阅方法 detach()
    数据通知 notify()

由于数据的发布的对像可能不止一个、数据的观察者(关注者)的对像也不同,因此观察者模式也比设计为:被观察者接口(SubjectInterface)、具体观察者对像(Subject)、观察者接口(ObserverInterface)、具体观察者(Observer)。

一个典型的应用就是发布-订阅模型。

二、Python中观察者模式实现

1.引入库

在Python里面设计接口用到abc(abstract base classes,ABCs)模块,用到元类ABCMetaabstractmethod方法,继承抽象类的对像必须实现abstractmethod装饰的方法。

from abc import ABCMeta, abstractmethod

class Interface(metaclass=ABCMeta):
    @abstractmethod
    def func(self):
        pass


class ConcreateInterface(Interface):
    def func(self):
        print("实现接口方法")       

2.观察者模式在python实现

(1)观察者接口

from abc import ABCMeta, abstractmethod


# 观察者接口
class ObserverInterface(metaclass=ABCMeta):
    @abstractmethod
    def update(self, subject, message):
        pass

(2)观察对像

# 观察对像
class SubjectInterface:

    @abstractmethod
    def attach(self, observer):
        pass

    @abstractmethod
    def detach(self, observer):
        pass

    @abstractmethod
    def notify(self, message):
        pass

(3)具体被观察对像

class ConcreateSubject(SubjectInterface):
    def __init__(self):
        self._observers = []

    def attach(self, observer):
        self._observers.append(observer)

    def detach(self, observer):
        self._observers.remove(observer)

    def notify(self, message):
        for observer in self._observers:
            observer.update(self, message)

    def get_observers(self):
        return self._observers

(4)具体观察者

# 观察者
class ConcreateObserver(ObserverInterface):
    def update(self, subject, message):
        print(f"接收到主题{subject}的通知:{message}")

(5)实例化

if __name__ == "__main__":
    subject = ConcreateSubject()
    observer1 = ConcreateObserver()
    observer2 = ConcreateObserver()

    subject.attach(observer1)
    subject.attach(observer2)

    subject.notify("test")

打印结果

接收到主题<__main__.ConcreateSubject object at 0x0000021EA31280A0>的通知:tetst
接收到主题<__main__.ConcreateSubject object at 0x0000021EA31280A0>的通知:tetst

三、发布-订阅模式

在这里插入图片描述


直接上代码:

from abc import abstractmethod, ABCMeta


class PublishInterface(metaclass=ABCMeta):
    @abstractmethod
    def update(self, message):
        pass


# 订阅主题
class Subject:
    def __init__(self):
        self._subscribers = []

    # 订阅
    def subscribe(self, subscriber):
        self._subscribers.append(subscriber)

    # 取消订阅
    def unsubscribe(self, observer):
        self._subscribers.remove(observer)

    def publish(self, message):
        for subscriber in self._subscribers:
            subscriber.update(message)

    def get_subscribers(self):
        return self._subscribers


# 观察者
class Subscriber(PublishInterface):
    def update(self, message):
        print(f"接收到主题的通知:{message}")


class Server:
    def __init__(self):
        super().__init__()
        self.users = {}  # 模拟用户信息存储
        self.subjects = {}  # 主题管理

    def user_register(self, customer):
        user = customer.username
        if user not in self.users.keys():
            self.users[customer.username] = customer.pwd

    def user_unregister(self, username):
        self.users.pop(username)

    def subscribe_with_subject(self, customer, subject=''):
        user = customer.username
        if user in self.users.keys():
            # 不存在则创建主题
            if subject in self.subjects:
                self.subjects.get(subject).subscribe(customer)
            # 否则直接添加
            else:
                subject_ = Subject()
                subject_.subscribe(customer)
                self.subjects[subject] = subject_
        else:
            print("请先注册!!!")

    def unsubscribe_with_subject(self,  customer, subject=''):
        self.subjects.get(subject).unsubscribe(customer)

    def print_subjects_info(self):
        print("\n***************订阅管理信息表*************************")
        for subject, subject_obj in self.subjects.items():
            print(f"{subject}:")
            for subscriber in subject_obj.get_subscribers():
                print(f"\t{subscriber.username}")

    def print_subjects_by_user(self, user):
        print("\n***************用户订阅信息表*************************")
        print(f"{user}:")
        for subject, subject_obj in self.subjects.items():
            for subscriber in subject_obj.get_subscribers():
                if user == subscriber.username:
                    print(f"\t{subject}")

    def sports_notify(self):
        print("**********************发布体育讯息*********************")
        self.subjects.get("体育").publish("发布了一条体育讯息!\n")

    def technology_notify(self):
        print("**********************发布科技报道*********************")
        self.subjects.get("科技").publish("发布了一条科技报道!\n")


class Customer(Subscriber):
    def __init__(self, username, pwd):
        super().__init__()
        self.username = username
        self.pwd = pwd

    def update(self, message):
        print(f"****************<{self.username}>:接受订阅信息********")
        print(f"我是用户:{self.username},接收到订阅消息:{message}\n")


if __name__ == "__main__":

    server = Server()

    customer1 = Customer("Lily", "tets123")
    customer2 = Customer("Aobama", "tets00123")

    server.subscribe_with_subject(customer1, "体育")
    server.subscribe_with_subject(customer1, "科技")

    server.subscribe_with_subject(customer2, "科技")

    server.user_register(customer1)
    server.user_register(customer2)

    server.subscribe_with_subject(customer1, "体育")
    server.subscribe_with_subject(customer1, "科技")

    server.subscribe_with_subject(customer2, "科技")

    server.print_subjects_info()
    server.print_subjects_by_user(customer1.username)

    server.unsubscribe__with_subject(customer1, "科技")
    server.print_subjects_info()
    server.print_subjects_by_user(customer1.username)

    server.sports_notify()
    server.technology_notify()

打印结果:

请先注册!!!
请先注册!!!
请先注册!!!

***************订阅管理信息表*************************
体育:
	Lily
科技:
	Lily
	Aobama

***************用户订阅信息表*************************
Lily:
	体育
	科技

***************订阅管理信息表*************************
体育:
	Lily
科技:
	Aobama

***************用户订阅信息表*************************
Lily:
	体育
**********************发布体育讯息*********************
****************<Lily>:接受订阅信息********
我是用户:Lily,接收到订阅消息:发布了一条体育讯息!


**********************发布科技报道*********************
****************<Aobama>:接受订阅信息********
我是用户:Aobama,接收到订阅消息:发布了一条科技报道!

在这里插入图片描述


总结

虽然很懒,还是写点吧!

  • 本次学习的重点就是观察者模式的思想核心

对像:被观察者接口、具体被观察者、观察者接口、具体观察者

观察者:数据发布方法 update()

被观察者:
数据订阅方法 attach()
取消订阅方法 detach()
数据通知 notify()

  • 以及python里面接口的定义:ACBMeta元类、abstractmethod方法。

在这里插入图片描述

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐