哈工大软件构造lab3
2020年春季學期
計算機學院《軟件構造》課程
Lab 3實驗報告
1 實驗目標概述 1
2 實驗環境配置 1
3 實驗過程 1
3.1 待開發的三個應用場景 1
3.2 面向可復用性和可維護性的設計:PlanningEntry 1
3.2.1 PlanningEntry的共性操作 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 可復用API設計及Fa?ade設計模式 2
3.9.1 檢測一組計劃項之間是否存在位置獨占沖突 2
3.9.2 檢測一組計劃項之間是否存在資源獨占沖突 2
3.9.3 提取面向特定資源的前序計劃項 2
3.10 設計模式應用 2
3.10.1 Factory Method 3
3.10.2 Iterator 3
3.10.3 Strategy 3
3.11 應用設計與開發 3
3.11.1 航班應用 3
3.11.2 高鐵應用 3
3.11.3 進程應用 3
3.11.4 課表應用 3
3.11.5 學習活動應用 3
3.12 基于語法的數據讀入 3
3.13 應對面臨的新變化 3
3.13.1 變化1 3
3.13.2 變化2 4
3.13.3 變化3 4
3.14 Git倉庫結構 4
4 實驗進度記錄 4
5 實驗過程中遇到的困難與解決途徑 4
6 實驗過程中收獲的經驗、教訓、感想 5
6.1 實驗過程中收獲的經驗和教訓 5
6.2 針對以下方面的感受 5
1 實驗目標概述
本次實驗覆蓋課程第 3、4、5 章的內容,目標是編寫具有可復用性和可維護性的軟件,主要使用以下軟件構造技術:
本次實驗給定了五個具體應用(高鐵車次管理、航班管理、操作系統進程管理、大學課表管理、學習活動日程管理),學生不是直接針對五個應用分別編程實現,而是通過 ADT 和泛型等抽象技術,開發一套可復用的 ADT 及其實現,充分考慮這些應用之間的相似性和差異性,使 ADT 有更大程度的復用(可復用性)和更容易面向各種變化(可維護性)。
2 實驗環境配置
在這里給出你的GitHub Lab3倉庫的URL地址(Lab3-學號)。
https://github.com/ComputerScienceHIT/Lab3-1180300625
3 實驗過程
請仔細對照實驗手冊,針對每一項任務,在下面各節中記錄你的實驗過程、闡述你的設計思路和問題求解思路,可輔之以示意圖或關鍵源代碼加以說明(但千萬不要把你的源代碼全部粘貼過來!)。
3.1 待開發的三個應用場景
我選擇的三個應用場景:
? 航班管理
? 高鐵車次管理
? 大學課表管理
異同點:
位置的數量:分別為2個、N個和1個
僅有大學課表的位置可更改
航班為單個資源,高鐵為有序多個資源,大學課表為無序多個資源
僅有高鐵車次可阻塞
3.2 面向可復用性和可維護性的設計:PlanningEntry
該節是本實驗的核心部分。
3.2.1 PlanningEntry的共性操作
/**
* 開始計劃項
*/
public void start();
3.2.2 局部共性特征的設計方案
public abstract class CommonPlanEntry implements CPEimlements {
protected EntryState estate = WaitState.getInstance();
方法也都是采用狀態模式進行狀態轉換
3.2.3 面向各應用的PlanningEntry子類型設計(個性化特征的設計方案)
采用方案 5:CRP,通過接口組合實現局部共性特征的復用:針對方案4,通過delegation 機制進行改造。每個維度分別定義自己的接口,針對每個維度的不同特征取值,分別實現針對該維度接口的不同實現類,實現其特殊操作邏輯。進而,通過接口組合,將各種局部共性行為復合在一起,形成滿足每個應用要求的特殊接口(包含了該應用內的全部特殊功能),從而該應用子類可直接實現該組合接口。在應用子類內,不是直接實現每個特殊操作,而是通過 delegation 到外部每 個維度上的各具體實現類的相應特殊操作邏輯。
public class CourseEntry extends CommonPlanEntry implements CoursePlanEntry {
private ALEImplements sin1;
private AREImplements sin2;
private ATEImplements sin3;
private ChangeableLocationEntry cha;
private final String id;
public class FlightEntry extends CommonPlanEntry implements FlightPlanEntry {
private TLEImplements tle;
private AREImplements arei;
private ATEImplements atei;
private final String id;
public class TrainEntry extends CommonPlanEntry implements TrainPlanningEntry {
private MLElmplements mle;
private BEImplements bei;
private MTEImplements mte;
private MREImplements mre;
private final String id;
public interface TrainPlanningEntryextendsManyLocationEntry,BlockableEntry, ManyResourceEntry, ManyTimeEntry {
接口大多相同,返回值的區別很小。
3.3 面向復用的設計:R
@Override
public boolean equals(Object obj);
/**
* 獲得一個自己的相同的資源
*
* @return Resource類型的自己的clone
/
public Resource getResourece();
/*
* 獲得一個資源的標志,例如名字
*
* @return 自己的最有特征的標志
*/
public String getbiaozhi() ;
/**
-
車廂類型的資源,不可變類
*/
public final class Carriage implements Resource {
private final String ID, type;
private final int capacity, year;// Abstraction function:
// number, type, capacity, year分別表示車廂的編號,類型,定員數,出廠年份
// Representation invariant:
// 車廂編號不能為null,定員數,出廠年份是正數
// Safety from rep exposure:
// 所有屬性均為private final
/**
-
飛機類型的資源,不可變類
*/
public final class Plane implements Resource {
private final String ID, model;
private final int seats,age;// Abstraction function:
// ID, model, seats,age分別表示飛機的編號,機型號,座位數,機齡
// Representation invariant:
// 飛機編號不能為null,座位數和機齡是正數
// Safety from rep exposure:
// 所有屬性均為private final
/** -
教師類型的資源,不可變類
*/
public final class Teacher implements Resource {
private final String ID, name, position;
private final boolean sex;// Abstraction function:
// ID, name, position分別表示教師的編號,姓名,職稱
// sex為true表示該教師性別為男,false為女
// Representation invariant:
// 教師姓名和身份證號不能為null
// Safety from rep exposure:
// 所有屬性均為private final
3.4 面向復用的設計:Location
/** -
位置
/
public interface Location {
/*- 獲得該位置的地址名
- @return String類型的該位置的地址名
/
public String getPlace();
/* - 獲得相同的位置
- @return Location類型位置的clone
*/
public Location getLocation();
@Override
public boolean equals(Object obj);
}
/**
-
機場,不可變類
*/
public final class Airport implements Location {private final String longitude, latitude, name;
private final boolean share;// Abstraction function:
// longitude,latitude,place分別表示機場所在位置的經度,緯度,機場名
// Share 表示機場是否可共享
// Representation invariant:
// 機場名不能為null,Share為true
// Safety from rep exposure:
// 所有屬性均為private final
/** -
教室,不可變類
*/
public final class Classroom implements Location {
private final String longitude, latitude, name;
private final boolean share;// Abstraction function:
// longitude,latitude,place分別表示教室所在位置的經度,緯度,教室名
// Share 表示教室是否可共享
// Representation invariant:
// 教室名不能為null,Share為false
// Safety from rep exposure:
// 所有屬性均為private final
/**
- 高鐵站,不可變類
*/
public class Trainstation implements Location {
private final String longitude, latitude, name;
private final boolean share;
3.5 面向復用的設計:Timeslot
/**
-
起止時間,不可變類
*/
public final class Lot_time {
private final Calendar start, end;// Abstraction function:
// start, end分別表示起止時間
// Representation invariant:
// 開始時間,結束時間不為空
// Safety from rep exposure:
// 所有屬性均為private final
public Lot_time(Calendar start, Calendar end) {
this.start = start;
this.end = end;
checkRep();
}/**
- 獲得開始時間
- @return Calendar 開始時間
*/
public Calendar getStartTime() {
return (Calendar) start.clone();
}
/**
- 獲得結束時間
- @return Calendar 結束時間
*/
public Calendar getEndTime() {
return (Calendar) end.clone();
}
// checkRep
public void checkRep() {
assert !(start == null || end == null);
}
3.6 面向復用的設計:EntryState及State設計模式
/**
- 一個能夠改變狀態和獲得狀態的接口
/
public interface EntryState {
/*- 向下進行下一個狀態 *
- @return 一個新狀態的接口
/
public EntryState nextState();
/* - 撤銷或阻塞一個狀態
- @return 一個新狀態的接口
/
public EntryState cancleState();
/* - 獲得當前狀態的信息
- @return 字符串類型的當前狀態信息
*/
3.7 面向應用的設計:Board
import java.util.List;
import Entry.PlanningEntry.CPEimlements;
import Resource.Resource;
/**
- 將計劃項可視化
/
public interface Board {
/*- 將此處的計劃項可視化
public void display();
/*- 選擇與自身位置匹配的計劃項,加到可視化計劃項列表中
- @param List<PlanEntry> 一組計劃項
*/
public void add(List<CPEimlements> entry);
*課程的可視化
*/
public class CourseBoard implements Board {
private final Location location;
private List<CPEimlements> entry;
/**
- 航班的可視化
*/
public class FlightBoard implements Board {
private final Location location;
private List<CPEimlements> entry;
private static final int range = 1;
public static final int arrive = 1;
public static final int leave = -1;
// Abstraction function:
// location, entry分別表示位置與在此位置處的計劃項集合
// Representation invariant:
// location不能為空
// Safety from rep exposure:
// location為private final,entries為private
/**
-
高鐵的可視化
*/
public class TrainBoard implements Board {
private final Location location;
private List<CPEimlements> entry;
private static final int range = 1;
public static final int arrive = 1;
public static final int leave = -1;// Abstraction function:
// location, entry分別表示位置與在此位置處的計劃項集合
// Representation invariant:
// location不為空
// Safety from rep exposure:
// location為private final,entries為private
3.8 Board的可視化:外部API的復用
調用public class Create extends JFrame{
public Create(String xinxi,Vector<Vector<?>> data, Vector name) {
table = new JTable(data, name);
scrollpane = new JScrollPane(table);
setTitle(xinxi);
setBounds(300,300,400,400);
setVisible(true);
add(scrollpane,BorderLayout.CENTER);
}
3.9 可復用API設計及Fa?ade設計模式
3.9.1 檢測一組計劃項之間是否存在位置獨占沖突
public boolean CLConflict(List<CPEimlements> entry) {
for(CPEimlements cpei1 : entry) {
for (CPEimlements cpei2 : entry) {
CoursePlanEntry cpe1=(CoursePlanEntry)cpei1;
CoursePlanEntry cpe2=(CoursePlanEntry)cpei2;
if(cpei1.getid().equals(cpei2.getid()))
continue;
if(cpe1.getEntryLocation().equals(cpe2.getEntryLocation()))
{
Calendar cpe1time = cpe1.getTime().getStartTime();
Calendar cpe2time = cpe2.getTime().getStartTime();
Calendar cpe1etime = cpe1.getTime().getEndTime();
Calendar cpe2etime = cpe2.getTime().getEndTime();
if (!(cpe1time.after(cpe2etime) || cpe1etime.before(cpe2time)))
return false;
}
}
}
return true;
}
三個都差不多,故只放一個
3.9.2 檢測一組計劃項之間是否存在資源獨占沖突
public boolean CRConflict(List<CPEimlements> entry) {
for (CPEimlements cpei1 : entry)
for (CPEimlements cpei2 : entry) {
CoursePlanEntry cpe2 = (CoursePlanEntry) cpei2;
CoursePlanEntry cpe1 = (CoursePlanEntry) cpei1;
if(cpei1.getid().equals(cpei2.getid())||cpe1.getResource()==null||cpe2.getResource()==null)
continue;
if (cpe2.getResource().equals(cpe1.getResource())) {
Calendar cpe1time = cpe1.getTime().getStartTime();
Calendar cpe2time = cpe2.getTime().getStartTime();
Calendar cpe1etime = cpe1.getTime().getEndTime();
Calendar cpe2etime = cpe2.getTime().getEndTime();
if (!(cpe1time.after(cpe2etime) || cpe1etime.before(cpe2time)))
return false;
}
}
return true;
}
3.9.3 提取面向特定資源的前序計劃項
public CPEimlements FEResource(Resource r, CPEimlements cpei,List<CPEimlements> entry) {
CoursePlanEntry cpe1 = (CoursePlanEntry) cpei;
for (CPEimlements cpei2 : entry) {
CoursePlanEntry cpe2 = (CoursePlanEntry) cpei2;
if (cpe2.getResource().equals?) {
if (cpe2.getTime().getStartTime().before(cpe1.getTime().getStartTime())) {
return cpei2;
}
}
}
return null;
}
3.10 設計模式應用
請分小節介紹每種設計模式在你的ADT和應用設計中的具體應用。
3.10.1 Factory Method
3.10.2 Iterator
Vector<Vector<?>> data = new Vector<>();
Vector name = new Vector<>();
Iterator<CPEimlements> hmx = entry.iterator();
Sort sort;
sort = new ShellSort();
sort.shell(entry, location, type);
3.10.3 Strategy
/**
-
希爾排序
*/
public class ShellSort implements Sort {@Override
public void shell(List<CPEimlements> entry, Location location, int type) {
int i, j, k;
為數據進行排序
3.11 應用設計與開發
利用上述設計和實現的ADT,實現手冊里要求的各項功能。
只需保留你選定的三個應用即可。
3.11.1 航班應用
3.11.2 高鐵應用
3.11.3 進程應用
3.11.4 課表應用
3.11.5 學習活動應用
3.12 基于語法的數據讀入
依據給定數據的格式,可以設計正則表達式,并保存在Pattern對象中。
“Flight:(.?),([A-Z]{2}\d{2,4})\n\{\nDepartureAirport:(\w+)\nArrivalAirport:(\w+)\nDepatureTime:(.?)\nArrivalTime:(.?)\nPlane:((N|B)\d{4})\n\{\nType:([a-zA-Z0-9]+)\nSeats:(.?)\nAge:((0|(([1-9])\d))(\.\d)?)\n\}\n\}\n”)
判讀異常
異常就由頂層方法捕獲,打印文件格式不符合的信息,把現有的計劃項返回
反之就把新建的航班加入到計劃項集合中
3.13 應對面臨的新變化
只考慮你選定的三個應用的變化即可。
3.13.1 變化1
將航班的實現類的接口的繼承由之前的TwoLocationEntry改為ThreeLocationEntry
3.13.2 變化2
課程:把接口繼承由之前的SingleSortedResourceEntry改為MultipleSortedResourceEntry
3.13.3 變化3
高鐵:把父類commonPlanningEntry中的cancel重寫一下即可,讓只有未分配與阻塞狀態可取消
3.14 Git倉庫結構
請在完成全部實驗要求之后,利用Git log指令或Git圖形化客戶端或GitHub上項目倉庫的Insight頁面,給出你的倉庫到目前為止的Object Graph,尤其是區分清楚314change分支和master分支所指向的位置。
6.2 針對以下方面的感受
(1) 重新思考Lab2中的問題:面向ADT的編程和直接面向應用場景編程,你體會到二者有何差異?本實驗設計的ADT在五個不同的應用場景下使
用,你是否體會到復用的好處?
答:前者得先思考框架前期麻煩但是后期會變得更方便,后者前期可以隨心所欲地寫,但越到后面需要小心的地方就越多,出現問題多的話可能得重新開始寫代碼。修改和使用非常方便。
(2) 重新思考Lab2中的問題:為ADT撰寫復雜的specification, invariants, RI,
AF,時刻注意ADT是否有rep exposure,這些工作的意義是什么?你是否愿意在以后的編程中堅持這么做?
答:幫助作者或者使用代碼的人快速理解代碼。愿意因為這個可以減少我花費的時間。
(3) 之前你將別人提供的API用于自己的程序開發中,本次實驗你嘗試著開發給別人使用的API,是否能夠體會到其中的難處和樂趣?
答:深深的體會到了難處。
(4) 在編程中使用設計模式,增加了很多類,但在復用和可維護性方面帶來了收益。你如何看待設計模式?
答:剛開始建的時候很難,但是后來就會很好用。
(5) 你之前在使用其他軟件時,應該體會過輸入各種命令向系統發出指令。本次實驗你開發了一個解析器,使用語法和正則表達式去解析輸入文件并據此構造對象。你對語法驅動編程有何感受?
答:考慮的東西非常多,一錯就是一大片。
(6) Lab1和Lab2的大部分工作都不是從0開始,而是基于他人給出的設計方案和初始代碼。本次實驗是你完全從0開始進行ADT的設計并用OOP實現,經過五周之后,你感覺“設計ADT”的難度主要體現在哪些地方?你是如何克服的?
答:主要難在框架的構建。我向很多同學咨詢了。
(7) “抽象”是計算機科學的核心概念之一,也是ADT和OOP的精髓所在。本實驗的五個應用既不能完全抽象為同一個ADT,也不是完全個性化,如何利用“接口、抽象類、類”三層體系以及接口的組合、類的繼承、設計模式等技術完成最大程度的抽象和復用,你有什么經驗教訓?
答:熟練掌握接口的使用能讓代碼復用率變高,代碼量減少。
(8) 關于本實驗的工作量、難度、deadline。
答:工作量很大,難度其次。就是需要一直不厭其煩的修改。
(9) 到目前為止你對《軟件構造》課程的評價。
答:學到很多的知識,但難度很大,很有挑戰。
總結
以上是生活随笔為你收集整理的哈工大软件构造lab3的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: css3d转换_使用CSS 3D转换创建
- 下一篇: 高阶低通无源滤波器的设计