1、实验二 旅行预定系统的设计与实现 实验要求 编写一个简单的旅行预订系统。 该系统涉及的信息有航班, 出租车, 宾馆房间和客户的 数据信息。他们的关系模式如下: FLIGHTS (String flightNum, int price, int numSeats, int numAvail, String FromCity, String ArivCity) ; HOTELS(String location, int price, int numRooms, int numAvail) ; CARS(String location, int price, int numCars, int num
2、Avail) ; CUSTOMERS(String custName) ; RESERVATIONS(String custName, int resvType, String resvKey) 为简单起见,我们有下列假设: 1. 在给定的一个班机上,所有的座位价格也一样;flightNum 是表 FLIGHTS 的一个主码 (primary key ) 。 2. 在同一个地方的所有的宾馆房间价格也一样;location 是表 HOTELS 的一个 主码。 3. 在同一个地方的所有出租车价格一样;location 是表 CARS 的一个主码。 4. custName 是表 CUSTOMERS
3、的一个主码。 5. 表 RESERVATIONS 包含着那些和客户预订的航班、出租车或宾馆房间相应的条目,具体 的说, resvType 指出预订的类型 (1 为预订航班, 2 为预订宾馆房间, 3 为预订出租车) , 而 resvKey 是表 RESERVATIONS 的一个主码。 6. 在表 FLIGHTS 中,numAvail 表示指定航班上的还可以被预订的座位数。 对于一个给定的 航班 (flightNum ), 数据库 一致性的条件之一是, 表 RESERVATIONS 中所有预订该航班的 条目数加上该航班的剩余座位数必须等于该航班上总的座位数。这个条件对于表 CARS 和表 HOT
4、ELS 同样适用。 该应用系统完成如下基本功能: 1 航班,出租车,宾馆房间和客户基础数据的入库,更新 2 预定航班,出租车,宾馆房间。 3 查询航班,出租车,宾馆房间,客户和预订信息。 4 查询某个客户的旅行线路。 5 检查预定线路的完整性。 概要设计 我的程序起名为 TravelAgency,使 用 Access+ODBC+MFC 的方式 实现, 能够实现上述所有 功能。Access 使用的是 2007 版,MFC 的版本是跟随 Visual Studio 2008 的 9.0 版,ODBC 驱动 使用的是 Microsoft Access Driver 。 首先,利用 Access 中创
5、 建一个满足实验要求中关系模式定义的数据库 Tour.mdb 。其中 FLIGHTS 表、 HOTELS 表、 CARS 表、 CUSTOMERS 表的主键分别按实验要求依次取为 flightNum 、 location 、location 、custName。对 于 RESERVATIONS 表, 我把 resvKey 定义为所选定的预定 内 容在FLIGHTS 表、 HOTELS 表和CARS 表中对应的主键; 在RESERVATIONS 表中, 主键为(custName, resvType,resvKey) 。 再利用Windows 的ODBC 数据源管理工具创建一个File DSN ,
6、 使用Microsoft Access Driver , 并与刚才去创建的 Tour.mdb 连接。 该 DSN 起名为 tour.dsn 。 最后, 创建一个 MFC 应用程序, 依次选择使用单文档/ 视图架构、 有文件支持的数据库、 Dynaset 模式。 主记录集类CTravelAgencySet (继承自CRecordSet )与Tour.mdb 中的 RESERVATIONS 表绑定 , 同 时创建4 个MFC Consumer (也是 继承 自CRecordSet ) CUSTOMERS 、 FLIGHTS 、HOTELS 、CARS ,分别与 数 据库中其 他 4 个表相 连接
7、。至此, 整个 数据库应 用系 统 的平台就 搭好 了。 功能介绍与实现 软件主界面如下图所示。 项目选择区用于选择当前 Flight 、Car 、Hotel 和 Customer 中的 某一项进行操作;内容显示区使用一个 ListControl ,该控件十分适合显示一个表中的信息。 为方便起见,我也用它来显示旅客行程和可用路线。 图 1 软件 界面 下面介绍功能选择区每一个按钮的功能,以及该功能的实现。所有功能都在 TraveAgencyView.cpp 中实现。 (1 )List Items 显示表中内容 图 1 中显示 的正是当前表选择为 FLIGHTS 时, List Items 的显
8、示效果。 该按钮对应于void CTravelAgencyView:OnBnClickedListItem() 函数, 实现该 功能比较简单。 首先根据 选择的表的类型, 创建ListCtrol 的表头; 然后利用CRecordSet 的MoveNext() 函数遍历整个表, 并把每一行的信息输出到 List Ctorl 中。 (2 )Add Item 添加记录 图 2 添加 记录 项目选择区 内容显示区 功能选择区 该功能对应与 void CTravelAgencyView:OnBnClickedAddItem() 。 以 FLIGHTS 表为例,图 2 显示的是点 击 Add Item 按
9、扭后弹出的 Add Flights 对话框;对每一种类型的表 有一个单独此种对划款。 的点击OK , 系统会利用CRecordSet:AddNew() 和CRecordSet:Update() 函数实现记录的添加。 图 3 添 加记 录后的表 图 3 显示了 点击 OK 后表 中的内容,可以看到新的航班 D002 以经成功的加入了表中。 (3 )Edit Item (修改记录)和 Delete Item (删除记录) 这两个功能分别对由 void CTravelAgencyView:OnBnClickedUpdateItem() 和 void CTravelAgencyView:OnBnCli
10、ckedDeleteItem2() 实现。 以图3 为例 , 当在List Control 中 选定一个 项目 后,Edit Item 和Delete Item 两个 按钮就被 激活 了,可以 使用 。 这两个功 能分 别调用 了CRecordSet:Edit() 和CRecordSet:Delete() 函数。 为保证数 据库 的一致性 , 在 做修改和 删除 记录时, 软件 会检测RERVATIONS 表中 有没有哪 一个预定 使用 了待修改 或删 除的条目 ,如 果有的话 ,软 件会弹出MessageBox 提示必须先 移除 所有相关 的预 定,如 图4 所示 。 图 4 修 改或 删除
11、时的 提示 错误 (4 )List Reservations 显示所有预定信息 图 5 显 示所 有预定信 息 由 void CTravelAgencyView:OnBnClickedListResv() 实现,效果 见 图 5 。实 现 方法与 List Items 类似 ,实际上 该功 能可以合 并 到 List Items 中,只 需 在项目选 择区 添 加 Reservation 这一个选 项 并对于void CTravelAgencyView:OnBnClickedListItem() 函数做适 当修 改既可。 (5 )Make Reservation 进行预定 图 6 添 加预 定
12、对话框 由void CTravelAgencyView:OnBnClickedMakeRes() 实现 ,弹出的 添加 对话框如 图 6 所 示。 实现方法 类似 与 Add Item 。有所不 同 的是,在 进行 预定时, 系统 会检查所 要预 定 的信息对 应的 表, 如 果预定 的条目不 存在 或者可用 数目 为0 , 则提示 不能完成 ; 成 功预定后 , 对 相关条目 在对 应表中的 可用 数减1. (6 )Display Itinerary 显示旅客 行程 由 void CTravelAgencyView:OnBnClickedDisplayItin() 实现。 在 CUSTOME
13、R 表正在显 示时 ,选中某 个旅 客,Display Itinerary 按钮就 被激 活,点击 就会 根距该旅 客的 机票预定 信息 找出一条 连续 的旅行线 路。 如果不能 找出 这样首尾 相连 的旅行线 路, 则会提示“The itinerary is incomplete, please make more reservation!“ 的错误 。 图7 是显 示了Hans (具 体预订信 息见 图5 )的 行程 路线。 (6 )Route 路线查找 由 void CTravelAgencyView:OnBnClickedRoute() 实现。 点击 Route 按钮,会 弹出如 图7
14、 所 示的对话 框用 于输入出 发地 和目的地 , 点 击OK 就 会在 主窗口 的List 控件中 显示 中转最少 的一 条线路, 以及 每条线路 可用 的航班, 如 图8 所示 。 实现该功能的基本算法是深度优先遍历。为建立一张航班路线构成的图,我用数字索引一 个城市作 为顶 点,并定 义了 如下结构 表示 边。 struct FlEdge CString flight; / 航班 CString strFrom, strTo; / 航班的起 止城市 int from, to; / 起止城市 的索引值 ; 我使用bool *flightsWeb 表示航班 路线图, 这是 一个n元 仿阵,n
15、 表示城 市 数目。当 且 仅当城市i 到城 市j有 航班, 则flightsWebij 为真。 辅助的数 据结 构还包括CArray allFlights 和std:map cityNodes ,分别表 示所 有航班以 及从 城市到其 索引 数字的映 射。 具体的执 行过 程为: 1 )顺序访 问FLIGHTS表中的所有 航班 。在访问过程中为每一个城市选定一个数字作代表, 并添加到cityNodes 中; 为每个航 班构 造一个FlEdge 表示,并 添 加到allFlights 中。 2 )利用上 一 步得到的cityNodes 和allFlights 构造路线图flightsWeb 。
16、 3 )对待查 找 的路线, 在cityNodes 中找出其起 止城 市对应的 结点 。如果找 不到 ,则该城 市没有航 班到 达,查找 路线 失败。 4 ) 初始化每 一个结点 的前 驱为-1 ; 以出 发城市作 为起 始结点, 对flightsWeb 作深度优先 遍历,并 记录 每一个结 点在 遍历过程 中的 前驱。 5 ) 如果 目的 地城市对 应的 结点的前 驱不 为-1 , 则 说明 在图上找 到了 一条线路 ; 否 则, 查 找 路线失败 。 6 ) 如果 查找 路线成功 , 则 利用前驱 信息 得到一条 从出 发地到目 的地 的路线 ; 对路 线中的每 一步,查 找allFlights 中所有符 合的 航班。 图 7 出发地 和目的地 输入 图 8 显示 最短 路 线 可能的改进 FLIGHTS 、CARS 和 HOTELS 可以添加日 期信息 Date ,同时添加到主键中,这样更符合实 际。 在预定比如航班时,系统可以提示有那些航班是可用的 添加账户管理功能 FLIGHTS 中添 加距离、价 格等信息; 在路线完整 性检查时, 不仅仅可以 根据中转次 数, 而且可以根据总距离或总价格选择最短路线。