OO第二單元總結(jié)
摘要
第二單元相對(duì)于第一單元,在思路構(gòu)建和過(guò)程模擬的難度上有了較大的提升,因?yàn)?strong>多線程本身的不確定性和bug的隨機(jī)復(fù)現(xiàn)性,所以需要我們構(gòu)建出良好的架構(gòu)以及我們要對(duì)自己的代碼運(yùn)行過(guò)程有著極為清晰的認(rèn)識(shí)。然而,相對(duì)于第一單元,在面向?qū)ο蟮乃悸飞想y度稍微好了一些,主要原因是隨著課程的深入,對(duì)面向?qū)ο蟮睦斫庖哺由羁?,除此之外,電梯相?duì)于表達(dá)式,是一個(gè)更加貼近生活的對(duì)象(我甚至在公寓電梯里一直不出去企圖分析電梯的運(yùn)行過(guò)程),化簡(jiǎn)表達(dá)式時(shí)要對(duì)各種結(jié)構(gòu)進(jìn)行拆分建模,而分析電梯的運(yùn)行過(guò)程時(shí),其在我們腦海中構(gòu)建的時(shí)候本來(lái)就是以對(duì)象的形式存在的,比如說(shuō)電梯、乘客(請(qǐng)求)、樓座樓層、請(qǐng)求隊(duì)列等等,我們?cè)谧x題的過(guò)程中盡管不一定有非常清晰的敲代碼思路,但是該建什么類,類中該有什么屬性是比較容易想出來(lái)的。
第五次作業(yè)(無(wú)中生有)
1.架構(gòu)與多線程分析
由0邁到1的這一步是異常艱難的(也正因如此對(duì)第五次作業(yè)的分析會(huì)多一些),由于之前對(duì)多線程根本不了解,看完相關(guān)基礎(chǔ)知識(shí)后瀏覽指導(dǎo)書發(fā)現(xiàn)真的很難:既要考慮架構(gòu),也要考慮可迭代性,又要考慮線程安全問(wèn)題。當(dāng)然,分析完第五次作業(yè)指導(dǎo)書后,會(huì)發(fā)現(xiàn)本次作業(yè)不太需要考慮線程安全問(wèn)題,因?yàn)?臺(tái)電梯本身是互不干擾的,每個(gè)請(qǐng)求應(yīng)該去哪個(gè)電梯哪個(gè)位置等待也都是固定的。換句話說(shuō),當(dāng)輸入線程讀到一個(gè)指令的時(shí)候,我們可以直接把指令放到確定的位置,不用顧及任何事情,類比到現(xiàn)實(shí)的話,那就是你想從新主樓F的2樓到3樓,那你就直接去F的2樓的電梯門口等著就好了,沒(méi)有什么需要考慮的。
至于調(diào)度算法,再看完指導(dǎo)書中的ALS基準(zhǔn)策略后,感覺(jué)ALS好像實(shí)現(xiàn)起來(lái)有點(diǎn)復(fù)雜,過(guò)程也沒(méi)太弄清楚,而且對(duì)于很多情況運(yùn)行時(shí)間都不會(huì)太好,再請(qǐng)教了同學(xué)和瀏覽了學(xué)長(zhǎng)的博客后,發(fā)現(xiàn)look算法比較好,而且更好理解、更好實(shí)現(xiàn)、性能也很不錯(cuò)。我在網(wǎng)上并沒(méi)有查到特別詳細(xì)的look算法,根據(jù)各種各樣的信息,我實(shí)現(xiàn)的look算法如下:電梯有一個(gè)初始方向(一般定為上),電梯每到一個(gè)樓層對(duì)電梯內(nèi)部和外部的乘客進(jìn)行分析,如果到達(dá)了內(nèi)部乘客的目的樓層,該乘客出去,如果外部乘客的方向(上樓或下樓)跟電梯一樣,那么電梯就讓他進(jìn)來(lái)(這里省略的開(kāi)關(guān)門的分析過(guò)程以及電梯容量問(wèn)題)。當(dāng)電梯內(nèi)部沒(méi)有人,并且電梯同方向上的其他樓層也都沒(méi)有乘客叫電梯,那么電梯反向。這個(gè)算法的一個(gè)特點(diǎn)就是,電梯不存在主請(qǐng)求,只是不斷的上下樓,符合條件就讓進(jìn)出,實(shí)現(xiàn)起來(lái)比較容易,捎帶策略和轉(zhuǎn)向策略也使得這個(gè)算法在性能上比ALS也好了很多,當(dāng)然在討論課上也發(fā)現(xiàn)了其他同學(xué)的一些優(yōu)化方法,例如目的地和起始地距離近的乘客優(yōu)先進(jìn)入,這樣可以減少電梯來(lái)回一次的時(shí)間。
綜上,本次作業(yè)我主要采用了輸入線程類InputThread,電梯類Elevator,請(qǐng)求表類RequestTable,策略類Strategy。至于為什么沒(méi)有乘客類Person,這其實(shí)是我比較矛盾的一個(gè)地方,官方給的PersonRequest所包含的全部信息基本上就是我乘客的屬性了,我就沒(méi)有再建造一個(gè)Person類來(lái)去復(fù)制PersonRequest的屬性,直接把指令當(dāng)成人看,這里確實(shí)不太符合現(xiàn)實(shí)。除此之外,我并沒(méi)有構(gòu)建一個(gè)調(diào)度器負(fù)責(zé)安排指令位置,因?yàn)檎缟厦嫠f(shuō),指令具體去哪個(gè)電梯直接就能知道,因此我直接在輸入線程內(nèi)將指令傳給了請(qǐng)求表RequestTable,而請(qǐng)求表類本質(zhì)上就是一個(gè)三維乘客數(shù)組(這是個(gè)抽象說(shuō)法),根據(jù)樓座和樓層,我就可以直接找到該位置的請(qǐng)求隊(duì)列,因此,對(duì)于第五次作業(yè)來(lái)說(shuō),調(diào)度器確實(shí)是沒(méi)什么用的,不過(guò)也得留一個(gè)心眼兒,對(duì)于以后的迭代肯定是需要調(diào)度器的。
策略類Strategy里面實(shí)現(xiàn)了我的look算法,至于策略類的存在意義是什么,我認(rèn)為是為了以后的迭代考慮,策略類可以為我的電梯提供這種各樣的策略接口,這樣電梯就可以擁有不同的調(diào)度。
至于線程通信,wait-notify機(jī)制固然不錯(cuò),但是我認(rèn)為有一個(gè)相對(duì)不符合現(xiàn)實(shí)的地方就是,如果來(lái)了乘客,理論上我們只需要喚醒該乘客所乘坐的電梯即可,而不是用notifyAll去喚醒所有電梯再讓剩余的電梯發(fā)現(xiàn)沒(méi)乘客然后接著睡。于是我在網(wǎng)上查到了一個(gè)LockSupport工具類,其中調(diào)用LockSupport.park()直接就可以在該位置進(jìn)行暫停(wait),而LockSupport.unpark(Thread)(括號(hào)內(nèi)是你要喚醒的線程,也就是某個(gè)電梯)可以喚醒該線程。除此之外,這兩個(gè)方法不用像wait和notifyAll封裝在sychronized里,也不用考慮先后順序問(wèn)題,使用起來(lái)非常直觀且可靠。wait-notify機(jī)制對(duì)于我們對(duì)多線程的理解更加深入,而LockSupport工具類對(duì)于對(duì)多線程不熟悉的人來(lái)說(shuō)用起來(lái)更加方便,當(dāng)然只是個(gè)人想法。
2.代碼分析
UML類圖如下:
UML協(xié)作圖(三個(gè)線程視角)如下:
Statistic分析如下:
Metrics分析如下:
根據(jù)上述分析結(jié)果,我們可以發(fā)現(xiàn):首先,在架構(gòu)設(shè)計(jì)方面,利用輸入線程來(lái)獲取指令,將指令送往指定隊(duì)列然后喚醒指定電梯,電梯喚醒后調(diào)用自身的策略類,策略類來(lái)進(jìn)行調(diào)整電梯和乘客的狀態(tài)。因此,我將look算法全部在Strategy類中實(shí)現(xiàn)的,因此Strategy的復(fù)雜度也確實(shí)高了一些,其實(shí)根據(jù)指導(dǎo)書,策略類理論上只是負(fù)責(zé)提供主請(qǐng)求,真正的上下樓和開(kāi)關(guān)門應(yīng)該是電梯自身干的事情,但是由于我在實(shí)現(xiàn)look算法的過(guò)程中沒(méi)有用到主請(qǐng)求這一對(duì)象,因此這里的設(shè)計(jì)確實(shí)復(fù)雜了一些,也確實(shí)有悖面向?qū)ο蟮乃枷搿?/p>
在線程交互方面,其實(shí)只有輸入線程喚醒電梯線程這一個(gè)稍微復(fù)雜的地方,再一個(gè)就是電梯線程的停止條件需要包含輸入線程是否結(jié)束。實(shí)際上第五次作業(yè)基本上不存在線程競(jìng)爭(zhēng),需要加鎖保證線程同步的地方有兩處,一個(gè)是官方提供的輸出類,一個(gè)是請(qǐng)求隊(duì)列的add和remove,因?yàn)槲业恼?qǐng)求隊(duì)列是一個(gè)ArrayList,因此需要加鎖保證其add和remove能夠線程同步,其他地方確實(shí)不需要考慮。
直觀分析代碼本身,發(fā)現(xiàn)Strategy的look算法實(shí)現(xiàn)的非常復(fù)雜,我為了能夠保證方法行數(shù)不超過(guò)60,強(qiáng)行在一些地方進(jìn)行了封裝,因此這里的實(shí)現(xiàn)相當(dāng)?shù)牟粌?yōu)雅。
對(duì)于該架構(gòu)的優(yōu)點(diǎn):由于電梯之間比較獨(dú)立,大體上整個(gè)電梯運(yùn)行的過(guò)程還算是比較清晰,而且策略類的構(gòu)建有利于后面作業(yè)的擴(kuò)展,因?yàn)椴煌碾娞菘赡苄枰紤]不同的策略。
該架構(gòu)的缺點(diǎn):靈活性還是不夠,無(wú)法適應(yīng)其他種類的電梯,由于采用的是靜態(tài)調(diào)度,對(duì)后期作業(yè)可能存在的動(dòng)態(tài)分配請(qǐng)求并沒(méi)有良好的適應(yīng)性,而且多個(gè)方法的實(shí)現(xiàn)都非常的復(fù)雜冗長(zhǎng),debug不方便且不優(yōu)雅。
第六次作業(yè)(多多益善)
1.架構(gòu)、調(diào)度器與多線程分析
第六次作業(yè)在第五次作業(yè)的基礎(chǔ)上,架構(gòu)方面有了一定的改動(dòng)。根據(jù)指導(dǎo)書,我們?cè)黾恿藱M向循環(huán)電梯,原先的樓層變成了橫向電梯的樓座,原先的樓座變成了橫向電梯的樓層,而且沒(méi)有最高處和最低處之分,除此之外,對(duì)于橫向請(qǐng)求,只有相對(duì)方向,沒(méi)有絕對(duì)方向,因?yàn)殡娞葜灰3忠粋€(gè)方向走,總會(huì)到達(dá)該請(qǐng)求的目的地。經(jīng)過(guò)分析,由于橫向電梯和縱向電梯擁有很多相同的屬性,我打算把這兩種電梯解離成縱向電梯(VerElevator)和橫向電梯(HorElevator),同時(shí)繼承一個(gè)主電梯類(Elevator),除了基本的屬性,兩種電梯的區(qū)別主要在于策略的不同,因此,Strategy里除了包含第一次實(shí)現(xiàn)的縱向look算法,又添加了橫向look算法(所以復(fù)雜度又增加了......)。除此之外,對(duì)于電梯的屬性(樓座,ID,樓層,內(nèi)部乘客等),我又添加了一個(gè)二維請(qǐng)求數(shù)組<樓層,請(qǐng)求隊(duì)列>。其實(shí)根據(jù)實(shí)際,乘客/請(qǐng)求可以說(shuō)是和電梯是分開(kāi)的,他們更像是樓的屬性,然而之所以我將10層樓的請(qǐng)求隊(duì)列放入電梯內(nèi)部,是因?yàn)槲?strong>忽略了樓的這個(gè)概念,電梯則是一個(gè)架空的對(duì)象,每個(gè)電梯有10個(gè)隊(duì)列,進(jìn)入電梯等同于外部隊(duì)列remove,內(nèi)部隊(duì)列add,乘客出電梯等同于內(nèi)部隊(duì)列remove,而與這五棟樓沒(méi)什么關(guān)系了。
此次作業(yè)還增加了添加電梯功能,因此,我這次構(gòu)建了一個(gè)調(diào)度類(Schedule),該類的作用是兩個(gè),一個(gè)是獲取增加電梯的請(qǐng)求向電梯容器中添加新電梯,另一個(gè)是獲取乘客的請(qǐng)求將其分配到指定電梯。因此調(diào)度類里擁有我目前所擁有的所有電梯。而由于我每一部電梯都擁有屬于自己的請(qǐng)求集合,我采用基準(zhǔn)策略來(lái)將指令送往電梯。由于電梯個(gè)數(shù)的增多,其實(shí)理論上采用自由競(jìng)爭(zhēng)的分配策略會(huì)更好一些,然而由于我不想對(duì)已有的架構(gòu)進(jìn)行大的調(diào)整,并且我想保證線程的安全性,因此,采用基準(zhǔn)策略來(lái)平均分?jǐn)傠娞?/strong>,不過(guò),依照我的理解,我并沒(méi)有按照指導(dǎo)書中說(shuō)的那樣進(jìn)行分配,而是選擇目前內(nèi)外乘客數(shù)量最少的電梯優(yōu)先分配。我用了一個(gè)比較樸素的思想就是,越忙的電梯盡量就別給他增添請(qǐng)求了,把請(qǐng)求給一些比較閑的電梯能節(jié)省一點(diǎn)時(shí)間,盡管沒(méi)有理論上驗(yàn)證是否合理,不過(guò)感覺(jué)和基準(zhǔn)策略差不太多。與此同時(shí),幾臺(tái)電梯同時(shí)去搶奪一個(gè)請(qǐng)求隊(duì)列的情況就不存在,換句話說(shuō)我直接就是多了10臺(tái)電梯,然后無(wú)論怎么添加,各個(gè)電梯之間依然是相互獨(dú)立的。
2.代碼分析
UML類圖如下:
UML協(xié)作圖如下:
Statistic分析如下:
Metrics分析如下:
線程角度:由于我本著求穩(wěn)的心態(tài),在線程通信這方面基本上和第一次作業(yè)一樣,換句話說(shuō)盡管電梯增加了,每個(gè)請(qǐng)求去哪個(gè)電梯依然是固定的,該用sychronized封裝的地方和上次也沒(méi)什么區(qū)別。
架構(gòu)角度:多了調(diào)度類,電梯也存在了繼承關(guān)系,但是由于我所實(shí)現(xiàn)的調(diào)度本身就是一個(gè)靜態(tài)的過(guò)程,而且兩種電梯除了look算法有差別外在第六次作業(yè)中基本也沒(méi)什么區(qū)別,因此主要的工作量依然是Strategy類中對(duì)于兩種look算法的實(shí)現(xiàn)。這里我也確實(shí)是繼承了我第一次作業(yè)的缺點(diǎn),Strategy類不僅沒(méi)有減輕負(fù)擔(dān)反而還來(lái)了個(gè)加倍的工作量。其實(shí)這里應(yīng)該對(duì)策略類和電梯類的交互進(jìn)行一下重構(gòu),但是由于本人的懶惰就沒(méi)有進(jìn)行。
該架構(gòu)的優(yōu)點(diǎn):對(duì)橫縱向電梯的分離有利于后期的迭代,每個(gè)電梯對(duì)應(yīng)各自的請(qǐng)求隊(duì)列從而擁有良好的線程安全性。
該架構(gòu)的缺點(diǎn):完全采用基準(zhǔn)策略靜態(tài)分配,導(dǎo)致性能與使用自由競(jìng)爭(zhēng)/其他優(yōu)化方案的架構(gòu)相比確實(shí)差了一些,其他缺點(diǎn)跟第一次一樣。
第七次作業(yè)(動(dòng)靜結(jié)合)
1.架構(gòu)、調(diào)度器與多線程分析
到了第二單元的最后一次作業(yè),我的目的也變得很簡(jiǎn)單了,因?yàn)闊o(wú)需考慮后期的迭代了(可以為所欲為了哈),因此唯一的目的就是正確性(捎帶著性能)。第七次作業(yè)可能都會(huì)猜到會(huì)有不同樓座不同樓層的請(qǐng)求了,這就涉及到了中轉(zhuǎn)的過(guò)程了,我前兩次作業(yè)犧牲了一部分性能就是為了盡量保證線程的安全性,這次無(wú)論如何都不能偷懶了,因?yàn)殡娞菥€程之間是一定會(huì)有交互的。
相對(duì)于第六次作業(yè),第七次作業(yè)主要加入了如下新功能:電梯的屬性增加了,容量和爬樓時(shí)間由常數(shù)變成了可以改變的屬性,除此之外,橫向電梯多了一個(gè)屬性就是開(kāi)關(guān)門信息,利用一個(gè)1~31的數(shù)字,將其二進(jìn)制的每一位和A~E樓座對(duì)應(yīng),代表著在某些樓座橫向電梯無(wú)法開(kāi)門。不過(guò)這些其實(shí)都是可以用正常的方法就可以解決的,最關(guān)鍵的就是這次作業(yè)來(lái)了較為隨意的請(qǐng)求,這里就需要對(duì)該類請(qǐng)求做出特別的分析。其實(shí),閱讀指導(dǎo)書可以發(fā)現(xiàn),只要是不同樓座的請(qǐng)求,都可能會(huì)發(fā)生中轉(zhuǎn)過(guò)程。因此我構(gòu)建了一個(gè)SpecialRequest類,繼承官方提供的PersonRequest類,對(duì)于讀到的fromBuilding和toBuilding不同的請(qǐng)求,都轉(zhuǎn)化成SpecialRequest類型供調(diào)度器安排,而且SpecialRequest類中還多了一個(gè)屬性就是中轉(zhuǎn)樓層。
這樣整體架構(gòu)就出來(lái)了,比第六次多了一個(gè)SpecialRequest類。至于調(diào)度器的變化,這里確實(shí)是第七次作業(yè)最關(guān)鍵的地方:調(diào)度器在讀到PersonRequest的時(shí)候,如果發(fā)現(xiàn)這個(gè)請(qǐng)求的起始和目的樓座不同,那么就會(huì)重新new一個(gè)SpecialRequest對(duì)象,復(fù)制過(guò)來(lái)PersonRequest的所有屬性,同時(shí)計(jì)算需要中轉(zhuǎn)的樓層,根據(jù)目前所有樓層的電梯,在既存在橫向電梯且開(kāi)關(guān)門信息符合該請(qǐng)求的樓層中選擇距離起始樓層和目的樓層之和最小的,找到中轉(zhuǎn)樓層后電梯在分析請(qǐng)求的目的樓層時(shí),對(duì)于SpecialRequest的目的樓層就不是toFloor,而是transferFloor了。
對(duì)于多種電梯的選擇,我依然采用基準(zhǔn)策略,但是在這基礎(chǔ)上根據(jù)自己的理解進(jìn)行了優(yōu)化:在選擇電梯的時(shí)候,速度快容量大的電梯優(yōu)先選擇。采用這樣的策略在請(qǐng)求比較少的時(shí)候和自由競(jìng)爭(zhēng)的性能差不多,但是在請(qǐng)求比較多的時(shí)候性能如何確實(shí)不太好說(shuō)了。
如何實(shí)現(xiàn)整個(gè)中轉(zhuǎn)過(guò)程呢?這里我采用了動(dòng)靜結(jié)合的方式。調(diào)度器本來(lái)只是輸入線程的屬性,但是由于從電梯中出來(lái)的請(qǐng)求可能是中轉(zhuǎn)的請(qǐng)求,因此該請(qǐng)求還需要重新分配電梯,因此需要給策略類也配備一個(gè)調(diào)度器,所以當(dāng)中轉(zhuǎn)的乘客出電梯時(shí)候,策略類里會(huì)分析出該乘客目前的起始地和目的地,重新將一個(gè)新的PersonRequest扔進(jìn)調(diào)度器內(nèi),這樣就做到了靜態(tài)分配電梯,動(dòng)態(tài)調(diào)度中轉(zhuǎn)請(qǐng)求。
在多線程角度看,調(diào)度器的功能之一就是根據(jù)讀進(jìn)來(lái)的請(qǐng)求分配電梯,由于調(diào)度器封裝進(jìn)了策略類內(nèi)部,因此策略類的工作并沒(méi)有變得特別繁重,而且電梯與電梯之間采用調(diào)度器進(jìn)行溝通連接,線程安全方面也還算可以。但是由于中轉(zhuǎn)請(qǐng)求的特點(diǎn),電梯線程的結(jié)束條件需要多考慮一下,前兩次作業(yè)電梯線程的結(jié)束條件是輸入線程結(jié)束且本電梯的所有請(qǐng)求處理完畢,可中轉(zhuǎn)請(qǐng)求的特點(diǎn)就是目前用不上的電梯過(guò)一段時(shí)間后可能會(huì)使用,因此電梯線程結(jié)束條件就改成了輸入線程結(jié)束且全部電梯的所有請(qǐng)求處理完畢。這樣就又導(dǎo)致了一個(gè)問(wèn)題,不能光在輸入線程結(jié)束后喚醒所有空閑的線程,在電梯線程結(jié)束后也要喚醒全部線程,否則輸入線程提前結(jié)束,請(qǐng)求還沒(méi)有處理完,會(huì)出現(xiàn)先喚醒再沉睡的錯(cuò)誤(當(dāng)然這里的問(wèn)題因代碼而異)。
2.代碼分析
UML類圖如下:
UML協(xié)作圖如下:
Statistics分析如下:
Metrics分析如下:
根據(jù)上圖可以看出,可拓展性幾乎沒(méi)有了,因此多個(gè)類的復(fù)雜度很高,而Strategy和Schedule兩個(gè)類正是整個(gè)電梯調(diào)度過(guò)程的核心類,復(fù)雜度過(guò)高對(duì)debug和bug的修復(fù)確實(shí)會(huì)有很大影響。
該架構(gòu)的好處:線程安全性高,動(dòng)靜結(jié)合的中轉(zhuǎn)過(guò)程使得其既有基準(zhǔn)策略的線程安全,又在性能上有了一定的優(yōu)化。
該架構(gòu)的缺點(diǎn):真的不能再迭代了,再來(lái)其他電梯或策略是真的寫不下去了;在性能上不太穩(wěn)定,相比于自由競(jìng)爭(zhēng)會(huì)差一些。
同步塊和鎖的分析
由于本人三次作業(yè)都在盡量避免線程沖突,優(yōu)化方案也都盡量在靜態(tài)過(guò)程中進(jìn)行,因此在同步塊和鎖的這方面確實(shí)思考的不夠多。
首先就是輸出類,官方包提供的輸出類是線程不安全的,而且TimableOutput相當(dāng)于一個(gè)全局變量,如果有多個(gè)位置同時(shí)調(diào)用它的println方法的時(shí)候會(huì)發(fā)生一些奇怪的事情導(dǎo)致時(shí)間戳不遞增。
因此,根據(jù)其他同學(xué)的想法,利用synchronized將TimableOutput.println封裝成同步方法。
其次還需要考慮的地方就是ArrayList本身是線程不安全的,所以如果兩個(gè)地方同時(shí)對(duì)ArrayList進(jìn)行增刪操作的時(shí)候可能會(huì)發(fā)生異常,因此,前兩次作業(yè)僅僅是用synchronized鎖住了特定的數(shù)組,這樣可以避免該數(shù)組同時(shí)remove和add。等到了第七次作業(yè),我采用了利用Collections.synchronizedList方法使數(shù)組變成線程安全的(代碼如下),因?yàn)橛捎谝恍﹥?yōu)化方法,需要對(duì)數(shù)組內(nèi)部的元素進(jìn)行排序,然而同時(shí)數(shù)組也可能會(huì)增刪元素,因此我直接利用該方法讓ArrayList變成線程安全的可以免除后顧之憂,但是性能可能會(huì)略有下降。
點(diǎn)擊查看代碼
for (int i = 0; i < 10; i++) {
Elevators[i] = new ArrayList<>();
Collections.synchronizedList(Elevators[i]);
}
互測(cè)/自測(cè)的策略+bug分析
跟第一單元相比,第二單元的輸入如果手動(dòng)構(gòu)造會(huì)很麻煩,但是格式非常固定,由于我還不會(huì)什么高級(jí)語(yǔ)言,所以拿C隨便生成了一些數(shù)據(jù)。比如說(shuō)第五次作業(yè),只要按照指導(dǎo)書限定好每個(gè)數(shù)據(jù)(時(shí)間,樓層,樓座,ID)的范圍,就能夠生成很多請(qǐng)求;第六、七次作業(yè)只需要添加一些可以生成增加電梯的隨機(jī)輸出,再豐富一些細(xì)節(jié)就可以了。不過(guò)我不會(huì)寫評(píng)測(cè)機(jī)來(lái)驗(yàn)證我的代碼的正確性,所以在生成數(shù)據(jù)的時(shí)候,一般只生成五六行,然后通過(guò)肉眼來(lái)觀察過(guò)程的正確性。最后生成50-100行的數(shù)據(jù)來(lái)觀察代碼是否會(huì)出現(xiàn)TLE或者RA等錯(cuò)誤。如果產(chǎn)生了TLE這樣的錯(cuò)誤,我一般會(huì)刪減一些代碼,盡量將錯(cuò)誤鎖定在幾個(gè)特定輸入上,然后就開(kāi)始捋自己的代碼執(zhí)行過(guò)程,這個(gè)過(guò)程確實(shí)是低效的,但對(duì)我來(lái)說(shuō)是不得不做的。至于判斷是CTLE是RTLE,由于本人不會(huì)寫評(píng)測(cè)機(jī),因此確實(shí)不容易確定,只能通過(guò)IDEA的debug功能和在各個(gè)位置進(jìn)行print來(lái)判斷線程是否結(jié)束,哪里陷入死循環(huán)等等。至于bug時(shí)而出現(xiàn)時(shí)而不出現(xiàn)的問(wèn)題,我也只能多做嘗試,盡量保存每次出現(xiàn)bug的輸入輸出,沒(méi)有什么巧妙的辦法。
互測(cè)的時(shí)候,我是利用自動(dòng)生成數(shù)據(jù)+構(gòu)造刁鉆數(shù)據(jù)的方法,自動(dòng)生成數(shù)據(jù)一般比較隨機(jī),刁鉆數(shù)據(jù)一般是如下幾種:某種相同請(qǐng)求在同一時(shí)刻大量出現(xiàn)、同一座(層)樓有各種方向的請(qǐng)求、每層樓都有大量請(qǐng)求等等。由于不像第一單元利用肉眼就能看出對(duì)錯(cuò),況且本地輸出和評(píng)測(cè)機(jī)輸出很有可能不一致,所以這幾次互測(cè)我把每個(gè)數(shù)據(jù)都直接交到評(píng)測(cè)機(jī)上了。
對(duì)于產(chǎn)生的bug,主要是輸出類線程不安全的問(wèn)題,也是因?yàn)閷懲甑谖宕巫鳂I(yè)后,清明節(jié)假期期間沒(méi)太思考,既沒(méi)看討論區(qū)也沒(méi)看水群,所以這里的問(wèn)題給忽略了。
心得體會(huì)和反思
兩個(gè)單元的學(xué)習(xí)確實(shí)感覺(jué)收獲了很多。對(duì)于面向?qū)ο蟮睦斫飧由钊?,面向?qū)ο蟮挠⑽氖荗bject-Oriented,根據(jù)我的理解,Object其實(shí)說(shuō)白了就是東西,對(duì)于程序員來(lái)說(shuō),在用代碼描繪某件抽象的過(guò)程時(shí),我們需要從中構(gòu)建出實(shí)體出來(lái),換句話說(shuō)要對(duì)代碼的功能和變量進(jìn)行分類,對(duì)于一個(gè)需求,在學(xué)C語(yǔ)言程序設(shè)計(jì)的時(shí)候我們可能更加關(guān)注的是數(shù)據(jù)結(jié)構(gòu)和運(yùn)行過(guò)程,而對(duì)于面向?qū)ο?,我們還要關(guān)注的有在實(shí)現(xiàn)需求的過(guò)程中,整個(gè)流程是由哪幾個(gè)東西來(lái)干,每個(gè)東西有什么特點(diǎn)、能干什么事情,東西與東西之間有什么聯(lián)系。當(dāng)然,我的理解可能還很膚淺甚至是錯(cuò)誤的,但是,我在學(xué)習(xí)OO課的過(guò)程中,確確實(shí)實(shí)能夠感受到自己的編程思想在發(fā)生一些轉(zhuǎn)變。
不過(guò),需要提升的地方還有很多,比如說(shuō)架構(gòu)設(shè)計(jì)和代碼實(shí)現(xiàn)上,盡管現(xiàn)在拿來(lái)題先開(kāi)始設(shè)計(jì)架構(gòu)而不是直接敲鍵盤了,但是設(shè)計(jì)到實(shí)現(xiàn)的過(guò)程還很艱難,感覺(jué)設(shè)計(jì)的時(shí)候考慮的東西還不夠周到,導(dǎo)致實(shí)現(xiàn)的時(shí)候很多地方都得重新構(gòu)思。其次,關(guān)于每個(gè)功能的代碼實(shí)現(xiàn),代碼總是超過(guò)限制的行數(shù),覺(jué)得自己可能在框架上是面向?qū)ο蟮?/strong>,但是在具體敲鍵盤的時(shí)候依然是面向過(guò)程的,希望在以后的學(xué)習(xí)過(guò)程中能夠提升自己面向?qū)ο蟮哪芰?,能夠更好的利用面向?qū)ο蟮乃枷肜斫馐澜纭?/p>
除此之外,對(duì)于實(shí)驗(yàn)課我也有一些反思。每次實(shí)驗(yàn)課助教們都在對(duì)我們的作業(yè)架構(gòu)進(jìn)行一定的提示,所以實(shí)驗(yàn)課代碼確實(shí)是我們應(yīng)該借鑒和學(xué)習(xí)的,但是這兩個(gè)單元我都忽視了實(shí)驗(yàn)代碼的重要性,導(dǎo)致一直在堆自己的*山。但是,不得不說(shuō),我經(jīng)常看不太懂實(shí)驗(yàn)代碼,盡管實(shí)驗(yàn)代碼的架構(gòu)很清晰巧妙,但是我還需要很多時(shí)間去理解。所以很多時(shí)候自己的爛代碼就像是自己的孩子,而實(shí)驗(yàn)代碼就像是別人家的孩子,不管別人家的孩子多么優(yōu)秀,我只愿意呵護(hù)關(guān)心自己的孩子。我這個(gè)比喻并不恰當(dāng),但是確實(shí)希望以后能夠多理解理解實(shí)驗(yàn)代碼,畢竟實(shí)驗(yàn)代碼的架構(gòu)和實(shí)現(xiàn)方式確實(shí)是教科書式的,如果能熟練應(yīng)用在自己的作業(yè)中會(huì)更好。
本文摘自 :https://www.cnblogs.com/