软件构造实验三

 

2020年春季学期
计算机学院《软件构造》课程

 

 

 

 

Lab 3实验报告
 

 

 

 

 

 

 

 

 

 

 

 

目录

 

1 实验目标概述··· 1

2 实验环境配置··· 1

3 实验过程··· 1

3.1 待开发的三个应用场景··· 1

3.2 面向可复用性和可维护性的设计:PlanningEntry<R>· 1

3.2.1 PlanningEntry<R>的共性操作··· 1

3.2.2 局部共性特征的设计方案··· 2

3.2.3 面向各应用的PlanningEntry子类型设计(个性化特征的设计方案)··· 2

3.3 面向复用的设计:R· 2

3.4 面向复用的设计:Location· 2

3.5 面向复用的设计:Timeslot· 2

3.6 面向复用的设计:EntryState及State设计模式··· 2

3.7 面向应用的设计:Board· 2

3.8 Board的可视化:外部API的复用··· 2

3.9 PlanningEntryCollection的设计··· 2

3.10 可复用API设计及Façade设计模式··· 2

3.10.1 检测一组计划项之间是否存在位置独占冲突··· 2

3.10.2 检测一组计划项之间是否存在资源独占冲突··· 2

3.10.3 提取面向特定资源的前序计划项··· 2

3.11 设计模式应用··· 2

3.11.1 Factory Method· 3

3.11.2 Iterator 3

3.11.3 Strategy· 3

3.12 应用设计与开发··· 3

3.12.1 航班应用··· 3

3.12.2 高铁应用··· 3

3.12.3 进程应用··· 3

3.12.4 课表应用··· 3

3.12.5 学习活动应用··· 3

3.13 基于语法的数据读入··· 3

3.14 应对面临的新变化··· 3

3.14.1 变化1· 3

3.14.2 变化2· 4

3.14.3 变化3· 4

3.15 Git仓库结构··· 4

4 实验进度记录··· 4

5 实验过程中遇到的困难与解决途径··· 4

6 实验过程中收获的经验、教训、感想··· 5

6.1 实验过程中收获的经验和教训··· 5

6.2 针对以下方面的感受··· 5

 

 

 

  1. 实验目标概述

根据实验手册简要撰写。

本次实验覆盖课程第 3、4、5 章的内容,目标是编写具有可复用性和可维护

性的软件,主要使用以下软件构造技术:

  1. 子类型、泛型、多态、重写、重载
  2. 继承、代理、组合
  3. 常见的 OO 设计模式
  4. 语法驱动的编程、正则表达式
  5. 基于状态的编程
  6. API 设计、API 复用
  7. 本次实验给定了五个具体应用(高铁车次管理、航班管理、操作系统进程管
  8. 理、大学课表管理、学习活动日程管理),学生不是直接针对五个应用分别编程
  9. 实现,而是通过 ADT 和泛型等抽象技术,开发一套可复用的 ADT 及其实现,充
  10. 分考虑这些应用之间的相似性和差异性,使 ADT 有更大程度的复用(可复用性)
  11. 和更容易面向各种变化(可维护性)。
  1. 实验环境配置

实验环境设置请参见 Lab-0 实验指南。

本次实验在 GitHub Classroom 中的 URL 地址为:

https://classroom.github.com/a/aMg3ti15

请访问该 URL,按照提示建立自己的 Lab3 仓库并关联至自己的学号。

本地开发时,本次实验只需建立一个项目,统一向 GitHub 仓库提交。实验

包含的多个任务分别在不同的包内开发,具体目录组织方式参见各任务最后一部

分的说明。请务必遵循目录结构,以便于教师/TA 进行测试。

https://github.com/ComputerScienceHIT/Lab3-1180300604.git

  1. 实验过程

请仔细对照实验手册,针对每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。

    1. 待开发的三个应用场景

 

1.航班管理

2.高铁车次管理

4.大学课表管理

 

分析三个应用场景的异同,理解需求:它们在哪些方面有共性、哪些方面有差异。

 

Flight 和 Course 十分类似 可以从他们的board程序里面看出来,表格是根据地点来绘制的,但是这两个都只有1个location,不需要经停,开始之后都不能阻塞

Train有一个最大的不同,它含有多个location,且每个location都有经停时间,同时表格上也有差异,但是board的显示上面有一些区别

    1. 面向可复用性和可维护性的设计:PlanningEntry<R>

该节是本实验的核心部分。

 

 

 

 

 

 

 

 

