【转】第01课:生活中的监听模式——一坑爹的热水器

      • 用程序来模拟生活
      • 从剧情中思考监听模式
        • 监听模式
      • 监听模式的模型抽象
        • 代码框架
        • 类图
        • 基于框架的实现
        • 模型说明
          • 设计要点
          • 推模型和拉模型
      • 应用场景

【故事剧情】

刚刚大学毕业的 Tony 只身来到北京这个硕大的城市,开始了北漂的生活。但刚刚毕业的他身无绝技、包无分文,为了生活只能住在沙河镇一个偏僻的村子里,每天坐着程序员专线(13号线)来回穿梭于昌平区与西城区……

在一个寒冷的冬天,下班之后要坐2个小时的地铁+公交才能回到住处,Tony 拖着疲惫的身体回到家。准备洗一个热水澡暖暖身体,耐何简陋的房子中用的还是90年代的热水器。因为热水器没有警报更没有自动切换模式的功能,所以烧热水必须得守着;不然时间长了烫死猪,时间短了又冷成狗。无奈的 Tony 背靠着墙,头望着天花板,深夜中做起了白日梦:一定要努力工作,过两个月我就可以自己买一个智能热水器了:水烧好了就发一个警报,我就可以直接去洗操。还要能自己设定模式,既可以烧开了用来喝,可以烧暖了用来洗……

enter image description here

用程序来模拟生活

Tony 陷入白日梦中……他的梦虽然在现实世界里不能立即实现,但在程序世界里可以。程序来源于生活,下面我们就用代码来模拟 Tony 的白日梦。

源码示例:

 
  1. class WaterHeater:

  2. "热水器:战胜寒冬的有利武器"

  3.  
  4. def __init__(self):

  5. self.__observers = []

  6. self.__temperature = 25

  7.  
  8. def getTemperature(self):

  9. return self.__temperature

  10.  
  11. def setTemperature(self, temperature):

  12. self.__temperature = temperature

  13. print("current temperature is:", self.__temperature)

  14. self.notifies()

  15.  
  16. def addObserver(self, observer):

  17. self.__observers.append(observer)

  18.  
  19. def notifies(self):

  20. for o in self.__observers:

  21. o.update(self)

  22.  
  23.  
  24. class Observer:

  25. "洗澡模式和饮用模式的父类"

  26.  
  27. def update(self, waterHeater):

  28. pass

  29.  
  30.  
  31. class WashingMode(Observer):

  32. "该模式用于洗澡用"

  33.  
  34. def update(self, waterHeater):

  35. if waterHeater.getTemperature() >= 50 and waterHeater.getTemperature() < 70:

  36. print("水已烧好,温度正好!可以用来洗澡了。")

  37.  
  38.  
  39. class DrinkingMode(Observer):

  40. "该模式用于饮用"

  41.  
  42. def update(self, waterHeater):

  43. if waterHeater.getTemperature() >= 100:

  44. print("水已烧开!可以用来饮用了。")

测试代码:

 
  1. def testWaterHeater():

  2. heater = WaterHeater()

  3. washingObser = WashingMode()

  4. drinkingObser = DrinkingMode()

  5. heater.addObserver(washingObser)

  6. heater.addObserver(drinkingObser)

  7. heater.setTemperature(40)

  8. heater.setTemperature(60)

  9. heater.setTemperature(100)

输出结果:

 
  1. current temperature is: 40

  2. current temperature is: 60

  3. 水已烧好,温度正好!可以用来洗澡了。

  4. current temperature is: 100

  5. 水已烧开!可以用来饮用了。

从剧情中思考监听模式

这个代码非常简单,水烧到50-70度时,会发出警告:可以用来洗澡了!烧到100度也会发出警告:可以用来喝了!在这里洗澡模式和饮用模式扮演了监听的角色,而热水器则是被监听的对象。一旦热水器中的水温度发生变化,监听者都能及时知道并做出相应的判断和动作。其实这就是程序设计中监听模式的生动展现。

监听模式

监听模式又名观察者模式,顾名思意就是观察与被观察的关系,比如你在烧开水得时时看着它开没开,你就是观察者,水就是被观察者;再比如说你在带小孩,你关注她是不是饿了,是不是喝了,是不是撒尿了,你就是观察者,小孩就是被观察者。

观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。当你看这些模式的时候,不要觉得陌生,它们就是观察者模式。

观察者模式一般是一种一对多的关系,可以有任意个(一个或多个)观察者对象同时监听某一个对象。监听的对象叫观察者(后面提到监听者,其实就指观察者,两者是等价的),被监听的对象叫被观察者(Observable,也叫主题 Subject)。被观察者对象在状态或内容发生变化时,会通知所有观察者对象,使它们能够做出相应的变化(如自动更新自己的信息)。

监听模式的模型抽象

代码框架

