OO第三次博客作业---透过代码看设计
不得不說(shuō)的JSF
經(jīng)過(guò)前幾次作業(yè)的煎熬。出租車的代碼量不斷地增多。而出租車問(wèn)題在不斷的完善,這也就牽涉到一個(gè)問(wèn)題,那就是最初出租車程序的設(shè)計(jì)問(wèn)題,如果一開(kāi)始設(shè)計(jì)的就有問(wèn)題的話,那么在后來(lái)的過(guò)程中就會(huì)遇到更多的麻煩。就像微軟不斷的給自己的系統(tǒng)打補(bǔ)丁一樣。但是如果某一天他發(fā)現(xiàn)系統(tǒng)有一個(gè)關(guān)鍵性的設(shè)計(jì)錯(cuò)誤。雖然這種幾率較小,但是一旦發(fā)生,將會(huì)帶來(lái)巨大的災(zāi)難,https://baike.baidu.com/item/%E5%8D%83%E5%B9%B4%E8%99%AB/2954?fr=aladdin。2000發(fā)生的千年蟲(chóng)事件就是一個(gè)例子。所以說(shuō),設(shè)計(jì)是代碼的基礎(chǔ),對(duì)于大型項(xiàng)目來(lái)說(shuō)設(shè)計(jì)顯得更為重要。
設(shè)計(jì)是如此的重要,就體現(xiàn)了JSF的重要性了。軟件發(fā)展走到今天,代碼儼然進(jìn)入了開(kāi)源時(shí)代。Github造福千萬(wàn)碼農(nóng)。但是一拿到別人的代碼,除了天才,大型項(xiàng)目的代碼也是難以一眼就看個(gè)明白吧。這里java中的JSF就發(fā)揮了作用了。有了JSF就可以很容易的理解java中方法的功能,對(duì)理解代碼,與看懂設(shè)計(jì)者的目的有很大的幫助。所以我們需要多多閱讀JSF來(lái)提高自己的設(shè)計(jì)水平,(*^_^*),:D。是這樣的嗎?我覺(jué)得JSF的初衷是這樣的,但是…………,可能是由于JSF本身作為一種難以十分明確的評(píng)測(cè)標(biāo)準(zhǔn),可能會(huì)導(dǎo)致同學(xué)之間評(píng)測(cè)的時(shí)候有小小的差異。有時(shí)候還會(huì)很大,super 大。JSF真的很有用,慚愧的是,我都沒(méi)有好好寫(xiě)JSF,基本都是中文草草解決了,后來(lái)才知道,已經(jīng)不允許用中文了嗎?≡(▔﹏▔)≡。慶幸的是,我的人品還行,這么多JSF,就只被報(bào)了一個(gè)Crash,實(shí)在很感謝那位同學(xué)了,☆⌒(*^-゜)v THX!!
?
出租車完善第一彈,加流量
為了讓DD出租車變得更加優(yōu)秀。此次特地增加了DD打鬼出租車功能。Load FileName的設(shè)計(jì)功能。如果需要滿足客戶的話,那么必須是實(shí)時(shí)的,也就是說(shuō),所有的系統(tǒng)必須滿足能夠?qū)崟r(shí)的處理問(wèn)題。但是對(duì)于Load Filename的實(shí)時(shí)處理確實(shí)會(huì)帶來(lái)一些問(wèn)題。這一功能也體現(xiàn)了我上一次代碼的不足。在設(shè)計(jì)層面上處理輸入問(wèn)題的失誤。對(duì)于輸入的問(wèn)題,現(xiàn)在輸入變的多樣化了,那么輸入的處理不是簡(jiǎn)單的只處理乘客的請(qǐng)求了。這讓我參悟關(guān)于輸入的問(wèn)題。之前的的所有的程序中,我們都是直接把輸入看作是請(qǐng)求,或者是任務(wù)。也就是說(shuō),在程序開(kāi)始之前,輸入就是我們某個(gè)指定的東西了,但是現(xiàn)在,我們發(fā)現(xiàn),輸入就是一個(gè)輸入,不要在程序之外就定義輸入是什么,那樣就相當(dāng)于把輸入的概念縮小了。所以我們處理輸入也是在程序之中處理輸入。
public synchronized void run() {//Requires: 無(wú)//Modifies: in_input//Effect:對(duì)輸入判斷,判斷輸入是什么類型的//THREAD_REQUIRES:無(wú)//THREAD_EFFECT:輸入線程,就是對(duì)輸入判斷的線程String in_input=null;Scanner scanner = new Scanner(System.in);Request request_in = new Request(new_taxi, new_map, new_gui); //對(duì)于請(qǐng)求類,就是輸入是請(qǐng)求而不是其他Big_change big_change = new Big_change(); //對(duì)于大規(guī)模的改變創(chuàng)建對(duì)象Test test = new Test(); //對(duì)于Change_road road_ch = new Change_road();in_input = scanner.nextLine();//in_input = in_input.replaceAll(" ","");while(true) {if(in_input.equals("END")) {break;}else if(in_input.equals("Load D:\\est.txt")) {big_change.change(new_taxi, new_map, new_gui, in_input);}else if(in_input.matches(str_road)) {road_ch.road_change(new_map, new_gui, in_input);}else if(in_input.matches(str_test)) {test.test_out(new_taxi, in_input);}else{request_in.input(in_input);}in_input = scanner.nextLine();//in_input = in_input.replaceAll(" ",""); }scanner.close();return ;}?
請(qǐng)不要太在意JSF,它的初衷是讓你知道我這段代碼在干什么,ο(=?ω<=)ρ⌒☆
另一個(gè)設(shè)計(jì)上的問(wèn)題就是關(guān)于出租車隨機(jī)走的問(wèn)題。出租車在隨機(jī)行駛的過(guò)程中也需要走流量最小的那一條邊。我嘗試過(guò)很多種方法。在第一次作業(yè)中僥幸沒(méi)有被檢測(cè)到bug。但是到了下一次作業(yè)就難逃發(fā)掌了。首先解決流量問(wèn)題勢(shì)必會(huì)增加出租車隨機(jī)走時(shí)行走一步的時(shí)間,但是之前采用的方案是,while循環(huán)使用隨機(jī)數(shù)。由于隨機(jī)數(shù)的不確定性,導(dǎo)致走一步的時(shí)間差距還是蠻大的。后來(lái)直接暴力遍歷四條邊,也就是說(shuō),四條邊都遍歷一下,然后再判斷走哪一條邊,這樣每走一步,時(shí)間大致是相同的。對(duì),走到這里還沒(méi)什么問(wèn)題。但是我疏忽了另一個(gè)問(wèn)題。那就是之前流量的刷新都是單獨(dú)一個(gè)線程的。那個(gè)線程的時(shí)間是500ms。現(xiàn)在我每走一步的時(shí)間根本不可能掐到500ms。也就是說(shuō)毫無(wú)疑問(wèn)的錯(cuò)了。流量1還沒(méi)拿來(lái)計(jì)算可能就被清空了吧。所以,那就改吧。由于時(shí)間是一個(gè)玄學(xué)的問(wèn)題。“當(dāng)你站在另一個(gè)角度的時(shí)候,時(shí)間總是在流逝”。所以我們就用假時(shí)間吧。流量也改吧,每走一步清空上一步的流量,然而這也帶來(lái)了問(wèn)題,那就是內(nèi)存問(wèn)題。
for(int i=1; i<=4; i++) {if(direction==1) {if(this.location_x<79 && map_mess.graph[location][location_1]==1 && (tra_wan[1]<=tra_wan[wan_flag] || wan_flag==0)) {wan_tem_x = this.location_x+1;wan_tem_y = this.location_y;wan_flag = 1;}direction = 2;this.Taxi_Direct = 1; //表示如果向東行駛continue;}else if(direction==2) {if(this.location_x>0 && map_mess.graph[location][location_2]==1 && (tra_wan[2]<=tra_wan[wan_flag] || wan_flag==0)) {wan_tem_x = this.location_x-1;wan_tem_y = this.location_y;wan_flag = 2;}direction = 3;this.Taxi_Direct = 3; //表示如果向西行駛continue;}else if(direction==3) {if(this.location_y>0 && map_mess.graph[location][location_3]==1 && (tra_wan[3]<=tra_wan[wan_flag] || wan_flag==0)) {wan_tem_y = this.location_y-1;wan_tem_x = this.location_x;wan_flag = 3;}direction = 4;this.Taxi_Direct = 4; //表示如果向北行駛continue;}else if(direction==4) {if(this.location_y<79 && map_mess.graph[location][location_4]==1 && (tra_wan[4]<=tra_wan[wan_flag] || wan_flag==0)) {wan_tem_y = this.location_y+1;wan_tem_x = this.location_x;wan_flag = 4;}direction = 1;this.Taxi_Direct = 2; //表示如果向南行駛continue;}}?
設(shè)計(jì)上顧全大局還是很有難度的。追求速度的時(shí)候,必然需要損失一定的內(nèi)存。這是無(wú)法避免的。我們將流量整合到出租車運(yùn)行中,在內(nèi)存上的開(kāi)銷肯定會(huì)有所增大。因?yàn)槲以谶@里用的是靜態(tài)數(shù)組,而不是動(dòng)態(tài)數(shù)組。所以這個(gè)設(shè)計(jì)問(wèn)題還是難以處理。但是最好還是多用動(dòng)態(tài)數(shù)組,最好不要用靜態(tài)數(shù)組,因?yàn)槟阌肋h(yuǎn)不知道對(duì)面是怎樣測(cè)你的程序的。`(*>﹏<*)′
出租車完善第二彈,紅綠燈
這一次的內(nèi)容是加上紅綠燈。剛才提到的多線程之間的時(shí)間問(wèn)題導(dǎo)致的流量問(wèn)題與這一次發(fā)現(xiàn)的另一問(wèn)題有著異曲同工之妙…………。( *^-^)ρ(*╯^╰)? 在設(shè)計(jì)紅綠燈的時(shí)候,我們需要等紅綠燈。而我們將紅綠燈的控制放在了單獨(dú)的線程中,那么就會(huì)導(dǎo)致我們不得不同時(shí)用兩個(gè)線程處理數(shù)據(jù)。也就是供給與需求的沖突問(wèn)題。當(dāng)然,這里對(duì)紅綠燈的處理,只有紅綠燈管理線程改變紅綠燈的顏色,而出租車線程僅僅讀取紅綠燈的顏色,并不會(huì)改變之。當(dāng)我們?cè)谑致房诘却t綠燈時(shí)候,出租車線程應(yīng)該是怎么樣的呢?
if((this.Old_Direct==2 && this.Taxi_Direct==2) || (this.Old_Direct==4 && this.Taxi_Direct==4) || (this.Old_Direct==1 && this.Taxi_Direct==2) || (this.Old_Direct==3 && this.Taxi_Direct==4)) {while(guigv.lightmap[this.location_y][this.location_x]==1) { //這時(shí)需要等紅燈 ;}}?
這是之前的錯(cuò)誤代碼?同學(xué)們有沒(méi)有發(fā)發(fā)現(xiàn)這個(gè)代碼錯(cuò)誤的地方呢?
我測(cè)了好久才發(fā)現(xiàn)問(wèn)題,(′д` )…彡…彡
只要遇到紅綠燈,如果需要等待的話,程序就會(huì)進(jìn)入死循環(huán)。對(duì)是死循環(huán),也就是說(shuō)程序檢測(cè)不到紅綠燈的變化嗎?
錯(cuò)!!!是紅綠燈根本就沒(méi)有機(jī)會(huì)改變顏色,因?yàn)樵贘ava中,多線程是指線程之間的調(diào)度執(zhí)行,多個(gè)線程之間進(jìn)行切換。但是實(shí)際上,CPU中運(yùn)行的線程只有一個(gè),這樣寫(xiě)帶來(lái)的問(wèn)題就是,由于while()循環(huán)實(shí)在是太快了,中間沒(méi)有任何的停頓,假設(shè)我們需要切換到控制紅綠燈的線程,但是由于while()循環(huán)幾乎沒(méi)有延遲的就要訪問(wèn)紅綠燈,這個(gè)訪問(wèn)時(shí)間,遠(yuǎn)比改變紅綠燈的時(shí)間短,那么控制紅綠燈的線程根本就沒(méi)有運(yùn)行。所以就導(dǎo)致紅綠燈無(wú)法改變,只能切換到其他線程,不能進(jìn)入紅綠燈線程。出租車就會(huì)一直停在等待紅綠燈的地方。
更改之后應(yīng)該是這樣的。
if((this.Old_Direct==2 && this.Taxi_Direct==2) || (this.Old_Direct==4 && this.Taxi_Direct==4) || (this.Old_Direct==1 && this.Taxi_Direct==2) || (this.Old_Direct==3 && this.Taxi_Direct==4)) {while(guigv.lightmap[this.location_y][this.location_x]==1) { //這時(shí)需要等紅燈try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch block e.printStackTrace();}}}?
我們等待紅綠燈的線程。說(shuō)到底就是等待時(shí)間,所以在這種情況下,我們?cè)诩t綠燈控制中計(jì)算好這樣一個(gè)時(shí)間,那就是下次紅綠燈改變的時(shí)間。
while(true) {try {Thread.sleep(guigv.Light_time);} catch (InterruptedException e) {// TODO Auto-generated catch block e.printStackTrace();}for(int i=0; i<80; i++) {for(int j=0; j<80; j++) {Light_Change(i,j);}}guigv.Light_Still = System.currentTimeMillis() + guigv.Light_time;}?
這樣,如果遇見(jiàn)紅綠燈需要等待,只需要等待至下次紅綠燈改變的時(shí)候即可。
出租車完善第三彈,VIP車
這里我們我們將他叫做VIP車,實(shí)際上是可追蹤出租車。但是我覺(jué)得老師提出可追蹤出租車的緣由并不是可以讓他走已關(guān)閉的道路,同時(shí)可以記錄出租車艱辛的路途。而是在檢測(cè)我們的設(shè)計(jì)的問(wèn)題。對(duì)設(shè)計(jì)而言是十分重要的。在這里我直接上我的程序設(shè)計(jì)文檔吧。寫(xiě)得不好,還是不上了吧,emmm。為什么嗎說(shuō)是檢測(cè)我們的設(shè)計(jì)問(wèn)題呢?因?yàn)閂IP出租車必須使用繼承的方式完成。這就要求我們?cè)瓉?lái)的出租車必須要有較為完整的設(shè)計(jì),才能接下來(lái)的操作。對(duì)于我來(lái)說(shuō),論證我的可追蹤出租車可能有些強(qiáng)詞奪理,但是我還是將要求實(shí)現(xiàn)了。具體實(shí)現(xiàn)的方法是這樣的。
我并沒(méi)有設(shè)計(jì)ArrayList將所有的出租車數(shù)據(jù)作為對(duì)象來(lái)存起來(lái)。而是將他們?nèi)枷戎苯虞敵龅轿募?#xff0c;作為中間存儲(chǔ)的介質(zhì),最后在需要的時(shí)候再將他們輸出出來(lái)。看起來(lái)這樣寫(xiě)也是挺好的,但是這樣并不是老師的初衷。為什么需要將數(shù)據(jù)作為對(duì)象來(lái)存儲(chǔ)起來(lái)呢?我之后在想這樣一個(gè)問(wèn)題,在我們的程序中,重要的是對(duì)對(duì)象的處理,只有將數(shù)據(jù)作為對(duì)象存儲(chǔ)器來(lái),才能真正意義上的實(shí)現(xiàn)迭代器。但是我們將數(shù)據(jù)輸出到文件,需要的時(shí)候再拿出來(lái),通常是工業(yè)上常常采用的方式。這樣的好處是隨隨時(shí)都可以訪問(wèn)大量的數(shù)據(jù),還可以通過(guò)其他程序進(jìn)行訪問(wèn)。但是指導(dǎo)書(shū)的要求是要實(shí)現(xiàn)迭代器,這樣卻無(wú)法實(shí)現(xiàn)。
關(guān)于出租車的繼承,我們需要滿足LSP原則,首先什么是JSP原則呢?
所有引用基類的地方必須能透明地使用其子類的對(duì)象。
通俗點(diǎn)講,只要父類能出現(xiàn)的地方子類就可以出現(xiàn),而且替換為子類也不會(huì)產(chǎn)生任何錯(cuò)誤或異常,使用者可能根本就不需要知道是父類還是子類。但是,反過(guò)來(lái)就不行了,有子類出現(xiàn)的地方,父類未必就能適應(yīng)。
那么我是怎樣滿足的呢?
我們?cè)谠O(shè)計(jì)的過(guò)程中使用了繼承。Super_Taxi類是從Taxi類繼承來(lái)的。那么他們之間是怎樣滿足要求的呢?首先,我再創(chuàng)建100個(gè)出租車時(shí)候是使用的是,Taxi類創(chuàng)建。這樣的一個(gè)數(shù)組,但是接下來(lái)
for(int i=1; i<=100; i++) {if(i<=30) {cars[i] = new Super_Taxi(i,map_GUI.gui,guiinfo);map_GUI.gui.SetTaxiType(i, 1);}else {cars[i] = new Taxi(i,map_GUI.gui,guiinfo); map_GUI.gui.SetTaxiType(i, 0);} }在這里,我們將前30輛出租車向下轉(zhuǎn)型,也就是初始化為Super_Taxi類,然后還是這樣的數(shù)組,我將這個(gè)數(shù)組的數(shù)據(jù)結(jié)構(gòu)傳到了其它的對(duì)象中作為其他的對(duì)象的屬性。但是屬性都是以Taxi定義的,這也就是說(shuō)明了,只要父類出現(xiàn)的地方,子類就可以出現(xiàn)。所以不會(huì)有錯(cuò)。然后就是我們?cè)趥鞯慕涌谑怯玫氖荰axi,但是我們可以看到的是,出租車Super_Taxi和Taxi里面,我的子類就是重寫(xiě)了父類的一些方法的。雖然接口是Taxi,但是我們最終調(diào)用的還是Super_taxi里面的方法。這也就滿足了多態(tài)的向下轉(zhuǎn)型。綜上所訴,這個(gè)繼承的是滿足LSP原則的。
總結(jié):對(duì)不起,我可能寫(xiě)不好JSF了
首先拿個(gè)自己的JSF出來(lái)試試水。
//Requires: str_in
//Modifies: find_num
//Effect:請(qǐng)求輸入->判斷是否合法 && 獲取請(qǐng)求的信息
這是input()方法的JSF,對(duì), 就是這樣,三次作業(yè)都沒(méi)改過(guò)。好好看著我這反面教材……。(人品是多么重要,(o゜▽゜)o☆? ),那么多JSF都是這么寫(xiě),只被報(bào)了一個(gè)Crash。再次感謝第三次測(cè)我代碼的那位好心人。
雖然我自己的代碼JSF寫(xiě)的不是很好。但是我在閱讀別人的代碼的過(guò)程中還是好好閱讀過(guò)他們的JSF的。結(jié)論是,同樣看不懂,但是我沒(méi)有報(bào)過(guò)任何一個(gè)規(guī)格bug,( o=^?ェ?)o ┏━┓
總結(jié)起來(lái)了,就是這個(gè)東西確實(shí)很有用,但是在OO這門(mén)課程中,體現(xiàn)的不是很明顯,反而成為互測(cè)被針對(duì)的地方。感覺(jué)有點(diǎn)違背了當(dāng)時(shí)發(fā)明JSF的人的初衷,希望在之后的作業(yè)里面,大家可以友好相處,和諧六系。但是JSF的書(shū)寫(xiě)有問(wèn)題,不代表設(shè)計(jì)也有問(wèn)題。同樣,可以寫(xiě)不好JSF,但是不能采用一個(gè)讓人無(wú)法理解的設(shè)計(jì)方案。總之呢?就是強(qiáng)調(diào)設(shè)計(jì)方案的重要性,為什么重要呢?這里引用老子的一句話“合抱之木,生于毫末,九層之臺(tái),起于累土,千里之行,始于足下”。只要每一步都設(shè)計(jì)好,一步一步的走下去,最終一定能夠走向成功。共勉,*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。
轉(zhuǎn)載于:https://www.cnblogs.com/wevolf/p/9098701.html
總結(jié)
以上是生活随笔為你收集整理的OO第三次博客作业---透过代码看设计的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 快速重置vuex数据 - Vue
- 下一篇: 20155209 林虹宇 Exp9 We