程序的结构主要是  

  1. 首先有一个接口

 

 

  1. 接着是一堆抽象类来对应上面的接口

 

  1. 然后是common的各个基本类,继承上述抽象类,这些类都是个体类针对个体,单个计划,单个资源,单个地点,单个时间

 

  1. 在之后是common_s类,采用装饰模式,没有继承,直接设置了包含上面单个common类的list,大多数类是通过list来集成的

 

  1. APP

 

 

 

      1. PlanningEntry<R>的共性操作

 

都是针对单个计划项的各种操作。

      1. 局部共性特征的设计方案

主要是对于里面的list的操作,增加或者移除计划

 

      1. 面向各应用的PlanningEntry子类型设计(个性化特征的设计方案)

 

在装饰过的第二子类中方法比较完善,因此例如像上述的第三子类不太需要太多的特定方法,有一些特定方法放在了app类里

    1. 面向复用的设计:R

 

此处的泛型R,L,都是代表类似Flight_Resource, Flight_Location的类,需要在创建CommonPlanningEntry的时候传入进去,因此可以改成Train_Location等等

    1. 面向复用的设计:Location

 

首先是一个接口

 

Location的抽象类没有补充太多属性和方法

再用对应于单个location 的commonlocation来继承添加部分属性重写一个方法

 

采用装置模式,产生了一个包含多个单个location的common_s类

 

包含了众多处理list的方法,其中包含几个函数,传入参数是String,方便在app即客户端口,通过读入的string 直接对list做处理。

 

后面 再针对不同的需求添加方法

 

    1. 面向复用的设计:Timeslot

 

首先是一个接口,这里主要采用了localdatetime这个类来表示时间,在app里面用户每操作一次,将计划时间和现有时间做一次对比,将所有计划项的时间进行更新。

 

抽象类没有补充太多

 

后面的继承类就添加了单个时间的年月日小时分钟秒,还有个总扩的time(localdatetime)

update_settime就是讲属性里的int同步到time里面,还有个比较重要的方法是time_deal

在客户端输入时,客户往往输入的是字符串,比如日期 “2020:1:1“  时间 “5:00”

Time_deal函数可以直接被调用,判断读入的是日期字符串还是时间字符串,将读入数据更新到属性的year month……等。

 

 

 

由于采用装饰模式,不想要类之间有太多的耦合,所以之间创建了存储多个时间的list

对于航班计划来说,就两个时间,高铁有多个,但都可以用list这种动态数组来存储,有很好的复用性。

后面针对 航班高铁课程 再继续继承可扩展的子类。

    1. 面向复用的设计:EntryState及State设计模式

State类的作用包含在了planningentry类里面,这里不赘述。

    1. 面向应用的设计:Board

 

针对3个APP,4个方法。

显示的gui主要用的是

 

Jtable表格方法

效果如图

 

这里是英文界面,设置的地点是“2”可以用“哈尔滨”等代替

 

 

 

    1. Board的可视化:外部API的复用

 

主要采用java JTable 的api,效果还可以。

 

 

 

    1. PlanningEntryCollection的设计

 

 

命名为Common_PlanningEntries,内置list来集合计划

 

    1. 可复用API设计及Façade设计模式

 

      1. 检测一组计划项之间是否存在位置独占冲突

通过判断资源state标志位,在common类里面置了state标志位,在app中也有检查

      1. 检测一组计划项之间是否存在资源独占冲突

通过判断资源state标志位,在common类里面置了state标志位,在app中也有检查

Resource 和location里面都有标志位和相应方法来判断占用。

 

    1. 设计模式应用

请分小节介绍每种设计模式在你的ADT和应用设计中的具体应用。

      1. Factory Method

可以使用匿名类的方式来实现 但是也可以在子类中创建 创建方法如:

 

也可以在别的类里面创建类似的方法构成工厂模式。

      1. Iterator

Iterator比较与list有些复杂,list作为可变数组非常好用,唯一不足是在迭代过程中无法remove.

 

 

 

 

      1. Strategy

针对特定List<R> 的add操作就有两种算法,一种传入参数是R一种是String,在app中都有采用。String的更加方便。

 

 

 

 

 

 

这是两种截然不同 的add方法,传入参数明显string较为方便

 

 

 

    1. 应用设计与开发

利用上述设计和实现的ADT,实现手册里要求的各项功能。

只需保留你选定的三个应用即可。

      1. 航班应用

 

 

 

首先创建了上述的多个航班类的对象,用来管理资源和计划,

之后的方法对应用户可以进行的操作,在main函数中是首先打印出可以进行的操作,然后和用户交互,根据用户输入对应调用上述函数

 