上面的示例代码还是相对比较粗糙,我们可以对它进行进一步的重构和优化,抽象出监听模式的框架模型。

 
  1. class Observer:

  2. "观察者的基类"

  3.  
  4. def update(self, observer, object):

  5. pass

  6.  
  7.  
  8. class Observable:

  9. "被观察者的基类"

  10.  
  11. def __init__(self):

  12. self.__observers = []

  13.  
  14. def addObserver(self, observer):

  15. self.__observers.append(observer)

  16.  
  17. def removeObserver(self, observer):

  18. self.__observers.remove(observer)

  19.  
  20. def notifyObservers(self, object = 0):

  21. for o in self.__observers:

  22. o.update(self, object)

类图

上面的代码框架可用类图表示如下:

enter image description here

addObserver,removeObserver 分别用于添加和删除观察者,notifyObservers 用于内容或状态变化时通知所有的观察者。因为 Observable 的 notifyObservers 会调用 Observer 的 update 方法,所有观察者不需要关心被观察的对象什么时候会发生变化,只要有变化就是自动调用 update,只需要关注 update 实现就可以了。

基于框架的实现

有了上面的代码框架之后,我们要实现示例代码的功能就会更简单了。最开始的示例代码我们假设它为 version 1.0,那么再看看基于框架的 version 2.0 吧。

 
  1. class WaterHeater(Observable):

  2. "热水器:战胜寒冬的有利武器"

  3.  
  4. def __init__(self):

  5. super().__init__()

  6. self.__temperature = 25

  7.  
  8. def getTemperature(self):

  9. return self.__temperature

  10.  
  11. def setTemperature(self, temperature):

  12. self.__temperature = temperature

  13. print("current temperature is:", self.__temperature)

  14. self.notifyObservers()

  15.  
  16.  
  17. class WashingMode(Observer):

  18. "该模式用于洗澡用"

  19.  
  20. def update(self, observable, object):

  21. if isinstance(observable,

  22. WaterHeater) and observable.getTemperature() >= 50 and observable.getTemperature() < 70:

  23. print("水已烧好,温度正好!可以用来洗澡了。")

  24.  
  25.  
  26. class DrinkingMode(Observer):

  27. "该模式用于饮用"

  28.  
  29. def update(self, observable, object):

  30. if isinstance(observable, WaterHeater) and observable.getTemperature() >= 100:

  31. print("水已烧开!可以用来饮用了。")

测试代码不用变。自己跑一下,会发现输出结果和之前的是一样的。

模型说明

设计要点

在设计观察者模式的程序时要注意以下几点:

  1. 要明确谁是观察者谁是被观察者,只要明白谁是关注对象,问题也就明白了。一般观察者与被观察者之间是多对一的关系,一个被观察对象可以有多个监听对象(观察者)。如一个编辑框,有鼠标点击的监听者,也有键盘的监听者,还有内容改变的监听者。
  2. Observable 在发送广播通知的时候,无须指定具体的 Observer,Observer 可以自己决定是否要订阅 Subject 的通知。
  3. 被观察者至少需要有三个方法:添加监听者、移除监听者、通知 Observer 的方法;观察者至少要有一个方法:更新方法,更新当前的内容,作出相应的处理。
  4. 添加监听者、移除监听者在不同的模型称谓中可能会有不同命名,如观察者模型中一般,addObserver,removeObserver;在源-监听器(Source/Listener)模型中一般是 attach/detach,应用在桌面编程的窗口中,还可能是 attachWindow/detachWindow,或 Register/UnRegister。不要被名称迷糊了,不管他们是什么名称,其实功能都是一样的,就是添加/删除观察者。

推模型和拉模型

观察者模式根据其侧重的功能还可以分为推模型和拉模型。

推模型:被观察者对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。一般这种模型的实现中,会把被观察者对象中的全部或部分信息通过 update 的参数传递给观察者 [update(Object obj) ,通过 obj 参数传递]。

如某应用 App 的服务要在凌晨1:00开始进行维护,1:00-2:00期间所有服务将会暂停,这里你就需要向所有的 App 客户端推送完整的通知消息:“本服务将在凌晨1:00开始进行维护,1:00-2:00期间所有服务将会暂停,感谢您的理解和支持!” 不管用户想不想知道,也不管用户会不会在这段期间去访问,消息都需要被准确无误地通知到。这就是典型的推模型的应用。

拉模型:被观察者在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到被观察者对象中获取,相当于是观察者从被观察者对象中拉数据。一般这种模型的实现中,会把被观察者对象自身通过 update 方法传递给观察者 [update(Observable observable ),通过 observable 参数传递 ],这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。

如某应用 App 有新的版本推出,则需要发送一个版本升级的通知消息,而这个通知消息只会简单地列出版本号和下载地址,如果你需要升级你的 App 还需要调用下载接口去下载安装包完成升级。这其实也可以理解成是拉模型。

