作业三-Water项目中的观察者模式

Water项目中观察者模式解析

1 项目简介

  用python实现的一个项目,提醒大家节约用水,不要随意浪费:当水龙头连续使用超过十分钟就提示使用者是否忘记关水了。

2 观察者模式简介

  建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。在此,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展,这就是观察者模式的模式动机。

3 观察者模式在该项目中的原理分析

 3.1这个项目由以下两部分组成:

    3.1.1监听器:监听水龙头打开时间。

    3.1.2发送提醒:一旦监听的事件发生(比如连续打开水龙头超过五分钟),那么监听器就会触发“发送提醒器”,提醒器会以某种方式发送通知给使用者。

  这个项目的对象关系是一个很经典的“观察者模式”的模型,UML图如下:

    

  3.2.1监听器抽象接口Listener,它实现了所有监听器共有的功能,即绑定观察者,解绑观察者,(在所监听的事件发生的时候)通知所有绑定的观察者,以及监听事件。

 1 class Listener:
 2 
 3     def __init__(self):
 4 
 5         self._observers = []
 6 
 7  
 8 
 9     def attach(self, observer):
10 
11         if not observer in self._observers:
12 
13             self._observers.append(observer)
14 
15  
16 
17     def detach(self, observer):
18 
19         try:
20 
21             self._observers.remove(observer)
22 
23         except ValueError, e:
24 
25             pass
26 
27  
28 
29     def notify(self):
30 
31         for observer in self._observers:
32 
33             observer.update()
34 
35  
36 
37     def listening(self):
38 
39         pass

 

    3.2.2 需要监听水龙头打开时间,所以继承实现了一个具体的监听器,OpenTimeListener,只需要实现listening函数即可。

 1 class WaterTimeListener(Listener):
 2 
 3     #使用观察者模式来实现对水龙头的监听
 4 
 5     format = "llHHI"
 6 
 7     size = struct.calcsize(format)
 8 
 9     keyboardDevice = "/dev/input/event3"
10 
11     fd = os.open(WaterDevice, os.O_RDWR)
12 
13  
14 
15     def __init__(self, maxTime=300, leastUseTime=120, notifyInterval=60):
16 
17         Listener.__init__(self)
18 
19 
20         self.maxTime = maxTime
21 
22         self.lleastUseTime = leastUseTime
23 
24         self.notifyInterval = notifyInterval
25 
26         self.OpenTime = time.time()
27 
28         self.Time = time.time() - notifyInterval
29 
30         self.start_water_time = time.time()
31 
32  
33 
34     def listening(self):
35 
36         while True:
37 
38             op = os.read(self.fd, self.size)
39 
40             # timestamp, subsecond, type, code, value = struct.unpack(format, op)
41 
42             now, _, _, _, _ = struct.unpack(self.format, op)
43 
44 
45                 # 如果超过十分钟没有关,就开始通知
46 
47                 if now - self.lastNotifyTime >= self.notifyInterval:
48 
49                     self.notify()
50 
51                     self.lastNotifyTime = now
52 
53             self.lastInputTime = now

 

 

  3.2.3观察者抽象类Observer,这个其实只是个接口而已,不是一个类,因为update()虽然是共有的接口函数,但它的实体是因人而异的,没法在这个类里给出一个default的实现(对比一下Listener的notify方法就知道了)

1 class Observer:
2 
3     def update(self):
4 
5         raise NotImplementedError("Must subclass me")

   3.2.4该项目,目前的发通知给使用者,只实现了一种方式:发送邮件给用户。

 1 # 第三方 SMTP 服务
 2 
 3 mail_host = "XXXX"  # 设置服务器
 4 
 5 mail_user = "XXXX"  # 用户名
 6 
 7 mail_pass = "XXXXX"  # 口令
 8 
 9 
10 class Mail:
11     def __init__(self):
12 
13         sender = 'XXXX'
14 
15     receivers = ['XXXX']  # 接收邮件
16     message = MIMEText(body.encode('utf-8'), 'plain', 'utf-8'17 
18     message['From'] = Header("提醒", 'utf-8')
19 
20     subject = '水龙头忘记关了吧!!!'
21 
22     message['Subject'] = Header(subject, 'utf-8')
23 
24     try:
25 
26         smtpObj = smtplib.SMTP()
27 
28         smtpObj.connect(mail_host, 25)  # 25 为 SMTP 端口号
29 
30         smtpObj.login(mail_user, mail_pass)
31 
32         smtpObj.sendmail(sender, receivers, message.as_string())
33 
34         print("邮件发送成功")
35 
36     except smtplib.SMTPException:
37 
38         print("Error: 无法发送邮件")

 

  值得注意的是:一个监听器可以有多个观察者,而一般一个观察者只能有一个监听器。比如监听是否浪费水这个事件,可以有多种通知方式,比如响闹铃,发送通知到手机,记录使用情况到日志文件以备后续分析,等等。而一般一个观察者都是特化了的,不会用在多个监听器上面。

4 观察者模式给该项目带来了哪些好处

  对于这个项目而言:观察者模式把监测事件和响应事件这两个职责给分离了,各司其职。监听器监测使用者有没有长时间打开水龙头,有的话,就通过接口告诉观察者,观察者再发通知给使用者,让使用者判断是否是忘记了关水。

  即观察者模式实现了表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。观察者模式在观察目标和观察者之间建立一个抽象的耦合。且观察者模式符合“开闭原则”的要求。

posted @ 2018-10-23 14:14  cyzhou96  阅读(208)  评论(0编辑  收藏  举报