度量分析的工具真的好難搞!到如今個人metrics也沒法正常使用,能夠建立它的透視圖,可是不能再工程的屬性裏找到它......得,我如今只能展現類關係圖譜(逃)。正則表達式
OO給個人感受就像是雨夜爬山通常,「爬山」本已舉步維艱,大晚上的還漆黑一片,得「邊爬邊摸索」,要是走了面向過程的「歪路」,也不免重頭再來。加之各類條條框框如大雨般傾盆而下,一不當心就弄個「泥濘不堪」,若是不慎落了「無效做業」的大坑,也只能叫苦連天但無力迴天。編程
嗨,這麼一寫還忽然以爲,OO有點意思。數組
第一次做業是要寫多項式的加減,個人程序的大致結構以下:多線程
其中,Main是主類,負責調用其餘的類,並運行程序;框架
Check類是用來檢測輸入的字符串是否合法的,在這裏主要使用了正則表達式來判斷;函數
Operation類是用來實現多項式加減的,主要是一個大循環,一個字符一個字符向後讀。工具
第一次做業的公測錯了兩個點,互測沒出問題,第一個是爆棧,緣由是個人正則表達式就是一個長串來匹配整個的輸入,致使在最大長度的輸入狀況下程序出了問題。把輸入的幾十個多項式按花括號拆開,再進行正則匹配便可解決。測試
第二個點是沒有考慮-0仍是什麼關於正負號的一個小點,後來仔細閱讀指導書後,大呼之遂心服口服,這很好的提醒了我在之後的做業中要仔細考慮各類狀況以及仔細閱讀指導書,勤于思考各類非法的狀況。spa
個人第一次做業的代碼量比較少,可能勉強算是一個有點,但第一次寫面向對象的程序,老是有些四不像的感受,不會使用構造函數,把全部的功能都放在了類的方法中,形似面向過程。線程
第二次做業是寫一個服從「傻瓜調度」的電梯,即根據指令的時間順序來控制電梯的運動,個人程序的大致結構以下:
其中,Request類是用來處理單條需求的,經過正則表達式判斷指令是否合法,進而判斷指令是哪一種類型(FR+UP,FR+DOWN,ER),而後將指令分解,分別去判斷時間和樓層是否越界。由於考慮到時間可能超過int型的範圍而且會有不少的前導零,我用了一個循環來算時間...
for(int i=0; i<s.length; i++ ) { if(s[i]!= '+') { NowTime *= 10; NowTime += (s[i] - '0'); } }
Queue類是用來循環讀入指令的,調用了Request類,對單條指令進行處理,並把它們分別存在對應的數組中。
Elevator類是用來記錄電梯的運行狀態的,包括電梯如今所處的樓層,下一個樓層,當前時間,下一個時間,電梯運行時間,運行狀態等。
Floor類是用來記錄樓層信息的,但其實實際操做中我幾乎沒用到它,由於Elevator類裏的東西就夠用了。
Scheduler類是用來執行電梯調度的,實例化了Queue類的對象來讀入指令,也實例化了Elevator類的對象來記錄電梯的運行狀態,並設置了一些其餘的屬性來模擬電梯的運行。
private double[] ERButton = new double[20]; private double[] FRUPButton = new double[20]; private double[] FRDOWNButton = new double[20];
上面三個按鈕數組用來模擬電梯裏面和樓層上的按鈕。開始時我想用boolean型的數組,可是發現那樣只能記錄按鈕的狀態,不能記錄按鈕狀態改變的時間,因此我後來改用double型,記錄每一個按鈕被釋放的時間,即這個按鈕在哪個時刻能夠被再次使用,在這個時刻以前,若是有人發出了須要這個按鈕的指令,則被視爲同質指令。
if(queue.RequestTypeArray[valid] == 1) { if(queue.TimeArray[valid] <= FRUPButton[queue.FloorArray[valid]]) { System.out.println("#This input is similar:"+(queue.InputArray[i])); IfSimilar = true; } }
拿一段代碼來講明,好比一條指令的類型爲1(FR+UP),那麼比較讀入指令的發出時刻與該指令的對應按鈕的釋放時間,就能夠判斷這條指令是否是同質(在這以前先判斷是否合法)。這樣就不須要預先知道後面的指令是什麼,簡化了代碼的複雜度。
若是它不一樣質,那麼就能夠產生一個對應的輸出,並改變某個按鈕的釋放時間,部分代碼以下:
if(queue.RequestTypeArray[valid] == 1) { FRUPButton[queue.FloorArray[valid]] = elevator.NextTime; }
好比這條指令的類型是1,那麼就將FRButton中對應按鈕的時間設置爲elevator.NextTime(即通過計算後的電梯達到下一個樓層的時間),這樣就可讓程序不斷的循環運做了~
第二次做業的公測我沒有錯測試點,互測錯了一個,是:輸出若是超過了int範圍而且是小數,那麼個人輸出就會把它的小數部分給省略掉,後來我尋找緣由,發如今這個地方:
System.out.print(BigDecimal.valueOf(elevator.NextTime));
我爲了使輸出不是科學記數法的形式,我用了BigDecimal,但不知爲啥這裏會出這樣的幺蛾子......
第二次做業我花了好久的時間去思考,主要在想如何去判斷各類同質的情況,後來通過不斷的摸索,而且有意識地去模擬真實電梯的屬性和方法(在我理解裏的面向對象吧),我選擇用按鈕這個概念來記錄電梯的被觸發不一樣狀態後的終止時刻,想明白了這個以後再去寫代碼就順暢了許多。有了此次的經驗,我在寫第三次做業以前花了更多的時間去思考。
第三次做業的電梯是在第二次做業的基礎上考慮「捎帶」這一規則,我本覺得只須要小改一下就成,後來在實際操做中我才發現本身錯的離譜......先展現一下程序的大致結構:
其中,除了SubScheduler類之外,其餘幾個類與第二次做業基本相同,不贅述;
SubScheduler是繼承了Scheduler父類的子類,說來慚愧,我此次做業幾乎只幹了一件事兒:重寫了Scheduler父類的Run函數......
由於電梯要捎帶,那麼電梯的運行就不能只是發生在相鄰的兩條指令之間了,由於後面的指令或者時刻靠後的指令徹底有可能要先執行,判斷哪些指令要先執行就是最大的難點所在。我先很天然地想到咱們使用的電梯是什麼樣的,在運動到某一樓層前,若是接收到這個樓層發出的信號,若是方向相同即可以停靠,那麼關鍵點有兩個,一個是位置,一個是時間。我最初想到的是以時間爲主線,直接以0.5s爲最小的度量,每過0.5秒記錄電梯的位置和運行狀態,而後去隊列中搜索有沒有這個時刻或以前發出的同層的指令,後來由於各類考慮放棄之。
因而便選擇了先遍歷一下讀入指令後面的指令,若是這條指令知足可捎帶的條件,執行之,而後把它從請求隊列中剔除,並改變一些按鈕被釋放的時間以及樓層、到達時刻等屬性,其中一部分大概像下面這樣:
else if(elevator.Condition.equals("UP")) { if(queue.RequestTypeArray[j] == 1) { if((queue.FloorArray[j] <= MaxFloor) && (queue.FloorArray[j] > elevator.NowFloor)) { ExtraTime = (queue.FloorArray[j] - elevator.NowFloor)*0.5; for(int k=(elevator.NowFloor); k<(queue.FloorArray[j]); k++) { ExtraTime += ExtraFloorArray[k]; } if(queue.TimeArray[j] < (elevator.NowTime + ExtraTime)) { if(queue.TimeArray[j] <= FRUPButton[queue.FloorArray[j]] ) { //同質 UsedArray[j] = true; System.out.println("#SAME["+(queue.ValidArray[j])+"]"); } else { FRUPButton[queue.FloorArray[j]] = (elevator.NowTime + ExtraTime); ExtraFloorArray[queue.FloorArray[j]] = 1.0; //加入捎帶的額外數組 UsedArray[j] = true; ExtraConditionArray[queue.FloorArray[j]] = "UP"; ExtraOrderArray[queue.FloorArray[j]][ExtraSameNumberArray[queue.FloorArray[j]]] = j; ExtraSameNumberArray[queue.FloorArray[j]]++; } } } }
很繁瑣,分了電梯運行的各類狀態以及指令的各類類型來分類討論,這裏把主指令以後的指令存入一個新的數組中,而不是直接輸出,由於它後面還可能有比它還要提早執行的指令,因此輸出也變得很繁瑣了......
if(elevator.Condition.equals("UP")) { for(int m=elevator.NowFloor; m<=MaxFloor; m++) { if(ExtraFloorArray[m] == 1.0) { for(int n=0; n<ExtraSameNumberArray[m]; n++) { if(queue.RequestTypeArray[ExtraOrderArray[m][n]] == 1) { System.out.print("[FR,"); System.out.print(queue.FloorArray[ExtraOrderArray[m][n]]); System.out.print(",UP,"); System.out.print(queue.TimeArray[ExtraOrderArray[m][n]]); System.out.print("]/("); System.out.print(m); System.out.print(","); System.out.print(ExtraConditionArray[m]); System.out.print(","); System.out.print(BigDecimal.valueOf(RunTime)); System.out.println(")"); }
我在主請求結束後進行這個輸出的循環,大致思路是上面的程序段記錄了每一個樓層的停靠狀態,以後遍歷樓層,把有標記的樓層按要求輸出。這是一種以位置爲主軸的方法吧。由於一層樓中可能會開若干次門,因此只能創建一個二維數組ExtraOrderArray來記錄某層樓的可能出現的若干次開門的請求。
很幸運,第三次做業的公測和互測都沒有出BUG,能夠說是很振奮人心了。但想到以後要寫多線程的電梯,感受程序不免仍是要修改,仍是很使人頭大。
此次做業雖然重點只是放在了重寫Run函數上,但週六日兩天剛好有事情不能寫OO,結果致使個人週一二三過的至關艱難,通宵數宿,苦不堪言,不堪回首,觸目驚心......想不想得清楚是一方面,更重要的是一些小的細節的改動會牽一髮而動全身,原本想要微調結果不得不大刀闊斧的改一通,其中折磨可想而知。這也讓我吸收到了很寶貴的經驗:1、拖延症害死人,能早點解決的事兒別把它養肥了;2、磨刀不誤砍柴工,在頭腦清醒時先把問題想清楚,方法想完善,必要時能夠手寫一下流程框架圖什麼的,這樣說不定就能事半功倍。
總的來講,OO仍是讓人收穫頗豐的,別的不說,就是之後得去「搬磚」,基本的編程能力仍是要有的,毋庸置疑,OO鍛鍊了個人編程能力;其次,在思考和對問題的分析上,我能夠有意識地用面向對象的思路去思考問題(或許我還並不能正確認識什麼是面向對象),這是一種有趣的思考過程,我總感受這樣幻想出來的對象還有點可愛......
最後祝你們永不被判無效做業!實在太痛了,也但願之後的OO能升級一下無效做業的判斷機制吧。