推模型和拉模型其实更多的是语义和逻辑上的区别。我们上面的代码框架,从接口 [update(self, observer, object)] 上你应该知道是可以同时支持推模型和拉模型的。推模型时,observer 可以传空,推送的信息全部通常 object 传递;拉模型时,observer 和 object 都传递数据,或只传递 observer,需要更具体的信息时通过 observer 引用去取数据。

应用场景

  1. 对一个对象状态或数据的更新需要其他对象同步更新,或者一个对象的更新需要依赖另一个对象的更新;
  2. 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节,如消息推送。

学习设计模式,更应该领悟其设计思想,不应该应该局限于代码的层面。 观察者模式还可以用于网络中的客户端和服务器,比如手机中的各种 App 的消息推送,服务端是被观察者,各个手机 App 是观察者,一旦服务器上的数据(如 App 升级信息)有更新,就会被推送到手机客户端。在这个应用中你会发现服务器代码和 App 客户端代码其实是两套完全不一样的的代码,它们是通过网络接口进行通迅的,所以如果你只是停留在代码层面是无法理解的!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/437020.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【经验】Qt项目开发必备工具

在实际的项目中&#xff0c;除了需要掌握Qt开发框架本身&#xff0c;还需要掌握一些开发工具。这些工具能起到事半功倍的效果&#xff0c;甚至某些工具是开发不可或缺的。下面笔者就介绍一些常用的开发工具的用法及下载地址&#xff0c;希望对缺少实际项目经验的同学提供一些参…

【转】TCP/IP协议--TCP的超时和重传

TCP是可靠传输。可靠之一体现在收到数据后&#xff0c;返回去一个确认。但是不能完全避免的是&#xff0c;数据和确认都可能丢失。解决这个办法就是&#xff0c;提供一个发送的重传定时器&#xff1a;如果定时器溢出时还没收到确认&#xff0c;它就重传这个报文段。 想法是完美…

mysql集群方案对比_MySQL云原生方案在携程开发测试场景中的实践

一、背景与使用场景随着Kubernetes平台在容器云计算领域的一统天下&#xff0c;云原生 (Cloud Native) 一词也被提的越来越频繁。各类应用纷纷走上了容器化、云原生化的道路&#xff0c;无状态服务应用在Kubernetes平台上的运行&#xff0c;已经得到了大规模生产级别的实践认可…

vb.net datagridview数据批量导入sql_【自学C#】|| 笔记 44 ComboBox:组合框控件数据绑定...

一、ComboBox&#xff1a;组合框控件数据绑定在 Windows 应用程序中很多控件都提供了 DataSource 属性&#xff0c;并将 DataSet 或 DataTable 的值直接赋给该属性&#xff0c;这样在控件中即可显示从数据库中查询出来的数据。 常用的数据绑定控件有文本框(TextBox)、标签(L…

【转】C#Socket编程详解(一)TCP与UDP简介

一、TCP与UDP 1、TCP 1.1 定义 TCP&#xff08;TransmissionControl Protocol&#xff09;传输控制协议。 是一种可靠的、面向连接的协议&#xff08;eg:打电话&#xff09;、传输效率低全双工通信&#xff08;发送缓存&接收缓存&#xff09;、面向字节流。使用TCP的应…

【精华】掌握Qt调试技术

前言 软件调试&#xff0c;是开发过程中必备的技能。通过调试可以发现软件存在的bug&#xff0c;即缺陷。调试可以帮助开发者窥探到软件运行过程中的详细状态&#xff0c;从而为消除bug提供重要信息。调试的英文是debug&#xff0c;前面的de在英文中表示“反对”&#xff0c;“…

ps海报合成教程_如何利用PS制作海报?详细教程来了!

今天能学长给大家带来一套利用PS做【月满中秋】海报的教程。福利干货到&#xff0c;请大家接住&#xff01;话不多说&#xff0c;直接上教程【月满中秋-第一课】月满中秋-海报制作教程https://www.zhihu.com/video/1187797197951918080为了方便大家阅读&#xff0c;本篇文章特地…

【转】WebSocket详解(一):初步认识WebSocket技术

1、前言 HTML5规范在传统的web交互基础上为我们带来了众多的新特性&#xff0c;随着web技术被广泛用于web APP的开发&#xff0c;这些新特性得以推广和使用&#xff0c;而websocket作为一种新的web通信技术具有巨大意义。 本文将带您认识WebSocket。也可查看本文的下篇&#x…

【Qt调试技巧】Profile配置使用及一些坑

介绍 不知从哪个版本起&#xff0c;Qt Creator中的构建配置中&#xff0c;增加了一种新型配置&#xff0c;名叫“Profile”&#xff0c;如下图所示&#xff1a; 官方对Profile的描述是&#xff1a;Profile是介于Debug和Release中间的一种配置。具体是什么意思呢&#xff1f;…

