程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA編程入門知識 >> Java 理論與實踐:偽typedef反模式

Java 理論與實踐:偽typedef反模式

編輯:JAVA編程入門知識

  將泛型添加到 Java 語言中增加了類型系統的復雜性,提高了許多變量和方法聲明的冗長程度。因為沒有提供 “typedef” 工具來定義類型的簡短名稱,所以有些開發人員轉而把擴展當作 “窮人的 typedef”,結果收到了良好的效果。
  
  對於 Java 5.0 中新增的泛型工具,一個常見的抱怨就是,它使代碼變得太冗長。原來用一行就夠的變量聲明不再存在了,與聲明參數化類型有關的重復非常討厭,非凡是還沒有良好地支持自動補足的 IDE。例如,假如想聲明一個 Map,它的鍵是 Socket,值是 Future<String>,那麼老方法就是:
  
  
Map socketOwner = new HashMap(); 

  比新方法緊湊得多:
  
  
 
Map<Socket, Future<String>> socketOwner  
  = new HashMap<Socket, Future<String>>();   

  當然,新方法內置了更多類型信息,減少了編程錯誤,提高了程序的可讀性,但是確實帶來了更多聲明變量和方法簽名方面的前期工作。類型參數在聲明和初始化中的重復看起來尤其沒有必要;Socket 和 Future<String> 需要輸入兩次,這迫使我們違犯了 “DRY” 原則(不要重復自己)。
  
  合成類似於 typedef 的東西
  
  添加泛型給類型系統增加了一些復雜性。在 Java 5.0 之前,“type” 和 “class” 幾乎是同義的,而參數化類型,非凡是那些綁定的通配類型,使子類型和子類的概念有了顯著區別。類型 ArrayList<?>、ArrayList<? extends Number> 和 ArrayList<Integer> 是不同的類型,雖然它們是由同一個類 ArrayList 實現的。這些類型構成了一個層次結構;ArrayList<?> 是 ArrayList<? extends Number> 的超類型,而 ArrayList<? extends Number> 是 ArrayList<Integer> 的超類型。
  
  對於原來的簡單類型系統,像 C 的 typedef 這樣的特性沒有意義。但是對於更復雜的類型系統,typedef 工具可能會提供一些好處。不知是好還是壞,總之在泛型加入的時候,typedef 沒有加入 Java 語言。
  
  有些人用作 “窮人的 typedef” 的一個(壞的)做法是一個小小的擴展:創建一個類,擴展泛型類型,但是不添加功能,例如 SocketUserMap 類型,如清單 1 所示:
  
    清單 1. 偽 typedef 反模式 —— 不要這麼做
  
  
 
public class SocketUserMap extends HashMap<Socket<Future<String>> { } 
SocketUserMap socketOwner = new SocketUserMap(); 

  我將這個技巧稱為偽 typedef 反模式,它實現了將 socketOwner 定義簡化為一行的這一(有問題的)目標,但是有些副作用,最終成為重用和維護的障礙。(對於有明確的構造函數而不是無參構造函數的類來說,派生類也需要聲明每個構造函數,因為構造函數沒有被繼續。)
  
  偽類型的問題
  
  在 C 中,用 typedef 定義一個新類型更像是宏,而不是類型聲明。定義等價類型的 typedef,可以與原始類型自由地互換。清單 2 顯示了一個定義回調函數的示例,其中在簽名中使用了一個 typedef,但是調用者提供給回調的是一個等價類型,而編譯器和運行時都可以接受它:
  
    清單 2. C 語言的 typedef 示例
  
 
// Define a type called "callback" that is a function pointer 
typedef void (*Callback)(int); 

void doSomething(Callback callback) { } 

// This function conforms to the type defined by Callback 
void callbackFunction(int arg) { } 

// So a caller can pass the address of callbackFunction to doSomething 
void useCallback() { 
  doSomething(&callbackFunction);  
} 

  擴展不是類型定義
  
  用 Java 語言編寫的試圖使用偽 typedef 的等價程序就會出現麻煩。清單 3 的 StringList 和 UserList 類型都擴展了一個公共超類,但是它們不是等價的類型。這意味著任何想調用 lookupAll 的代碼都必須傳遞一個 StringList,而不能是 List<String> 或 UserList。
  
    清單 3. 偽類型如何把客戶限定在只能使用偽類型
  
 
class StringList extends ArrayList<String> { } 
class UserList extends ArrayList<String> { } 
... 
class SomeClass { 
    public void validateUsers(UserList users) { ... } 
    public UserList lookupAll(StringList names) { ... } 

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved