【形式化方法:VDM++系列】4.VDM实战1——铁路费用计算
又有将近2个月没更新博客了啊!winter holiday简直玩儿疯了的说!结果假期前学习的形式化方法已经忘了大半!面对期末作业,大脑一片空白。于是,赶快复习了一下之前学习的姿势!
这次的主要任务是完成一个费用计算程序。
1.问题
Make a model to calculate train fare from a station to another station by using functions and the following table.
使用函数计算两个车站之前的铁路费用。基础数据如下:
values
vFareSet = {
mk_FareRecord("Tokyo", "Shinagawa", ),
mk_FareRecord("Tokyo", "Shinjuku", ),
mk_FareRecord("Shinjuku", "Shinagawa", )
}
函数开头如下:
static public Calculate_fare : set of FareRecord * Station * Station -> nat
Calculate_fare(aSetOfFare, aDeparture, anArrival) == is not yet specified;
2.解法
首先必须明确问题要求,仔细观察函数的输入输出,Calculate_fare函数有3个输入参数,分别是费用记录集合(set of FareRecord),始发车站,终点车站;输出为一个整数,即2个车站间的费用;函数内容尚未定义,现在需要我们定义函数体完成费用的计算。
计算费用的业务逻辑是:根据始发站和终点站查找费用记录集合,如果在费用纪录集合中找到始发站和终点站都相同的纪录,就返回该记录的费用。用SQL语言可以很简单的解释该逻辑:
select fare_num from fareRecord
where fareRecord.aDeparture=aDeparture and fareRecord.anArrival=anArrival
明确了业务逻辑就可以打开Overture工具开始编码了!
上图展示了Overture工具默认建立的vdm类,它包类定义,类型定义,值定义,初始化变量,操作定义,函数定义,测试用例定义。这里我们需要定义type,value和functions
(1)定义类型
需要定义的类型有:fareRecord类型,Station类型。
定义Station类型与String等价,定义FareRecord类型为结构体类型,包含3个子元素
(2)定义值
(3)定义函数
注意:红线部分所展示的函数体与之前的SQL语句基本相同,let .. in set .. be st .. in .. 是VDM++独特的语法所在,需要仔细体会才能明白。
(4)定义函数的前置条件和后置条件
函数的前置条件是:对于要求的始发站和终点站应该包含于费用记录集合当中,对于费用记录集合中的2条记录,如果始发站和终点站相同,那么费用也应该相同。
函数的后置条件是:存在唯一一条记录,该记录的始发站,终点站与传入的始发站,终点站相同,该记录的结果与执行函数体得到的result相同。
至此,我们的需求定义完成。
代码如下:
class fareCaculate
types
public Station = seq of char
inv s == s<>""; public FareRecord ::
fDeparture : Station
fArrival : Station
fFare : nat
inv fr == fr.fDeparture <> fr.fArrival functions
static public Calculate_fare : set of FareRecord * Station * Station -> nat
Calculate_fare(aSetOfFare, aDeparture, anArrival) ==
let wFareRecord in set aSetOfFare be st
{aDeparture, anArrival} = {wFareRecord.fDeparture, wFareRecord.fArrival}
in wFareRecord.fFare
pre
{aDeparture, anArrival} in set
{{e.fDeparture, e.fArrival} | e in set aSetOfFare} and
forall wFareRecord1, wFareRecord2 in set aSetOfFare &
wFareRecord1.fDeparture = wFareRecord2.fDeparture and
wFareRecord1.fArrival = wFareRecord2.fArrival =>
wFareRecord1.fFare = wFareRecord2.fFare
post
exists1 wFareRecord in set aSetOfFare &
{aDeparture, anArrival} = {wFareRecord.fDeparture, wFareRecord.fArrival} and
RESULT = wFareRecord.fFare; end fareCaculate
3.测试
现在编写测试程序对上述需求进行测试。测试程序如下所示:
class Test is subclass of fareCaculate values vFareSet = {
mk_FareRecord("Tokyo","Shinagawa",),
mk_FareRecord("Tokyo","Shinjuku",),
mk_FareRecord("Shinjuku","Shinagawa",)
}; functions
static public makeOrderMap : seq of bool +> map nat to bool
makeOrderMap(s) == {i |-> s(i) | i in set inds s};
public run : () -> seq of char * bool * map nat to bool
run() ==
let testcases = [t1(), t2(), t3()],
testResults = makeOrderMap(testcases)
in
mk_("The result of regression test = ",
forall i in set inds testcases & testcases(i), testResults); public t1 : () -> bool
t1() ==
Calculate_fare(vFareSet, "Tokyo", "Shinagawa") = ;
public t2 : () -> bool
t2() ==
Calculate_fare(vFareSet, "Tokyo", "Shinjuku") = ;
public t3 : () -> bool
t3() ==
Calculate_fare(vFareSet, "Shinjuku", "Shinagawa") = ;
end Test
测试结果如图所示:
测试全部返回true,表明需求定义正确。
至此,第一版的的铁路票价计算需求定义程序完成。
【形式化方法:VDM++系列】4.VDM实战1——铁路费用计算的更多相关文章
- 【形式化方法:VDM++系列】3.基于VDM++的图书管理系统需求定义
接前文:http://www.cnblogs.com/Kassadin/p/4091040.html 1.Before We Start: 在开始图书管理系统需求定义之前,需要先进行一些说明. 1.1 ...
- 【形式化方法:VDM++系列】2.VDMTools环境的搭建
接前文:http://www.cnblogs.com/Kassadin/p/3975853.html 上次讲了软件需求分析的演化过程,本次进入正题——VDM开发环境的搭建 (自从发现能打游戏以来,居然 ...
- 【形式化方法:VDM++系列】1.前言
1.前言 今天开始上课学习软件需求分析与VDM++,经过一节课的学习,我又增长了见识. 软件需求工程在软件工程中处于十分核心的地位:需求分析的好坏直接决定软件工程的成败.这一点是我之前对需求工程的理解 ...
- 【asp.net core 系列】10 实战之ActionFilter
0.前言 在上一篇中,我们提到了如何创建一个UnitOfWork并通过ActionFilter设置启用.这一篇我们将简单介绍一下ActionFilter以及如何利用ActionFilter,顺便补齐一 ...
- Chapter 5 软件工程中的形式化方法
从广义上讲,形式化方法是指将离散数学的方法用于解决软件工程领域的问题,主要包括建立精确的数学模型以及对模型的分析活动.狭义的讲,形式化方法是运用形式化语言,进行形式化的规格描述.模型推理和验证的方法. ...
- 手牵手,使用uni-app从零开发一款视频小程序 (系列下 开发实战篇)
系列文章 手牵手,使用uni-app从零开发一款视频小程序 (系列上 准备工作篇) 手牵手,使用uni-app从零开发一款视频小程序 (系列下 开发实战篇) 扫码体验,先睹为快 可以扫描下微信小程序的 ...
- 从零开始搭建django前后端分离项目 系列六(实战之聚类分析)
项目需求 本项目从impala获取到的数据为用户地理位置数据,每小时的数据量大概在8000万条,数据格式如下: 公司要求对这些用户按照聚集程度进行划分,将300米范围内用户数大于200的用户划分为一个 ...
- 【asp.net core 系列】8 实战之 利用 EF Core 完成数据操作层的实现
0. 前言 通过前两篇,我们创建了一个项目,并规定了一个基本的数据层访问接口.这一篇,我们将以EF Core为例演示一下数据层访问接口如何实现,以及实现中需要注意的地方. 1. 添加EF Core 先 ...
- Spark RDD/Core 编程 API入门系列之动手实战和调试Spark文件操作、动手实战操作搜狗日志文件、搜狗日志文件深入实战(二)
1.动手实战和调试Spark文件操作 这里,我以指定executor-memory参数的方式,启动spark-shell. 启动hadoop集群 spark@SparkSingleNode:/usr/ ...
随机推荐
- 【整理】c# 调用windows API(user32.dll)
User32.dll提供了很多可供调用的接口,大致如下(转自http://blog.csdn.net/zhang399401/article/details/6978803) using System ...
- MVC 生成PDf表格并插入图片
最近做的项目中有一个功能,将最终的个人信息生成PDF表格,并插入图片.对于没接触过的程序员来说回一片茫然,网上有多种生成PDf的方法,我给大家介绍一下我认为比较简单,好操作的一种. iTextShar ...
- eclispe 出现超内纯错误
刚开始以为只要修改tomcat的最大最小内存就可以,结果还是报错,后来才懂需要在eclipse.ini文件中修改 -Xms256m-Xmx512m的值改大些,增加虚拟机运行的内存空间 刚开始最小值只有 ...
- 结构型模式——Adapter
1.意图 将一个类的接口转换成客户希望的另一个接口.使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 2.结构 类适配器 对象适配器 3.参与者 Target定义Client使用的与特定领域 ...
- linux find 反转 查找没有被找到的结果
在linux下,有时候需要找一些文件,还有时候这些文件格式不够统一和规范,但是需要排除的那些文件却格式统一,就可以使用find命令的反转功能 一般用find查找文件的命令是: find . -name ...
- jQuery阻止冒泡和HTML默认操作
1:jQuery是一个快捷简便的JavaScript框架,说道框架可以直接理解为就是对原来底层的东西进行了封装使得开发者能够利用这个框架快速开发. 2:在当今的各个浏览器中都支持事件的冒泡,所谓的冒泡 ...
- JSONP 含jquery 实例
前言: 由于Sencha Touch 2这种开发模式的特性,基本决定了它原生的数据交互行为几乎只能通过AJAX来实现. 当然了,通过调用强大的PhoneGap插件然后打包,你可以实现100%的Soc ...
- [译]GC专家系列2:Java 垃圾回收的监控
原文链接:http://www.cubrid.org/blog/dev-platform/how-to-monitor-java-garbage-collection/ 这是"成为GC专家系 ...
- C# 学习之旅(2)--- 意外的收获
今天在完成老师布置的C#作业(计算一元二次方程的根)的时候,收获到意外的知识,所以写此博文予以记录. 意外收获为: 对文本框的输入值进行检测,使之按照要求格式输入. 下面是整个的源代码: using ...
- SDP协议分析
一.SDP协议介绍 SDP 完全是一种会话描述格式 ― 它不属于传输协议 ― 它只使用不同的适当的传输协议,包括会话通知协议(SAP).会话初始协议(SIP).实时流协议(RTSP).MIME 扩展协 ...