课程名称:程序设计方法学

实验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设计模式)-行为型模式之观察者模式的应用与实现的更多相关文章

  1. 设计模式----行为型模式之观察者模式(Observer Pattern)

    下面是阅读<Head First设计模式>的笔记. 观察者模式 定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新. JDK API内置机制 ...

  2. 设计模式-行为型模式,python访问者模式

    访问者模式 在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法.通过这种方式,元素的执行算法可以随着访问者改变而改变.这种类型的设计模式属于行为型模式. ...

  3. Java设计模式——行为型模式

    行为型模式,共11种:策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.访问者模式.中介者模式.解释器模式. 11种模式的关系: 第一类:通过父类与子类的关系 ...

  4. java设计模式--创建型模式(一)

    2016-04-24 10:10:34 创建型模式:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式 注意:工厂模式可以分为三类: 1)简单工厂模式(Simple Factory) 2)工厂 ...

  5. C# 设计模式·行为型模式

    这里列举行为型模式·到此23种就列完了···这里是看着菜鸟教程来实现··,他里边列了25种,其中过滤器模式和空对象模式应该不属于所谓的23种模式责任链模式:为请求创建一个接收者对象的链,对请求的发送者 ...

  6. C# 设计模式·创建型模式

    面试问到这个··答不出来就是没有架构能力···这里学习一下···面试的时候直接让我说出26种设计模式··当时就懵逼了··我记得好像之前看的时候是23种的 还有3个是啥的··· 这里先列出几种创建型模式 ...

  7. C#设计模式-创建型模式(转)

    一.简单工厂模式 简单工厂模式Simple Factory,又称静态工厂方法模式.它是类的创建模式.是由一个工厂对象决定创建出哪一种产品类的实例,是不同的工厂方法模式的一个特殊实现. 优点: u 模式 ...

  8. java设计模式--行为型模式--状态模式

    什么是行为型模式,小编觉得就是对行为的一种描述啦,一种对某种行为模型的定义. 状态模式: 状态模式 概述 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被 ...

  9. 设计模式-行为型模式,python 中介者模式

    中介者模式 中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性.这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护.中介者模式属于行 ...

随机推荐

  1. 高效的数据压缩编码方式 Protobuf

    一. protocol buffers 是什么? Protocol buffers 是一种语言中立,平台无关,可扩展的序列化数据的格式,可用于通信协议,数据存储等. Protocol buffers ...

  2. 我也用github(2)——关联本地工程到github仓库

    github只是为我们提供了一个存储的功能,我们也可以准备一个服务器(当然,能联网是前提了),将版本库保存到服务器上. 本文以github为例进行实验. 1. 在github上创建一个仓库 这个非常简 ...

  3. 混沌数学之Chua's circuit(蔡氏电路)

    蔡氏电路(英语:Chua's circuit),一种简单的非线性电子电路设计,它可以表现出标准的混沌理论行为.在1983年,由蔡少棠教授发表,当时他正在日本早稻田大学担任访问学者[1].这个电路的制作 ...

  4. 混沌数学之Baker模型

    相关DEMO参见:混沌数学之离散点集图形DEMO 相关代码: // http://wenku.baidu.com/view/ac9b57ea172ded630b1cb65b.html class Ba ...

  5. RabbitMQ Zabbix 监控

    RabbitMQ Zabbix 监控 参考: https://github.com/jasonmcintosh/rabbitmq-zabbix copy api.py list_rabbit_node ...

  6. mahout源码分析之DistributedLanczosSolver(六)完结篇

    Mahout版本:0.7,hadoop版本:1.0.4,jdk:1.7.0_25 64bit. 接上篇,分析完3个Job后得到继续往下:其实就剩下两个函数了: List<Map.Entry< ...

  7. 什么是Copy-Only Backup? 为什么要用它?

    Copy-only backup是一种独立于传统SQL Backup方法的一种备份方式. 一般来说, 做一次数据库备份会影响到后面的备份和还原作业. 然而, 有时你需要为了某个特殊的目的而做一次备份但 ...

  8. 使用sed进行文字替换

    范式: sed -i "s/查找内容/替换后内容/g" `grep 查找内容 -rl 查找开始路径` 例子: #sed -i "s/abc/ABC/g" `gr ...

  9. JS 提交form表单

    源码实例一:javascript 页面加裁时自动提交表单Form表单:<form method="post" id="myform" action=&qu ...

  10. angular5使用httpclient时解决跨域问题

    跨域问题的环境: 在本地开发时,使用命令行ng s开启服务,访问地址为http://localhost:4200 假设调用数据接口的服务地址为http://localhost:8088/api/dat ...