oop課程4-6次作業小結
(1)前言
- `
- ??第四次題目集主要是對答題判斷程序3的進一步改進,增加了對題目類的拆分,需要使用繼承的方式來實現各個種類的題目之間的聯系,但是難度不是很大,只需要對答題程序3稍作修改,區別各個Question的內部實現,既多選與填空的判題方法等,還是很好修改的。此外還有兩個有關迭代的小題目,不是很難但是讓我了解了對toString方法的使用,這些都對后續的題目具有啟發作用,是從答題判斷程序到家庭電路系統的過度,能夠讓我們更能適應新題面的到來。
- ??第五次題目集揭開了全新題面的大幕,面對智能家居的到來,我們也需要適應新潮流,針對家庭電路的控制進行模擬,本次主要進行了抽象類的實際使用,將電路中所有的電路設備進行抽象,所有的共同屬性都歸為一個大類,儲存了各種狀態和方法,在之后進行繼承與調用。只要確定好了方向,對于各個類的定義就自然會成型,測試點不難,很容易就能過,因為是第一次迭代,不用考慮得太多,只要能夠實現大致的功能就夠了,但是一定要在開始就確定好方向,不然很容易跌進思維陷阱。
- ??第六次題目集對第一次的家庭電路系統進行了第一次修改,增加了串聯和并聯類,從只有一條簡單串聯電路更新到了存在多條串聯和并聯電路,并使并聯類關聯到串聯類,并聯多條單獨的串聯類,類間關系更加復雜,電壓的計算更加多變。
(2)設計與分析
`
第四次作業(答題判題程序-4)
??新增多選和填空類,并將所有接收題目信息的方法全部移入Submission類中,類間關系更新為如下


新增多選類
??按題目要求,增加多選類,主要繼承和重寫了題目類的判題方法,具體實現為:
??for循環遍歷所有提交的答案,如果有與題目中某一個正確答案相同的選項,則設標志flag為true,如果遍歷結束flag仍為false則證明所有答案都不符合,函數返回值0,代表所有選項都不匹配,答案錯誤。在遍歷結束后,判斷提交答案的數組長度是否小于正確答案的數組長度,如果為真,則證明提交的答案不全,函數返回2,代表半對。如果為假,則提交答案長度正好符合正確答案長度,且全部正確,即答案完全正確,函數返回1
新增填空類
??按題目要求,增加填空類,主要繼承和重寫了題目類的判題方法,具體實現如下:
public int check(String fillAns)
{
if(fillAns.matches("\\s*"))return 0;//無答案判錯,與測試點無關
if(this.fillAns.matches(".*"+fillAns.trim()+".*"))
{
if(this.fillAns.equals(fillAns.trim()))
{
return 1;
}
return 2;
}
else return 0;
}
如果提交答案存在于正確答案中,則繼續判斷是否完全相同,相同則函數返回1,代表答案完全正確,否則返回2,代表部分正確,再否則則返回0,代表答案錯誤。
第五次作業(家居強電電路模擬程序-1)
本次作業為第一次家庭電路的模擬,是一次全新項目的開始,題目要求模擬計算家庭220V電路下的設備電壓,實現各種電路設備之間的串并聯聯系,可設置控制設備和受控設備兩種設備,使它們都繼承自電路設備類。類間關系設計如下:

Element類
??根據題目要求,設計所有電路設備的父類如下:
abstract class Element implements Comparable<Element>
{
int id;
String inPin;
String outPin;
Boolean inUsed;
Boolean outUsed;
double inVolt;
double outVolt;
public abstract String getInPin();
public abstract String getOutPin();
public abstract Boolean getInUsed();
public abstract Boolean getOutUsed();
public abstract void setInPin(String inPin);
public abstract void setOutPin(String outPin);
public abstract char getType();
}
??類中包含輸入引腳和輸出引腳,儲存另一個電路設備的引腳信息,在之后根據連接信息查找和搜索。并儲存了每個引腳的電壓,以便計算每個電路設備的電壓信息。
??Element類中包含抽象方法getType(),在排序方法compareTo()中調用,可以根據給定的順序排序所有Element的實例,具體實現如下:
public int compareTo(Element o)
{
String order = "KFLRBD";
if(getType()==o.getType())
return id-o.id;
return order.indexOf(getType())-order.indexOf(o.getType());
}
??根據下標索引相減,可以大量減少排序方法的代碼塊,使用父類的抽象方法,能夠極大縮減函數復用帶來的不必要重復。還可以根據給定順序排序,即使順序更改,只需要修改一處便可適應新排序。
??與getType()相似,Element類中還包含toString()方法,子類定義時,便重寫該方法,使得最后輸出時只需要短短一個for循環遍歷輸出,直接使用System.out.println(e);即可輸出。
控制設備
開關#
public void changeState()
{
state ^= 1;
}
??最簡單的控制設備,只有0和1兩種狀態,在切換狀態時可以使用異或運算簡化方法體。
分檔調速器#
??比開關多兩個狀態,設有position代表檔位(0~3),因為檔位連續,可用數組存儲每個檔位的調速數據,設立私有數據域private final double[] gradeTimes = {0,0.3f,0.6f,0.9f};,在每次調速之后,用檔位對應下標,提取數據域中對應檔位的值,更新調速數據。
受控設備
白熾燈#
??根據題目要求,白熾燈的亮度隨電壓差呈線性變化,可求出方程式為L = 50 + (V-10) / 1.4,且電壓超過220和低于0時電壓不再變化,可寫出獲取亮度的方法如下:
public double getLighting()
{
double volt = getAbsVolt();
if(volt<=9)return 0;
else if(volt>=220)return 200;
else return 50 + (volt-10) / 1.4;
}
日光燈#
??根據題意,電壓不為0時亮度恒為180,否則亮度為0。獲取電壓的方法可簡化為一個三目運算符volt == 0 ? 0 : 180
吊扇#
??與白熾燈相似,吊扇的轉速與電壓差呈正比,可寫出獲取轉速的方法如下:
public double getSpeed()
{
double volt = getAbsVolt();
if(volt<80)return 0;
else if(volt>150)return 360;
else return 80 + 4.0 * (volt-80);
}
計算電壓(家庭電路類)
??最初設計時,考慮到題目給出各個引腳的數據,所以我在Element類中儲存了引腳的數據,記錄下了各個引腳通向的另一個引腳,于是在計算電壓的部分也利用了這部分數據,根據引腳的連通情況去進行搜索,每搜索到一個電器的同時去計算它的電壓情況,計算好電壓后,各個電器會在最后輸出階段自動調用已經寫好的方法,計算出需要輸出的數據。
??可是如何去遍歷搜索卻成為了一個難題,在一開始我便想得太復雜了,想著儲存了引腳的數據,就一定要用上,可是越往后做越發現,引腳的數據在這次迭代中根本用不到,其實刪除這部分數據的輸入捕獲,也能夠做到全對,可是考慮到之后可能會用,便仍接著遍歷搜索的思路去寫了。
??在計算電壓之前,先遍歷找出VCC引腳接在了哪個用電器上,并從該用電器作為出發點開始搜索計算。給出VCC所在的引腳和接入的電路設備,如果引腳為1,則將2引腳電壓更新,并將該引腳和與它連接的電路設備加入到隊列q中,然后進行下一次遍歷,反之依然。如果隊列q中沒有電路設備,則循環結束,如此搜索完一遍,便可以將所有引腳的電壓都計算出來,在得到所有引腳的電壓之后,便可以用電壓差計算出每個設備的電壓。由于我寫的太過繁瑣,就不展示出來了。大家可以自己去嘗試寫一下。
第六次作業(家居強電電路模擬程序-2)