【转】带你玩转Visual Studio——03.带你了解VC++各种类型的工程

上一篇文章带你玩转Visual Studio——带你新建一个工程一文中提到新建一个工程时会有很多的工程类型(图1)&#xff0c;现在将简单介绍各种类型工程的含义和主要用途。由于这里包含的工程类型太多&#xff0c;有很多本人也没有接触过&#xff0c;有些可能理解的不太对的地方还请…

如何调整金格电子章服务器印章_重磅!公安部再度认可电子签名、电子印章法律效力!...

近日&#xff0c;公安部发布《关于修改〈公安机关办理刑事案件程序规定〉的决定》&#xff0c;对《公安机关办理刑事案件程序规定》&#xff08;以下简称规定&#xff09;进行了全面修改完善&#xff0c;并将于9月1日起施行。修改后的规定共14章388条。其中&#xff0c;新增的第…

【转】带你玩转Visual Studio——04.带你高效开发

上一篇文章带你玩转Visual Studio——带你了解VC各种类型的工程一文中讲了各种类型VC工程的主要功能和用途。现在将带你一起快速开发c程序。 有过Java开发经验的人都知道Java的常用开发工具(如Eclipse、Intellij IDEA等)都有非常强大的关键字高亮、智能提示、快速追踪等的功能…

【信号与线性系统】知识点与学习攻略

知识点理解 关于正交分解可以看这个视频&#xff1a; https://www.bilibili.com/video/BV1qV411C7u6/ 记住两个完备正交函数集&#xff1a; 一个是正余弦三角函数&#xff0c;非零不同频率项乘积为0&#xff0c;非零同频率项乘积积分为T/2&#xff0c;零频率项乘积积分为T。 一…

2020-12-19

逆变&#xff08;contravariant&#xff09;与协变&#xff08;covariant&#xff09;是C#4新增的概念&#xff0c;许多书籍和博客都有讲解&#xff0c;我觉得都没有把它们讲清楚&#xff0c;搞明白了它们&#xff0c;可以更准确地去定义泛型委托和接口&#xff0c;这里我尝试画…

微软模拟飞行10厦门航空涂装_《微软飞行模拟器》多人游戏模式演示:可组队飞行...

IT之家3月29日消息 《微软飞行模拟器》(Flight Simulator)是2020年最受期待的游戏之一&#xff0c;开发商Asobo Studio现在分享了一段新的视频&#xff0c;详细介绍了《微软飞行模拟器》的多人游戏模式。《微软飞行模拟器》游戏的主模式将看到所有玩家在同一个世界中一起玩。微…

【转】UDP协议格式以及在java中的使用

UDP协议格式以及在java中的使用 UDP是面向无连接的通讯协议&#xff0c;由于通讯不需要连接&#xff0c;所以可以实现广播发送。UDP通讯时不需要接收方确认&#xff0c;属于不可靠的传输&#xff0c;可能会出现丢包现象&#xff0c;实际应用中要求程序员编程验证。 UDP适用于…

python网页填表教程_PythonSpot 中文系列教程 · 翻译完成

原文&#xff1a;PythonSpot Python Tutorials 协议&#xff1a;CC BY-NC-SA 4.0 欢迎任何人参与和完善&#xff1a;一个人可以走的很快&#xff0c;但是一群人却可以走的更远。在线阅读ApacheCN 学习资源目录PythonSpot 中文系列教程初学者 介绍Python 字符串字符串&#xff0…

【转】TCP/IP协议到底在讲什么?【乐搏TestPro】

用比喻和漫画给有需要的小伙伴解释下IP、TCP捎带题一下各种协议与HTTP协议的关系&#xff1b; 目录&#xff1a; 负责传输的IP协议 确保可靠性的TCP协议 各种协议与HTTP协议的关系 一、负责传输的IP协议 按照层次分&#xff0c;IP&#xff08;全称&#xff1a;Internet Prot…

Qt中标绘功能的实现方法对比

使用Qt开发桌面程序&#xff0c;经常会有标绘的需求&#xff0c;一般有以下几点&#xff1a; 新建&#xff1a;圆、矩形、椭圆、文字标注&#xff0c;插入图像等&#xff1b;编辑&#xff1a;指对已标绘内容的属性编辑修改功能&#xff1b;删除&#xff1a;指对已标绘内容的删…

【转】PE文件结构详解--(完整版)

&#xff08;一&#xff09;基本概念 PE&#xff08;Portable Execute&#xff09;文件是Windows下可执行文件的总称&#xff0c;常见的有DLL&#xff0c;EXE&#xff0c;OCX&#xff0c;SYS等&#xff0c;事实上&#xff0c;一个文件是否是PE文件与其扩展名无关&#xff0c;P…