例如add_flightentry函数,内部十分复杂,因为要检测资源,地点是否存在是否可用等等。

       public static void add_flightentry() {

              System.out.println("adding.............");

              System.out.println("please input the start and end time start and end place, type of the plane");

              System.out.println("for example: Chengdu Beijing c919 2020:6:1 9:00 12:00");

              BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

              String input_entry = null;

              try {

                     input_entry = reader.readLine();

              } catch (IOException e) {

                     e.printStackTrace();

              }

              String divide[] = input_entry.split(" ");

             

              //input check

              boolean check_flag1,check_flag2,check_flag3;

              check_flag1=flight_location.check(divide[0]);

              check_flag2=flight_location.check(divide[1]);

              check_flag3=flight_resource.check(divide[2]);

              if ((check_flag1 == false) || (check_flag2 == false) || (check_flag3 == false)) {

                     System.out.println("Plane modle or locations are not added.");

                     System.out.println("Add failed.");

                     return;

              }

             

              //location resource deal

              CommonLocation need_add0 = new CommonLocation();

              CommonLocation need_add1 = new CommonLocation();

              Flight_Resource need_add2 = new Flight_Resource();

              Flight_Location need_add3 = new Flight_Location();

             

              for (CommonLocation i : flight_location.common_locations) {

                     if (divide[0].equals(i.get_location())) {

                            need_add0=i;

                     }

                     if (divide[1].equals(i.get_location())) {

                            need_add1=i;

                     }

              }

              need_add3.add(need_add0);

              need_add3.add(need_add1);

             

              for(CommonResource i : flight_resource.common_resources) {

                     if (divide[2].equals(i.get_resource())) {

                            need_add2.common_resources.add(i);

                     }

              }

              //time deal

              Common_Times need_addTimes = new Common_Times();

              CommonTime need_addTime1 = new CommonTime();

              CommonTime need_addTime2 = new CommonTime();

              need_addTime1.time_deal(divide[3]);

              need_addTime1.time_deal(divide[4]);

              need_addTime1.date_copy(need_addTime2);

              need_addTime2.time_deal(divide[5]);

              need_addTime1.update_settime();

              need_addTime2.update_settime();

             

              need_addTimes.add_times(need_addTime1);

              need_addTimes.add_times(need_addTime2);

             

             

              flight_PlanningEntries.add_entry(need_addTimes,need_add2,need_add3);

              System.out.println("All entries:");

              show_fightenties();

             

       }

 

      1. 高铁应用

System.out.println("input middle location and time(like Chengdu 9:00 9:05 Meishan 10:00 10:07):");

              BufferedReader reader1 = new BufferedReader(new InputStreamReader(System.in));

              String input_entry1 = null;

              try {

                     input_entry1 = reader1.readLine();

              } catch (IOException e) {

                     e.printStackTrace();

              }

              String divide1[] = input_entry1.split(" ");

              CommonLocation need_addx = new CommonLocation();

              CommonTime need_addy = new CommonTime();

              CommonTime need_addz = new CommonTime();

              for(int i=0;i<divide1.length;i=i+3) {

                     for (CommonLocation o : flight_location.common_locations) {

                            if (divide1[i].equals(o.get_location())) {

                                   need_addx=o;

                            }

                     }

                     need_addy.time_deal(divide1[i+1]);

                     need_addTime1.date_copy(need_addy);

                     need_addz.time_deal(divide1[i+2]);

                     need_addTime1.date_copy(need_addz);

                    

                     need_add3.add(need_addx);//l

                     need_addTimes.add_times(need_addy);//t

                     need_addTimes.add_times(need_addz);//t

 

主要区别是中间有多个站点,同时每个站点包含到达时间,出发时间,所以用户需要再次输入中间站点。

                    

      1. 课表应用

//           flight_resource.add_resource("a", "plane");

//           flight_resource.add_resource("b", "plane");

//           flight_resource.add_resource("c", "plane");

//           flight_resource.add_resource("d", "plane");

//           flight_location.add_location("1");

//           flight_location.add_location("2");

//           flight_location.add_location("3");

//           flight_location.add_location("4");

             

              System.out.println("start time: "+now_time);

              BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

              System.out.println("please choose the operation(example: if you choose the first operation please input 1): ");

              System.out.println("1. add a plane");

              System.out.println("2. delete a plane");

              System.out.println("3. add an flight entry");

              System.out.println("4. cancle an flight entry");

              System.out.println("5. set resource to a flight entry");

              System.out.println("6. change location of a flight entry");

              System.out.println("7. see an entry's state");

              System.out.println("8. location board");

              System.out.println("111. exit");

              int input_number=0;

              while(input_number!=111) {

              input_number=0;

              try {

                     input_number=Integer.valueOf(reader.readLine());

              } catch (IOException e) {

                     // TODO 自动生成的 catch 块

                     System.out.println("get input failed");

                     e.printStackTrace();

              }

             

              switch(input_number) {

              case 1:

                     add_plane();

                     update();

                     break;

              case 2:

                     delete_plane();

                     update();

                     break;

              case 3:

                     add_flightentry();

                     update();

                     break;

              case 4:

                     delet_flightentry();

                     update();

                     break;

              case 5:

                     set_resource_to();

                     update();

                     break;

              case 6:

                     change_location();

                     update();

                     break;

              case 7:

                     see_state();

                     update();

                     break;

              case 8:

                     show_board();

                     update();

                     break;

              case 9:

                     break;

              case 111:

                     System.exit(0);

                     break;

              }

              }

             

       }