Element類
??看到本次題面,我發現引腳還是沒有被用上,于是我一怒之下怒了一下,把引腳直接給刪除了(),Element類被修改為如下:
abstract class Element implements Comparable<Element>
{
int id;
double voltage;
double resistance;//電阻
final double EPS = 1e-10;
final double INF = Double.POSITIVE_INFINITY;//1.78e+308
abstract boolean canGo(Element e);
public void updateVolt(double wholeResistance,double wholeVolt)
{
voltage = resistance * wholeVolt / wholeResistance;
}
public double getVolt()
{
return Math.abs(voltage);
}
public abstract char getType();
@Override
public int compareTo(Element o)
{
String order = "KFLBRDAHS";
if(getType()==o.getType())
return id-o.id;
return order.indexOf(getType())-order.indexOf(o.getType());
}
}
??由于本次迭代考慮了電阻,于是我將電阻的數據直接存放在Element類中,方便直接調用。考慮到電路斷路電阻為無窮大,我又在類中放了一個final類型的數據INF代表無窮大,在電路斷路時方便直接設置,并且該無窮大直接使用Double類中的無窮大,意為真正的無窮大。既然Double類中已經實現好了,自然要偷這個懶。并且類中還存放了另一個final類型的數據EPS,電壓電阻等數據為Double類型,計算時需要考慮精度問題,需要時可方便直接調用。
??在經過幾輪思考之后,Element中還新增了一個canGo的抽象方法,返回該電路設備是否能讓電流通過,對于所有的開關,canGo根據閉合狀態返回是否可通過;對于所有用電器,直接返回true,即使在之后要考慮電壓過大用電器會燒斷,也可以直接在該方法中修改返回值;對于所有串聯電路,只要電路中有一個元件的canGo方法返回了false,便直接返回false。對于并聯電路也同樣可以這樣思考,這便是根據實際情況,使用遞歸運算簡化了代碼的復雜度。
Light類
??抽象出所有燈的父類Light,由于所有燈都有亮度的數據,并且輸出時結構相似,于是在Light類中添加抽象方法getLighting(),并將所有燈的輸出方法放在Light類中,如此一來,便又一次降低了代碼量,增加了方法的復用度。
abstract class Light extends Electric
{
public abstract double getLighting();
@Override
public String toString()
{
return "@"+getType()+id+":"+String.format("%.0f",Math.floor(getLighting()));
}
}
Fan類
??與Light類似,本次添加了一種風扇,風扇種類便從1變為了2,所以可以抽象出Fan類,同樣具有所有風扇類都有的轉速屬性,并且輸出結構類似,于是添加抽象方法getSpeed()和toString()方法
abstract class Fan extends Electric
{
public abstract double getSpeed();
@Override
public String toString()
{
return "@"+getType()+id+":"+String.format("%.0f",Math.floor(getSpeed()));
}
}
(3)采坑心得
??由于考慮了引腳之間的連接,題目被我想得復雜化了,因此修改了很久都不對,太過復雜的連通關系總是把我繞進去,改卻總又改不對,最后還是要簡化,所以在一開始構思的時候不能想得太復雜,一切都要從簡,然后才去慢慢深入修改。
??還有就是一定要通篇檢查代碼,不要自以為某一段沒有問題就不去檢查,因為家庭電路系統-1題面中要求到要對電路設備進行排序,而答案提交之后也順利通過了,所以在第二次迭代中我就沒去檢查這段代碼,以至于一直修改其他地方分數卻保持不變,直到最后才開始懷疑。
(4)改進建議
??在之后的迭代中,我希望能夠引腳的部分重新加回來,但是不需要通過太復雜的代碼或是對代碼整體重新修改,就像是上面說的,不用一開始就想得復雜,而在之后通過打補丁的方式加入功能。也希望之后無論添加什么功能,都能輕易修改好,隨后僅剩一點點的調試。
(5)總結
??抽象是步入java大門的一把利器,不僅在家庭電路模擬中,也能用在各個場景中。面向抽象編程,不需要在一開始就將功能全部設想到,而是利用抽象的特性,一步步具象化,這樣不僅代碼清晰,每一步需要考慮的東西也減少了,將一次不能夠完成的功能分布展開,能夠在讓自己在每一步迭代中清晰的知道自己在這一次要完成什么,也能讓自己寫代碼的效率提高。
??總的來說,這三次題目集又讓我學到了很多,希望之后的迭代不會超出我代碼的可變范圍。希望自己對代碼的掌控更加熟練。
posted on 2024-06-09 17:18 WanLongPing 閱讀(71) 評論(0) 收藏 舉報
浙公網安備 33010602011771號