敏捷開發的必要技巧:將注釋轉為代碼
示例 這是一個會議管理系統. 在會議中,每個參會者都會戴一個牌子,這牌子上面有這個參會者的信息(比如姓名之類的).在這個系統中,Badge這個類用來存放這個參會者的信息.請看一下下面的代碼跟注釋: //存放參會者身上戴的牌子所顯示的信息. public class Badge {
示例
這是一個會議管理系統. 在會議中,每個參會者都會戴一個牌子,這牌子上面有這個參會者的信息(比如姓名之類的).在這個系統中,Badge這個類用來存放這個參會者的信息.請看一下下面的代碼跟注釋:
//存放參會者身上戴的牌子所顯示的信息.
public class Badge {
String pid; //參會者 ID
String engName; //英文全名
String chiName; //中文全名
String engOrgName; //所在部門英文名稱
String chiOrgName; //所在部門中文名稱
String engCountry; //部門所在國家的中文名稱
String chiCountry; //部門所在國家的英文名稱
//***********************
//構造函數.
//根據參會者的id,去數據庫取出該參與者的信息.
//***********************
Badge(String pid) {
this.pid = pid;
//***********************
//取出參會者
//***********************
ParticipantsInDB partsInDB = ParticipantsInDB.getInstance();
Participant part = partsInDB.locateParticipant(pid);
if (part != null) {
//取出參會者的英文全名
engName = part.getELastName() + ", " + part.getEFirstName();
//取出參會者的中文全名
chiName = part.getCLastName()+part.getCFirstName();
//***********************
//取出所在部門跟國家.
//***********************
OrganizationsInDB orgsInDB = OrganizationsInDB.getInstance();
//取出所在部門的id.
String oid = orgsInDB.getOrganization(pid);
if (oid != null) {
Organization org = orgsInDB.locateOrganization(oid);
engOrgName = org.getEName();
chiOrgName = org.getCName();
engCountry = org.getEAddress().getCountry();
chiCountry = org.getCAddress().getCountry();
}
}
}
...
}
將注釋轉換為代碼,讓代碼足夠清楚到可以表示注釋
我們先看一下第一個注釋:
//存放參會者身上戴的牌子所顯示的信息.
public class Badge {
...
}
我們干嘛需要這個注釋呢?因為程序員認為"Badge"這個類名不足以讓讀代碼的人清楚這個類的作用,所以就寫了這個注釋. 那如果我們直接將注釋所表達的一些信息放在類名里面的話,就沒有單獨寫注釋的必要了.比如::
public class ParticipantInfoOnBadge {
...
}
其實很多人肯定會問?難道寫注釋不是一個好的
編程習慣嗎?這問題很好,我也想知道.在解釋之前,我們先把這個示例中所有的注釋都轉為代碼先.
將注釋轉換為變量名
Consider:
public class ParticipantInfoOnBadge {
String pid; //參會者 ID
String engName; //英文全名
String chiName; //中文全名
String engOrgName; //所在部門英文名稱
String chiOrgName; //所在部門中文名稱
String engCountry; //部門所在國家的中文名稱
String chiCountry; //部門所在國家的英文名稱
...
}
這里,我們就像對屬性的注釋,轉化為屬性名, 比如:
public class ParticipantInfoOnBadge {
String participantId;
String participantEngFullName;
String participantChiFullName;
String engOrgName;
String chiOrgName;
String engOrgCountry;
String chiOrgCountry;
...
}
對參數的注釋,轉化為參數名
看看:
public class ParticipantInfoOnBadge {
...
//***********************
//構造函數.
//根據參會者的id,從數據庫取出該參與者的信息.
//***********************
ParticipantInfoOnBadge(String pid) {
this.pid = pid;
...
}
}
比如:
public class ParticipantInfoOnBadge {
...
//***********************
//構造函數.
//從數據庫取出該參與者的信息.
//***********************
ParticipantInfoOnBadge(String participantId) {
this.participantId = participantId;
...
}
}
將注釋轉換為方法的一部分
上面的構造函數中,有兩句注釋,第一句我們已經解決了,那么還有"從數據庫取出該參與者的信息"? 這句注釋描述了,這個構造函數是如何實現的(就是從數據庫里面取出信息),我們將這句話轉化:
public class ParticipantInfoOnBadge {
...
//***********************
//構造函數.
//***********************
ParticipantInfoOnBadge(String participantId) {
loadInfoFromDB(participantId);//現在,看一下這個構造函數內部,我們就能知道這個構造函數是做什么了吧.
}
void loadInfoFromDB(String participantId) {
this.participantId = participantId;
...
}
}
刪掉沒用的注釋
有時候,我們會碰到一些注釋,很明顯沒什么用處的,比如:
public class ParticipantInfoOnBadge {
...
//***********************
//構造函數.
//***********************
ParticipantInfoOnBadge(String participantId) {
...
}
}
就算去掉這些注釋,我們也能看得出來,這是個構造函數.這個注釋并沒什么用處.
什么樣的類是看代碼的人最喜歡的?那就是簡單易看的類.一個設計得好的類,能夠讓人家一眼就能出你這個類都有些什么東西,明白你這個類都做了一些什么事.如果看這個類的時候,要不停的將屏幕滾來滾去,而思維還要隨屏幕的滾動跳轉,無形中,看懂這個類需要花的時間就多了.
一個屏幕,差不多只能顯示20行左右的代碼,而這個沒用的注釋,一下子就占用了3行的代碼,一些有用的信息反而被擠掉了(比如說代碼),得不償失啊!我看還是趕緊移除這個注釋:
public class ParticipantInfoOnBadge {
...
ParticipantInfoOnBadge(String participantId) {
...
}
}
將一部分代碼重構成方法,用方法名來表達注釋的意思
先看看下面這個注釋:
void loadInfoFromDB(String participantId) {
this.participantId = participantId;
//***********************
//取得參會者的全名.
//***********************
ParticipantsInDB partsInDB = ParticipantsInDB.getInstance();
Participant part = partsInDB.locateParticipant(participantId);
if (part != null) {
//取得參會者的英文全名.
engFullName = part.getELastName() + ", " + part.getEFirstName();
//取得參會者的中文全名.
chiFullName = part.getCLastName()+part.getCFirstName();
//***********************
//取得參會者所在部門和國家.
//***********************
OrganizationsInDB orgsInDB = OrganizationsInDB.getInstance();
//取得參會者被雇傭部門的id.
String oid = orgsInDB.getOrganization(participantId);
if (oid != null) {
Organization org = orgsInDB.locateOrganization(oid);
engOrgName = org.getEName();
chiOrgName = org.getCName();
engOrgCountry = org.getEAddress().getCountry();
chiOrgCountry = org.getCAddress().getCountry();
}
}
}
現在我們已經看清這段注釋要表達一些什么信息,如果要使代碼跟注釋一樣清楚,我們可以將注釋所解釋的那部分代碼抽取出來,做成一個方法,然后讓方法名來表達注釋的意思.如果可以的話,我們就不需要額外的注釋了:
void loadInfoFromDB(String participantId) {
this.participantId = participantId;
getParticipantFullNames(); //(取得參會者的全名,注意,我們已經將注釋去掉了.)
//***********************
//取得參會者所在部門和國家.
//***********************
//取得參會者被雇傭部門的id.
OrganizationsInDB orgsInDB = OrganizationsInDB.getInstance();
String oid = orgsInDB.getOrganization(participantId);
if (oid != null) {
Organization org = orgsInDB.locateOrganization(oid);
engOrgName = org.getEName();
chiOrgName = org.getCName();
engOrgCountry = org.getEAddress().getCountry();
chiOrgCountry = org.getCAddress().getCountry();
}
}
void getParticipantFullNames() {
ParticipantsInDB partsInDB = ParticipantsInDB.getInstance();
Participant part = partsInDB.locateParticipant(participantId);
if (part != null) {
//取得參會者的英文全名.
engFullName = part.getELastName() + ", " + part.getEFirstName();
//取得參會者的中文全名.
chiFullName = part.getCLastName()+part.getCFirstName();
}
}
此外,還有一個注釋:"取得參會者所在部門和國家",也是可以重構在方法名里面的:
void loadInfoFromDB(String participantId) {
this.participantId = participantId;
getParticipantFullNames();
getOrgNameAndCountry(); //又抽取掉了一個注釋
}
void getParticipantFullNames() {
ParticipantsInDB partsInDB = ParticipantsInDB.getInstance();
Participant part = partsInDB.locateParticipant(participantId);
if (part != null) {
//取得參會者的英文全名.
engFullName = part.getELastName() + ", " + part.getEFirstName();
//取得參會者的中文全名.
chiFullName = part.getCLastName()+part.getCFirstName();
}
}
void getOrgNameAndCountry() {
OrganizationsInDB orgsInDB = OrganizationsInDB.getInstance();
//取得參會者被雇傭部門的id.
String oid = orgsInDB.getOrganization(participantId);
if (oid != null) {
Organization org = orgsInDB.locateOrganization(oid);
engOrgName = org.getEName();
chiOrgName = org.getCName();
engOrgCountry = org.getEAddress().getCountry();
chiOrgCountry = org.getCAddress().getCountry();
}
}
抽取出方法,放于另一個類
請看一下下面這兩個注釋:
public class ParticipantInfoOnBadge {
...
void getParticipantFullNames() {
ParticipantsInDB partsInDB = ParticipantsInDB.getInstance();
Participant part = partsInDB.locateParticipant(participantId);
if (part != null) {
//取得參會者的英文全名.
engFullName = part.getELastName() + ", " + part.getEFirstName();
//取得參會者的中文全名.
chiFullName = part.getCLastName()+part.getCFirstName();
}
}
}
因為程序員覺得,這些代碼片段還是不夠清楚,所以還是要用注釋還解釋它們. 但這回移除注釋時,我們會將抽取出來的方法,放到Participant這個類里面,而不是ParticipantInfoOnBadge了:
public class ParticipantInfoOnBadge {
...
void getParticipantFullNames() {
ParticipantsInDB partsInDB = ParticipantsInDB.getInstance();
Participant part = partsInDB.locateParticipant(participantId);
if (part != null) {
engFullName = part.getEFullName(); //將職責交給domain自己,也就是Participant.
chiFullName = part.getCFullName();
}
}
}
public class Participant {
String getEFullName() {
return getELastName() + ", " + getEFirstName();
}
String getCFullName() {
return getCLastName() + getCFirstName();
}
}
用注釋去命名一個已經存在的方法
請看下面的注釋,也是這個例子中的最后一個注釋了:
public class ParticipantInfoOnBadge {
...
void getOrgNameAndCountry() {
OrganizationsInDB orgsInDB = OrganizationsInDB.getInstance();
//取得參會者被雇傭部門的id.
String oid = orgsInDB.getOrganization(participantId);
if (oid != null) {
Organization org = orgsInDB.locateOrganization(oid);
engOrgName = org.getEName();
chiOrgName = org.getCName();
engOrgCountry = org.getEAddress().getCountry();
chiOrgCountry = org.getCAddress().getCountry();
}
}
}
我們之所以要用這個注釋"取得參會者被雇傭部門的id",是因為這個方法名"getOrganization"取得不夠清楚. 所以,我們將注釋表達的信息,放在這個方法名里面:
public class ParticipantInfoOnBadge {
...
void getOrgNameAndCountry() {
OrganizationsInDB orgsInDB = OrganizationsInDB.getInstance();
String oid = orgsInDB.findOrganizationEmploying(participantId);
if (oid != null) {
Organization org = orgsInDB.locateOrganization(oid);
engOrgName = org.getEName();
chiOrgName = org.getCName();
engOrgCountry = org.getEAddress().getCountry();
chiOrgCountry = org.getCAddress().getCountry();
}
}
}
public class OrganizationsInDB {
...
void findOrganizationEmploying(String participantId) {
...
}
}
pdf
下載:
http://www.blogjava.net/Files/Wingel/敏捷開發的必要技巧第1,2章.rar
原文轉自:http://www.kjueaiud.com