一點(diǎn)重構(gòu)心得
昨天,要寫一段程序完成一個定時任務(wù),是有關(guān)Socket 發(fā)送的。胖子給我發(fā)了一段現(xiàn)成的程序,這段程序基本上的功能是實(shí)現(xiàn)了,但是表達(dá)的并不是那么清晰,因此我想重構(gòu)一下。沒想到重構(gòu)的過程竟然花了一個多小時,從晚上八點(diǎn)多,一下就寫到了十點(diǎn),但是重構(gòu)完后,感覺清晰多了。仔細(xì)想想收獲頗多,因此在這里寫寫經(jīng)驗(yàn)進(jìn)行總結(jié)。重構(gòu)程序的目的,不是因?yàn)槌绦虿荒苡貌乓闳ブ貥?gòu),重構(gòu)的目的是因?yàn)橐弧⒛愕拇a,被人看的次數(shù),遠(yuǎn)比它用到的次數(shù)多;二、重構(gòu)有利于你發(fā)現(xiàn)問題,讓你的程序結(jié)構(gòu)優(yōu)化,因此可復(fù)用性更強(qiáng),遵守了知識的唯一性,DRY 原則;三、如果你要改動這段代碼,那么先重構(gòu),使得你的代碼好改,這實(shí)際是在為你的未來減少工作量,而且一段優(yōu)秀的代碼,帶給你的價值,遠(yuǎn)比你每次都要Ctrl+C,Ctrl+V 大得多。
寫代碼,要讓你的代碼第一次呈現(xiàn)在別人面前的時候,像讀英語一般,那么你的代碼功底是足夠了。你的代碼就可以稱作你最好的文檔了,其余什么文檔,大可不必!
基于昨天的經(jīng)驗(yàn),我新總結(jié)了兩條:
一、經(jīng)常使用重構(gòu)方法extract method 的人,會發(fā)現(xiàn),總是可以省掉一些臨時變量。這是好事,但這可能會造成如下的結(jié)果:
method_one(method_two(method_three(method_four())))
也就是說,很可能會導(dǎo)致這種長串的嵌套,導(dǎo)致程序可讀性的下降,使人看的暈頭轉(zhuǎn)向。那么如何解決呢,其實(shí)是一個度的問題。我給自己定了一個規(guī)矩,臨界點(diǎn)是三個函數(shù)這樣級聯(lián)起來,如果超過三個,我就將它們拆開。比如說上面這個小例子,我會拆成:
arg = method_three(method(four));
method_one(method_two(arg));
雖然浪費(fèi)了一個臨時變量,但是這樣就可以讓人一眼看懂我的意思,可讀性提升,修改起來自然也會容易些。
二、寫過Java I/O 的人,肯定看到過這樣的程序:
Reader in = null;
Writer out = null;
try
{
in = new InputStreamReader(socket.getInputStream(),"utf8");
out = new OutputStreamWriter(socket.getOutputStream(),"utf8");
/**
* some TODOs here
*
**/
}catch(IOException ioe)
{
System.err.println("error message");
ioe.printStackTrace();
}
finally
{
try
{
if(in != null)
in.close();
if(out != null)
out.close();
}catch(IOException ioe2)
{
System.err.println("some error message");
ioe2.printStackTrace();
}
}
怎么說呢,這段代碼看上去,其實(shí)是夠好了,其實(shí)不重構(gòu)也是可以的。也許我偏執(zhí)吧,我認(rèn)為它不夠好,因?yàn)椋菏紫龋蠖蔚膖ry catch 的確會捕獲異常,但是這段代碼至少有好幾段是會獨(dú)立拋出異常的,這里包含了四個IO 實(shí)例的創(chuàng)建和銷毀,這四段代碼如果出錯都會拋出異常,那么你捕獲的到底是哪個呢?其次,沒有把功能段合理分開,這段代碼的邏輯功能實(shí)際上是兩個,一個是讀,一個是寫,那么合并在一起,首先順序很亂,其次容易讓閱讀的人產(chǎn)生困惑,從而造成代碼可讀性差。我是這樣做的:
private void writeFile(String fileName, String outStr)
{
Writer writer = null;
try
{
writer = new OutputStreamWriter(new FileOutputStream(fileName),
"utf8");
}
catch (UnsupportedEncodingException e)
{
System.err.println("不支持的編碼方式");
e.printStackTrace();
}
catch (FileNotFoundException e)
{
System.err.println("初始化文件失敗,或路徑不存在:" + fileName);
e.printStackTrace();
}
try
{
writer.write(outStr);
writer.flush();
}
catch (IOException e)
{
System.err.println("寫文件失敗");
e.printStackTrace();
}
finally
{
try
{
if(writer != null)
writer.close();
}
catch (IOException e)
{
System.err.println("關(guān)閉文件失敗");
e.printStackTrace();
}
}
}
類似的,也將讀的邏輯獨(dú)立抽出來,雖然,這不但沒使代碼的量減少,卻增加了很多try catch 模塊,不過邏輯上很完整,而且發(fā)揮了每個try catch 的最佳功效。我把它起名曰,我個人的偏執(zhí)情節(jié)吧。
困了,要睡覺了,本來還想將代碼從最初模樣,到最后模樣的過程復(fù)述一遍,改天有機(jī)會再說,精華都已經(jīng)說了。嘿嘿
posted on 2008-01-08 23:56 朱雀 閱讀(352) 評論(0) 編輯 收藏 所屬分類: java 基礎(chǔ) 、應(yīng)用