消除case / if語句
要儘量避免在代碼中出現判斷語句,來測試一個對象是否某個特定類的實例。通常,如果你需要這麼做,那麼,重新設計可能會有所幫助。我在工作中遇到這樣的一個問題:我們在使用JAVA做XML解析時,對每個標籤映射了一個JAVA類,採用SAX(簡單的XML接口API:Simple API for XML)模型。結果,代碼中反覆出現了大量的判斷語句,來測試當前的標籤類型。爲此,我們重新設計了DTD(文檔類型定義:Document Type Definition),爲每個標籤增加了一個固定的屬性:classname,而且重新設計了每個標籤映射的JAVA類的接口,統一了每個對象的操作:
addElement(Element aElement); //增加子元素
addAttribute(String attName, String attValue); //增加屬性;
則徹底消除了所有的測試當前的標籤類型的判斷語句。每個對象通過 Class.forName(aElement.attributes.getAttribute("classname")).newInstence(); 動態創建,
減少參數個數
有大量參數需要傳遞的方法,通常很難閱讀。我們可以將所有參數封裝到一個對象中來完成對象的傳遞,這也有利於錯誤跟蹤。
許多程序員因爲,太多層的對象包裝對系統效率有影響。是的,但是,和它帶來的好處相比,我們寧願做包裝。畢竟,"封裝"也是OO的基本特性之一,而且,"每個對象完成儘量少(而且簡單)的功能",也是OO的一個基本原則。
類層次的最高層應該是抽象類
在許多情況下,提供一個抽象基類有利做特性化擴展。由於在抽象基類中,大部分的功能和行爲已經定義好,使我們更容易理解接口設計者的意圖是什麼。
由於JAVA不允許"多繼承",從一個抽象基類繼承,就無法再從其它基類繼承了。所以,提供一個抽象接口(interface)是個好主意,一個類可以實現多個接口,從而模擬實現了"多繼承",爲類的設計提供了更大的靈活性。
儘量減少對變量的直接訪問
對數據的封裝原則應該規範化,不要把一個類的屬性暴露給其它類,而是應該通過訪問方法去保護他們,這有利於避免產生波紋效應。如果某個屬性的名字改變,你只需要修改它的訪問方法,而不是修改所有相關的代碼。
子類應該特性化,完成特殊功能
如果一個子類只是使一個組件變成組件管理器,而不是實現接口功能,或者,重載某個功能,那麼,就應該使用一個外部的容器類,而不是創建一個子類。
建議:類層次結構圖,不要太深;
例如:下面的接口定義了組件的功能:發送消息;類Transceiver實現了該接口;而其子類Pool只是管理多個Transceiver對象,而沒有提供自己的接口實現。建議使用組合方式,而不是繼承!
public interface ITransceiver{
public abstract send(String msg);
}
public class Transceiver implements ITransceiver {
public send(String msg){
System.out.println(msg);
}
}
//使用繼承方式的實現
public class Pool extends Transceiver{
private List pool = new Vector();
public void add(Transceiver aTransceiver){
pool.add(aTransceiver);
}
public Transceiver get(int index){
pool.get(index);
}
}
//使用組合方式的實現
public class Pool {
private List pool = new Vector();
public void add(Transceiver aTransceiver){
pool.add(aTransceiver);
}
public Transceiver get(int index){
pool.get(index);
}
}
拆分過大的類
如果一個類有太多的方法(超過50個),那麼它可能要做的工作太多,我們應該試着將它的功能拆分到不同的類中,類似於規則四。
作用截然不同的對象應該拆分
在構建的過程中,你有時會遇到這樣的問題:對同樣的數據,有不同的視圖。某些屬性描述的是數據結構怎樣生成,而某些屬性描述的是數據結構本身。最好將這兩個視圖拆分到不同的類中,從類名上就可以區分出不同視圖的作用。
類的域、方法也應該有同樣的考慮!
儘量減少對參數的隱含傳遞
兩個方法處理類內部同一個數據(域),並不意味着它們就是對該數據(域)做處理。許多時候,該數據(域)應該作爲方法的參輸入數,而不是直接存取,在工具類的設計中尤其應該注意。例如:
public class Test{
private List pool = new Vector();
public void testAdd(String str){
pool.add(str);
}
public Object testGet(int index){
pool.get(index);
}
}
兩個方法都對List對象pool做了操作,但是,實際上,我們可能只是想對List接口的不同實現Vector、ArrayList等做存取測試。所以,代碼應該這樣寫:
public class Test{
private List pool = new Vector();
public void testAdd(List pool, String str){
pool.add(str);
}
public Object testGet(List pool, int index){
pool.get(index);