面向对象程序设计(OOP设计模式)-行为型模式之观察者模式的应用与实现
课程名称:程序设计方法学
实验5:OOP设计模式-行为型模式的应用与实现
时间:2015年12月02日三,第3、4节地点:理
一、实验目的
加深对行为型设计模式的理解以及在开发中的实际应用能力。
二、实验内容
实验内容:
在工业自动化系统中,作为监控端,要求能够实时采集生产线上每一个测点的数据,并根据事先设定好的条件来发出告警。目前,系统可以支持的告警方式在形式上呈现多样化的趋势,主要包括屏幕显示告警、语音发声告警、电话拨号告警、电子邮件告警、手机短信告警以及其他可利用的告警方式等。在设置监控端时,用户可以根据实际需要,针对生产线上的每个测点,动态地设定与其相关联的多个告警。每个告警都有对应的告警方式和告警对象。当从某个测点返回的采集数据超过了事先设定好的阈值时,就要立即触发与该测点相关的所有告警,以便相关人员能够及时得到有关异常情况的通知,便于其进行人工干预和处理。
针对以上说明,现在要求你设计监控端软件中的告警功能部分。要求使该系统能够实现针对测点和告警间的一对多的动态组合,并具有较强的可扩展性。
要求:
实验报告中要求绘制UML类图,给出设计中各个类的主要成员,并附以适当的文字说明详细描述每个类的作用;
实验报告中应针对上述设计,给出使用C++(或java)实现的完整的示意性代码,以及在本地计算机上调试、运行该程序的截图(要求截图的结果中能体现个人的学号、姓名等信息)。
实验报告的末尾请对所用的设计模式、该模式的优缺点及使用心得等做简要小结。
附加要求:
对于我们所介绍的常见的几种行为型的设计模式,你能不能也举出这些模式的一些应用实例,并给出相关的UML类图说明呢?
三、实验环境
硬件条件:微机
操作系统:Windows 2007
开发环境:Eclipse,Rational Rose 2003
四、实验步骤和结果
(一)选择适当的面向对象设计模式
由题意,要求设计一个设计监控端软件中的告警功能,作为监控端,要求能够实时采集生产线上每一个测点的数据,并根据事先设定好的条件来发出告警。告警方式有多样,当从某个测点返回的采集数据超过了事先设定好的阈值时,就要立即触发与该测点相关的所有告警。这需要实现测点和告警间的一对多的动态组合。故选用的是行为型设计模式中的观察者模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己,并做出相应动作。
(二)UML类图的设计和绘制
设计分析:
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,所有依赖于它的对象都得到通知并被自动更新。观察者模式中的角色有:
1、 抽象主题(Subject)角色:抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。
2、 具体主题(ConcreteSubject)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。
3、 抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。
4、 具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。
|
|
(图1 一般的观察者模式的UML类图 )
|
|
(图2该监控端软件中的告警功能的观察者模式的UML类图)
(三)针对上述设计,用java实现的完整的示意性代码如下所示:
Java 类的建立如下所示:
|
|
1、Sub_MeasuringPoint抽象类,即测点抽象类,该目标抽象类提供注册和删除观察者对象的接口:
package com.shen.observer; import java.util.ArrayList; //目标类:
//目标知道它的观察者,可以有任意多个观察者观察同一目标
//提供注册和删除观察者对象的接口 public abstract class Sub_MeasuringPoint { //用来保存注册的观察者对象
private ArrayList <Observer> list=new ArrayList<Observer>(); //注册观察者对象
public void Attach(Observer observer) { list.add(observer);
System.out.println("Attached an observer successfully!");
} //删除观察者对象
public void Detach(Observer observer) { list.remove(observer);
System.out.println("Detached an observer successfully!");
} //通知所有注册的观察者对象
public void NotifyObservers(String newState) { for (Observer observer:list) { observer.Update(newState);
observer.AlarmMode();
}
}
}
2、ConSub_MeasuringPoint具体目标类,当从某个测点返回的采集数据超过了事先设定好的阈值时,就要立即触发与该测点相关的所有告警
package com.shen.observer; //具体目标类
public class ConSub_MeasuringPoint extends Sub_MeasuringPoint { private String state;
public String getState() {
return state;
} //当从某个测点返回的采集数据超过了事先设定好的阈值时,就要立即触发与该测点相关的所有告警,
//数据超过阈值 public void DataOverThreshold(String newState) { state=newState;
System.out.println(">>>>>当前检测到测点状态为:"+state); ////状态发生改变,通知各个观察者
this.NotifyObservers(state); }
}
3、Observer 观察者接口,为那些在目标发生时需获得通知的对象定义一个更新接口:
package com.shen.observer;
//这是一个观察者接口,为那些在目标发生时需获得通知的对象定义一个更新接口
public interface Observer {
public void Update(String state);//检查到的状态更新
public Object alarmObject=new Object();//告警对象
public void AlarmMode();//告警方式
}
4、Ob_ScreenDisplayAlarm 屏幕显示告警:
package com.shen.observer;
//屏幕显示告警
public class Ob_ScreenDisplayAlarm implements Observer{
//观察者的状态
@SuppressWarnings("unused")
private String observerState;
@Override
public void Update(String state) {
// TODO Auto-generated method stub
observerState=state;
System.out.print("[屏幕显示告警器]发现测点数据超过阈值");
}
@Override
public void AlarmMode() {
// TODO Auto-generated method stub
System.out.println(",于是触发【屏幕显示告警】!");
}
}
5、Ob_VoiceAudibleAlarm语音发声告警:
package com.shen.observer; //语音发声告警
public class Ob_VoiceAudibleAlarm implements Observer{ //观察者的状态
@SuppressWarnings("unused")
private String observerState; @Override
public void Update(String state) { // TODO Auto-generated method stub
observerState=state;
System.out.print("[语音发声告警器]发现测点数据超过阈值");
} @Override public void AlarmMode() { // TODO Auto-generated method stub
System.out.println(",于是触发【语音发声告警】!");
}
}
6、Ob_TelephoneDialingAlarm电话拨号告警:
package com.shen.observer; //电话拨号告警
public class Ob_TelephoneDialingAlarm implements Observer{ //观察者的状态
@SuppressWarnings("unused")
private String observerState; @Override
public void Update(String state) {
// TODO Auto-generated method stub
observerState=state;
System.out.print("[电话拨号告警器]发现测点数据超过阈值");
} @Override
public void AlarmMode() {
// TODO Auto-generated method stub
System.out.println(",于是触发【电话拨号告警】!");
}
}
7、Ob_EmailAlarm 电子邮件告警
package com.shen.observer; //电子邮件告警
public class Ob_EmailAlarm implements Observer { //观察者的状态
@SuppressWarnings("unused")
private String observerState; @Override
public void Update(String state) {
// TODO Auto-generated method stub
observerState=state;
System.out.print("[电子邮件告警器]发现测点数据超过阈值");
} @Override
public void AlarmMode() {
// TODO Auto-generated method stub
System.out.println(",于是触发【电子邮件告警】!");
}
}
8、Ob_SMSAlarm 手机短信告警
package com.shen.observer;
//手机短信告警
public class Ob_SMSAlarm implements Observer{
//观察者的状态
@SuppressWarnings("unused")
private String observerState;
@Override
public void Update(String state) {
// TODO Auto-generated method stub
observerState=state;
System.out.print("[手机短信告警器]发现测点数据超过阈值");
}
@Override
public void AlarmMode() {
// TODO Auto-generated method stub
System.out.println(",于是触发【手机短信告警】!");
}
}
9、Ob_OtherAvailableAlarm其他可利用的告警方式
package com.shen.observer; //其他可利用的告警方式
public class Ob_OtherAvailableAlarm implements Observer{ //观察者的状态
@SuppressWarnings("unused")
private String observerState;
@Override
public void Update(String state) {
// TODO Auto-generated method stub
observerState=state;
System.out.print("[其他可利用的告警方式]发现测点数据超过阈值");
} @Override
public void AlarmMode() {
// TODO Auto-generated method stub
System.out.println(",于是触发其他可利用的告警方式......");
}
}
(四)编写监控器测试代码(MonitorClientTest.java)如下所示:
package com.shen.observer;
//客户端测试类
public class MonitorClientTest {
public static void main(String[] args) {
// 创建主题对象,即测点
System.out.println("--------<监控端软件中的告警功能_(shen)>-------");
ConSub_MeasuringPoint measuringPoint=new ConSub_MeasuringPoint();
//创建屏幕显示告警观察者对象
Observer observer1=new Ob_ScreenDisplayAlarm();
//创建语音发声告警观察者对象
Observer observer2=new Ob_VoiceAudibleAlarm();
//创建电话拨号告警观察者对象
Observer observer3=new Ob_TelephoneDialingAlarm();
//创建电子邮件告警观察者对象
Observer observer4=new Ob_EmailAlarm();
//创建手机短信告警观察者对象
Observer observer5=new Ob_SMSAlarm();
//创建其他可利用的告警方式观察者对象
Observer observer6=new Ob_OtherAvailableAlarm();
//将观察者对象注册到主题对象上
measuringPoint.Attach(observer1);
measuringPoint.Attach(observer2);
measuringPoint.Attach(observer3);
measuringPoint.Attach(observer4);
measuringPoint.Attach(observer5);
measuringPoint.Attach(observer6);
//改变主题对象的状态
measuringPoint.DataOverThreshold("测点返回的采集数据超过阈值!!!");
}
}
调试程序,运行结果如图所示:
|
|
五、实验结果和讨论
在编写完相应代码及测试程序后,调试程序,运行结果如图所示:
|
|
六、总结
(一)本次实验按时按量完成。通过实验基本掌握了行为型设计模式中的观察者模式。
(二)本次实验使用的是观察者模式。观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 在观察者模式中,一个目标物件(被观察者)管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知,这通常通过呼叫各观察者所提供的方法来实现。
优点:
1. 目标和观察者对象之间的抽象耦合。一个目标所知道的仅仅是它有一系列观察者,每个都符合抽象的Observer类的简单接口。目标不知道任何一个观察者属于哪一个具体的类,它只知道它们都有一个共同的接口。这样目标和观察者之间的耦合是抽象的和最小的。
2. 支持广播通信。不像通常的请求,目标发送的通知不需指定它的接收者。通知被自动广播给所有已向该对象登记的有关对象。
缺点:
1. 意外的更新。因为一个观察者并不知道其它观察者的存在,它可能对改变目标的最终代价一无所知。虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。
2. 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
3. 果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点。
4.如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
(三)使用观察者模式的心得体会:
从GOF给出的Observer模式的意图:“定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”。中,我们可以得到两个信息,如下:
1.观察者(具体执行操作的对象,有多个)
2.被观察者(顾名思义是被观察的对象,如果该对象发生某些变化则通知观察者执行对应的操作。)
目标Suject提供依赖于它的观察者Observer的注册(Attach)和注销(Detach)操作,并且提供了使得依赖于它的所有观察者同步的操作(Notify)。
观察者则提供一个Update操作,需要注意的是这里的Observer的Update操作并不在Observer改变了Subject目标状态的时候就对自己进行更新,这个更新操作要延迟到Subject对象发出Notify通知所有Observer进行修改(调用Update)。
通过学习,我了解到Observer是影响极为深远的模式之一,也是在大型系统开发过程中要用到的模式之一。
七、附加要求
对于我们所介绍的常见的几种结构型的设计模式,举出这些模式的一些应用实例,并给出相关的UML类图说明。
此处以“学生逐级请假制度”举例如下:
大学学生有事情离开学校需要请假,请假1天,辅导员可以批准;请假2天,学院副书记可以批准;请假超过2天,则需要找学院院长批假!
此处则采用职责链模式来实现上述制度。
职责链模式是一种对象的行为模式。在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象 决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。
职责链模式的组成:
1、抽象处理者(Handler)角色:定义出一个处理请求的接口。如果需要,接口可以定义出一个方法,以设定和返回对后继者的引用。这个角色通常由一个抽象类或接口实现。
2、具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问后继者。
3、客户端测试(ClientTest)角色:向职责链上的具体处理者(ConcreteHandler)对象提交请求。
UML类图设计如下所示:
|
|
(一) 代码设计如下所示:
1、处理请假请求的接口
package com.shen.cor;
//处理请假请求的接口
public abstract class LeaveBaseHandler {
//后继者
protected LeaveBaseHandler successor;
//get 和set 方法
public LeaveBaseHandler getSuccessor() {
return successor;
}
public void setSuccessor(LeaveBaseHandler successor) {
this.successor = successor;
}
//处理请假请求的方法
public abstract void requestLeave(int days);
}
2、对请假一天的处理
package com.shen.cor;
//对请假一天的处理
public class OnedayLeaveConcreteHandler extends LeaveBaseHandler {
@Override
public void requestLeave(int days) {
if (days<=1) {
System.out.println(">>>辅导员可以批准请假1天");
}
else {
super.successor.requestLeave(days);
}
}
}
3、对请假两天的处理
package com.shen.cor;
//对请假两天的处理
public class TwodaysLeaveConcreteHandler extends LeaveBaseHandler {
@Override
public void requestLeave(int days) {
if (days>1&&days<=2) {
System.out.println(">>>学院副书记可以批准请假2天");
}
else {
super.successor.requestLeave(days);
}
}
}
4、客户端测试类:
package com.shen.cor;
//客户端测试类
public class ClientTest {
private static void requestLeave() {
LeaveBaseHandler oneDay=new OnedayLeaveConcreteHandler();
LeaveBaseHandler twoDays=new TwodaysLeaveConcreteHandler();
LeaveBaseHandler moreThanTwoDays=new MoreThanTwodaysConcreteHandler();
oneDay.setSuccessor(twoDays);
twoDays.setSuccessor(moreThanTwoDays);
oneDay.requestLeave(1);
oneDay.requestLeave(2);
oneDay.requestLeave(3);
}
public static void main(String[] args) {
System.out.println("----------通过职责链模式实现逐级请假制度_105032013120----------");
requestLeave();
}
}
(二) 测试结果如下所示:
|
|
面向对象程序设计(OOP设计模式)-行为型模式之观察者模式的应用与实现的更多相关文章
- 设计模式----行为型模式之观察者模式(Observer Pattern)
下面是阅读<Head First设计模式>的笔记. 观察者模式 定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新. JDK API内置机制 ...
- 设计模式-行为型模式,python访问者模式
访问者模式 在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法.通过这种方式,元素的执行算法可以随着访问者改变而改变.这种类型的设计模式属于行为型模式. ...
- Java设计模式——行为型模式
行为型模式,共11种:策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.访问者模式.中介者模式.解释器模式. 11种模式的关系: 第一类:通过父类与子类的关系 ...
- java设计模式--创建型模式(一)
2016-04-24 10:10:34 创建型模式:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式 注意:工厂模式可以分为三类: 1)简单工厂模式(Simple Factory) 2)工厂 ...
- C# 设计模式·行为型模式
这里列举行为型模式·到此23种就列完了···这里是看着菜鸟教程来实现··,他里边列了25种,其中过滤器模式和空对象模式应该不属于所谓的23种模式责任链模式:为请求创建一个接收者对象的链,对请求的发送者 ...
- C# 设计模式·创建型模式
面试问到这个··答不出来就是没有架构能力···这里学习一下···面试的时候直接让我说出26种设计模式··当时就懵逼了··我记得好像之前看的时候是23种的 还有3个是啥的··· 这里先列出几种创建型模式 ...
- C#设计模式-创建型模式(转)
一.简单工厂模式 简单工厂模式Simple Factory,又称静态工厂方法模式.它是类的创建模式.是由一个工厂对象决定创建出哪一种产品类的实例,是不同的工厂方法模式的一个特殊实现. 优点: u 模式 ...
- java设计模式--行为型模式--状态模式
什么是行为型模式,小编觉得就是对行为的一种描述啦,一种对某种行为模型的定义. 状态模式: 状态模式 概述 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被 ...
- 设计模式-行为型模式,python 中介者模式
中介者模式 中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性.这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护.中介者模式属于行 ...
随机推荐
- ActiveMQ使用示例之Queue
我们使用ActiveMQ为大家实现一种点对点的消息模型. 开发时候,要将apache-activemq-5.12.0-bin.zip解压缩后里面的activemq-all-5.12.0.jar包加入到 ...
- Objective-C:在类中设置不同协议
在下面的代码中,设置了两种不同的协议规则:一种是老师对学生设置的协议:即老师发出命令后,学生站起来.回答问题.坐下; 另一种是我对学生设置的协议:即学生按照我的协议中的初始化函数去初始化一个整数. / ...
- C语言获取系统当前时间
C语言获取系统当前时间 time_t -- 时间类型 struct tm -- 时间结构 time(&now)函数获取当前时间距1970年1月1日的秒数,以秒计数单位. localtime ( ...
- 2018CVPR
CVPR 2018:腾讯图像去模糊.自动人像操纵最新研究 解密运动模糊:走向实用的非特定场景图片去模糊技术 在慢速曝光或快速运动拍摄照片时,图像模糊常常困扰着照片拍摄者.优图实验室的研究人员开发了可以 ...
- VMware vCenter中, 如何辩认虚机上Raw Device Mapping过了的一块物理磁盘?
比如说, 我们有一套VMware的环境, 其中有一台运行者ESXi的主机, 其上有十块SAS盘. 这十块盘中的五块盘被RDM到一台虚机上了. 假设你发现有添加多了一块盘, 你想移除掉, 但是5块盘其中 ...
- Insertion Sort List Leetcode java
题目: Sort a linked list using insertion sort. 题解: Insertion Sort就是把一个一个元素往已排好序的list中插入的过程. 初始时,sorted ...
- Memento 备忘录 快照模式 MD
备忘录模式 简介 在不破坏封装的前提下,捕获一个对象的[内部状态],并在该对象之外保存这个状态,这样以后就可以将该对象恢复到原先保存的状态. 角色: 发起人Originator:要被备份的成员,它提供 ...
- linux中sort命令
功能说明:将文本文件内容加以排序,sort可针对文本文件的内容,以行为单位来排序. 参 数: -b 忽略每行前面开始出的空格字符. -c 检查文件是否已经按照顺序排序. -d 排序时,处理英文字母.数 ...
- Angular6
Structural Directives https://angular.io/guide/structural-directives#template-input-variable There a ...
- Visual Studio 2008破解90天试用期
Visual Studio 2008破解90天试用期变成正式版的方法: 第一种方法(安装前用): 把iso文件中的setup文件夹中的setup.sdb文件中的[Product Key]下的一行的原来 ...