和飞机计划相比差别不是很大,主要注意要调用board类里面不同的方法,对应课表的显示方式。

    1. 基于语法的数据读入

修改“航班”应用以扩展该功能,读入text 按照指定格式,添加一个文本读写功能

 

使用bufferedreader,filereader类操作文件读写。

传入要更改的航班计划类,资源类,地点类,在函数中对这些类做出更改。

 

 

核心处理部分主要是发现13行一组的规律,通过对字符串的处理,还有split函数应用,类似于if语句,对输入文件进行读取。

    1. 应对面临的新变化

其实飞机增加经停点和火车的差异不是很大,但还是需要做一些小改动

 

 

分支创建了一个新的app叫F314change.java

 

    1. Git仓库结构

 

 

 

 

 

 

  1. 实验进度记录

请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。

每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。

不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。

日期

时间段

计划任务

实际完成情况

2020.5.1

8:00-23:00

读透实验手册

没有怎么读懂,后面和同学讨论,确定了大致采用装饰模式

2020.5.8

7:00-24:00

完成common,commons类

基本完成,复用性不好

2020.5.15

6:30-23:00

完成app类

还不错

20205.16

7:00-23:00

完成扩展内容

Test没写完,分支还没完善

  1. 实验过程中遇到的困难与解决途径

 

 

 

 

 

遇到的难点

解决途径

Gui不会

 

 

上网学习,决定使用JTable

List无法remove

 

 

在迭代中无法remove,flight_PlanningEntries.remove_entry(j);选出来之后再remove

 

Test没有头绪

 

使用app做测试,但其实还是需要习惯测试优先。

文件读入不熟练

上网学习

  1. 实验过程中收获的经验、教训、感想
    1. 实验过程中收获的经验和教训

难度很大,自己还有继续好好学习java,感觉能写出复用性好的api确实是了不起的

    1. 针对以下方面的感受
  1. 重新思考Lab2中的问题:面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?本实验设计的ADT在五个不同的应用场景下使用,你是否体会到复用的好处?

 

答:后面几个app可以轻松复用,不怎么需要重写

 

  1. 重新思考Lab2中的问题:为ADT撰写复杂的specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后的编程中坚持这么做?

 

答:方便后续阅读代码,别人阅读代码,比较愿意

 

  1. 之前你将别人提供的API用于自己的程序开发中,本次实验你尝试着开发给别人使用的API,是否能够体会到其中的难处和乐趣?

 

答:难处是接口不清晰,不熟练,乐趣是简单快捷。

 

  1. 在编程中使用设计模式,增加了很多类,但在复用和可维护性方面带来了收益。你如何看待设计模式?

答:非常好用非常有必要

 

  1. 你之前在使用其他软件时,应该体会过输入各种命令向系统发出指令。本次实验你开发了一个解析器,使用语法和正则表达式去解析输入文件并据此构造对象。你对语法驱动编程有何感受?

 

答:方便快捷,应该非常实用,可以写系统。

 

  1. Lab1和Lab2的大部分工作都不是从0开始,而是基于他人给出的设计方案和初始代码。本次实验是你完全从0开始进行ADT的设计并用OOP实现,经过五周之后,你感觉“设计ADT”的难度主要体现在哪些地方?你是如何克服的?

 

答:主要是架构要提前打好,磨刀不误砍柴工,慢慢来,考虑架构花了很长时间。

 

 

  1. “抽象”是计算机科学的核心概念之一,也是ADT和OOP的精髓所在。本实验的五个应用既不能完全抽象为同一个ADT,也不是完全个性化,如何利用“接口、抽象类、类”三层体系以及接口的组合、类的继承、设计模式等技术完成最大程度的抽象和复用,你有什么经验教训?

 

答:一定要找好同与不同,不然后面继承过于混乱。

 

 

  1. 关于本实验的工作量、难度、deadline。

 

答:工作量太大,不是很难,ddl延长一周更好

 

  1. 到目前为止你对《软件构造》课程的评价。

 

答:感觉学到了太多东西,发现自已以前的程序非常混乱。。。学到的ADT方法,设计模式,让我编程的逻辑更加清晰,能搞大软件了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值