註釋怎麼寫
註釋的作用是什麼?
我認爲註釋最終作用無非就兩個。
1.和僞代碼一樣的作用,爲接下來要實現的功能寫出一個指導性的算法思路。只是沒有僞代碼詳細。但是也指出了完成此功能的大體算法思路。
2.給看代碼的人一個解釋性說明。注意看代碼的人包括你自己。讓看你代碼的人可以快速的瀏覽你的代 碼,而不至於每看一行都要一層
一層的方法看下去,才能瞭解你這個方法到底在幹什麼。
簡單的說註釋作用就是:寫的時候提供算法思路。讀的時候能快速瞭解你大約是怎麼完成這個功能。
註釋越多越好?
很多公司或者個人希望開發者註釋寫的足夠詳細。以爲這樣就可以提高可讀性。我覺得這個想法是有問題的。
1.首先開發者寫註釋的時間可能超過了寫代碼。如果把大把的時間浪費在寫註釋上了,那麼開發者還怎麼能設計出足夠好的代碼呢。
2.看註釋的人不得不一邊看註釋,一邊看代碼。我覺得沒有哪個程序員會在看了足夠詳細的註釋的時候就真的相信了註釋而不看
具體的代碼了。或者看完代碼之後不看下注釋確認下自己的理解對不對。那麼就會造成老師期末考試的時候劃重點的時候說每章
的都 是重點。
註釋應該怎麼寫?
下面是我個人對註釋寫法的一些見解。
1.其實很簡陋啊。就是你實現的時候的僞代碼的超級精簡版。你要完成一個功能你就是 1.先xxx 2.在xxx 3.在xxx。那就把這個 1,2,3 註釋寫
上去就好了。如果有其他很重要的步驟的話,也可以寫下注釋說明。但是主流程 1,2,3必須要清楚。舉個例子:
一個人早上上班的流程。
起牀->刷牙->吃早飯->坐公交->刷卡->早會->coding。
/**
* 去上班 起牀->刷牙->吃早飯->坐公交->刷卡->早會->coding。
*
* @param test
*/
public void goWork( String test ){
//起牀
wakeUp();
//刷牙
toothbrushing();
//吃早飯
haveBreakfast();
//坐公交
takeBus();
//刷卡
swipingCard();
//早會
takeMorningMeeting();
//coding
coding();
}
看上面的註釋部分,相信你會非常快的瞭解這個人去工作需要哪些步驟。具體的起牀穿什麼衣服,刷牙用什麼牙膏等更細節的問題,本身就不是這個
goWork() 方法應該考慮的了。你想了解你去看具體的代碼塊就好了。
如果在坐公交的時候出現 bug。那麼開發者是不需要慢慢的找坐公交在哪開始的了。你可以直接的找到 takeBus() 開始仔細查找就好了。
2.該暴露的你必須要暴露出來讓其他開發者來看到。別人可以一目瞭然的知道你這個功能時候怎麼實現的。
函數不是越短越好,是越簡單越好。是算法上的清楚或者說是邏輯上的簡單
下面是我 review 代碼經常會遇到的問題。
例如我們把 坐公交,刷卡 這兩個方法寫到 吃早飯方法裏。
/**
* 去上班 起牀->刷牙->吃早飯->坐公交->刷卡->早會->coding。
*
* @param test
*/
public void goWork( String test ){
//起牀
wakeUp();
//刷牙
toothbrushing();
//吃早飯
haveBreakfast();
//早會
takeMorningMeeting();
//coding
coding();
}
//吃早飯
private void haveBreakfast() {
//先吃早飯
//坐公交
takeBus();
//刷卡
swipingCard();
}
代碼,變短了。從計算機的角度講沒毛病。吃完飯了坐公交然後刷卡。但是程序員只是瞭解計算機並不是真的是計算機。從 goWork() 函數上很直觀看的話,我就以爲是起牀->刷牙->吃早飯->早會->coding。然後坐公交出現了 bug 那麼恭喜你慢慢找吧。
上面那個例子同時違背了方法的責任單一原則。即一個方法只能抽象一件功能。
去上班可以是一個功能,起牀可以是一個功能,但是吃早飯,坐公交,刷卡肯定不是一個功能。
實踐中的經驗。
1.一個步驟下面還有子步驟。
不是說註釋下面就是對應一個方法。很多時候因爲其他的原則,比如說沒有複用性的是沒有必要寫成方法的。這種時候一個功能會是很多子功能的集合。那麼我建議子功能的註釋最好和上級功能的註釋區分開。以表明這只是一個子流程。
例子:
主流程使用 ===開頭
子流程使用 ——————-開頭。
樣式明確表示了功能級別。長度起到了看起來方便(因爲,像僞代碼的縮進)。
public final String apLogin(final HttpServletRequest request, HttpServletResponse response) {
//===本次請求的原數據寫日誌==================
String parameters = JSON.toJSONString(request.getParameterMap());
//-------------獲取 token 做爲本次請求的日誌 id-
String logId = StringUtil.getToken();
//-------------本次請求的數據寫日誌------------
logger.debug("{}訂製終端獲取頁面參數爲:{}", logId, parameters);
//===解析參數==============================
String deviceId = request.getParameter("dev_id");
String userMac = StringUtil.formatMac(request.getParameter("client_mac"));
String gwAddress = request.getParameter("gw_address");
String gwPort = request.getParameter("gw_port");
String url = request.getParameter("url");
String publicUserIp = request.getHeader(Constants.X_FORWARDED_FOR);
String publicUserPort = request.getHeader(Constants.X_FORWARDED_PORT);
//===校驗參數==============================
ApPortalServiceDTO apPortalServiceDTO =
new ApPortalServiceDTO(deviceId, userMac, gwAddress, gwPort, url, publicUserIp, publicUserPort);
String validateResult = validateLoginParameters(apPortalServiceDTO);
if ( null != validateResult) {
logger.error("{}訂製終端獲取頁面服務參數校驗不通過:{},參數爲:{}",
logId, validateResult, JSON.toJSONString(apPortalServiceDTO));
return JSON.toJSONString(ResultDTO.getParameterErrorResultDTO(validateResult));
}
//===去數據中心查詢 portal 頁信息===============
//-----------寫日誌需要的信息---------------
GlobalDTO globalDTO = new GlobalDTO(
logId, FunctionNameConstants.AP_PORTAL, GlobalDTO.assembleLogValue(deviceId, userMac));
//-----------查詢頁面信息------------------
ResultDTO resultDTO = apPortalService.getApPortal(globalDTO, apPortalServiceDTO);
if (ResultDTO.isResultError(resultDTO.getResultCode())) {
return JSON.toJSONString(resultDTO);
}
try {
//===重定向拉去拉取相應的頁面====================
response.sendRedirect((String) resultDTO.getData());
logger.info("{}apLogin重定向到{}完成", logId, resultDTO.getData());
//===返回客戶端結果
return JSON.toJSONString(new ResultDTO());
} catch (Exception e) {
logger.error("{}重定向到:{}發生異常:",
JSON.toJSONString(globalDTO), resultDTO.getMessage(), StringUtil.getExceptionStackTrace(e));
return JSON.toJSONString(ResultDTO.SEND_REDIRECT_EXCEPTION);
}
}