BeanShell腳本接口之“傻瓜”適配器(Adapter)和不完整的接口

更多BeanShell內容請點擊此處

在 Java 中爲了(處理)擁有多個方法的接口而創建“傻瓜”適配器的情況非常得常見。傻瓜適配器的工作就是帶着存根(空方法體)實現接口中的所有方法,允許開發者擴展適配器並且只是重寫感興趣的方法。

我們在之前的討論中暗示過 BeanShell 可以處理只是實現實際被使用的方法子集的腳本接口,而 BeanShell 的確就是這樣。你可以在 BeanShell 中自由地只是編寫你期望調用的接口方法的腳本。離開了實際被調用的方法的懲罰是調用者會接收到一個特殊的 run-time 異常: java.lang.reflect.UndeclaredThrowableException。

UndeclaredThrowableException 是 Java 語法 API 中的一個典型,使動態接口成爲可能。就是說一個接口拋出一個沒有被方法簽名指定的檢查異常類型。那是在 Java 編譯環境中不太會發生的情況。所以 Java 反射 API 通過在這個特殊的未檢查(RuntimeException)類型裏包裝檢查異常的方式將它拋出。你可以通過使用 exception 的 getCause() 方法獲得隱含的錯誤,這樣做將顯示 BeanShell 的 EvalError 異常,報出沒有找到正確簽名的腳本方法。

invoke() 元方法
BeanShell 爲帶有大量方法的腳本接口提供一個非常簡單的速記機制。你可以在任何腳本上下文中實現特殊方法 invoke(name, args)。invoke() 方法被調用來處理未被定義的接口的任何方法的調用。
示例代碼

  1. mouseHandler = new MouseListener() { 
  2.   mousePressed( event ) { 
  3.     print("mouse button pressed"); 
  4.   } 
  5.   invoke( method, args ) { 
  6.     print("Undefined method of MouseListener interface invoked:" + name +", with args: "+args  ); 
  7.   } 
  8. }; 
  9. JFrame jf = new JFrame(); 
  10. int a10 = Toolkit.getDefaultToolkit().getScreenSize().width; // 取得屏幕長度 
  11. int b10 = Toolkit.getDefaultToolkit().getScreenSize().height; // 取得屏幕寬度 
  12. jf.setLocation((a10 - 500) / 2, (b10 - 300) / 2); // 設定位置(屏幕中心) 
  13. jf.setTitle("窗口"); // 設定標題 
  14. jf.setSize(500, 300); // 設定大小 
  15. jf.setResizable(false); // 設定不能縮放 
  16. jf.setVisible(true); // 設定顯示 
  17. jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 設定在點關閉後關閉窗口 
  18. jf.addMouseListener(mouseHandler); 

運行效果

呈現出的窗口

將你的鼠標移到窗口內,或者點擊窗口空白處來觀察控制檯的變化
 

在上面的例子中我們忽視了 MouseListener 接口裏五個方法中的四個方法。他們將會被 invoke() 方法處理,簡單地打印方法名和他的參數。不管怎樣,既然 mousePressed() 方法被定義了,它就會被接口調用。

這是一個更實際的例子,可謂性手拈來。在解析一個 XML 文檔時,讓我們使用 invoke() 方法來打印通過 Java SAX API 接口 ContentHandler 調用的方法名稱。

示例代碼

  1. import javax.xml.parsers.*; 
  2. import org.xml.sax.InputSource; 
  3. factory = SAXParserFactory.newInstance(); 
  4. saxParser = factory.newSAXParser(); 
  5. parser = saxParser.getXMLReader(); 
  6. parser.setContentHandler( this ); 
  7. invoke( name, args ) { 
  8.   print( name ); 
  9. parser.parse( new InputSource(bsh.args[0]) ); 

通過運行 XML 文件腳本作爲參數,我們可以看到幾打或者如同這樣 SAX API 的方法通過文檔的結構被運行起來,無需爲它們每個方法寫空方法。

  1. 提示: 
  2. 你可以直接在你自己的範圍或者也可以是全局的範圍裏使用 invoke(name, args)元方法,這樣你可以自己任意處理 
  3. “unknown”方法的調用,也許是實現你自己的“虛擬”命令。試着在命令行裏打如下的內容: 
  4.  
  5. invoke(name,args) { print("Command: "+name+" invoked!"); } 
  6. noSuchMethod(); // 打印 "Command: noSuchMethod() invoked!" 

運行效果

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章