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