http://pt2club.blogspot.com/search/label/GWT
有幾篇粗劣的入門文章可以稍微略知一二
===============================================================
網頁版:
http://pt2club.blogspot.com/2010/02/gwt-part-2javascript-overlay-type.html
==========================[正文開始]===========================
原文:http://googlewebtoolkit.blogspot.com/
2008/08/getting-to-really-know-gwt-part-2.html
技術校正、審閱:tkcn
假設你已經在 GWT module 當中,愉快地使用 JSNI 來呼叫某些手寫的
JavaScript。一切運作正常,但是 JSNI 只能在獨立的 method 下運作。某些整
合性狀況需要你徹底地把 JavaScript 跟 Java 的 object 綁在一起——寫 DOM
跟 JSON 就是兩個好例子——所以我們十分需要可以從 Java 程式碼直接與
JavaScript object 互動的方法。換句話說,我們想要 JavaScript 的 object
看起來就像我們寫的 Java object。
GWT 1.5 引入了 JavaScript overlay type,這讓 GWT 程式整合各種
JavaScript object 變得容易許多。這個技術有很多好處,像是讓你能用 Java
IDE 的 code completion 跟 refactoring 功能,即使你寫的是 untype 的
JavaScript object。
範例:簡單、有效率的 JSON
用一個範例來瞭解 overlay type 是最簡單的方法。假設我們要存取一組「
customer」數據,底層是用 JSON object。在 JavaScript 中的資料結構可能像
這樣:
void jsonData = [
{ "FirstName" : "Ps", "LastName" : "Monkey" },
{ "FirstName" : "痞子", "LastName" : "猴" },
{ "FirstName" : "Pt2", "LastName" : "Club" },
{ "FirstName" : "STO", "LastName" : "Orz" },
];
要把一個 Java type 加到上述的資料結構,要從建立一個 JavaScriptObject
的 subclass 開始,這在 GWT 表示是一個 JavaScript 的 object。接著增加一
些 getter。
// An overlay type
class Customer extends JavaScriptObject {
// Overlay types always have protected, zero-arg ctors
protected Customer() { }
// Typically, methods on overlay types are JSNI
public final native String getFirstName() /*-{
return this.FirstName;
}-*/
public final native String getLastName() /*-{
return this.LastName;
}-*/
// Note, though, that methods aren't required to be JSNI
public final String getFullName() {
return getFirstName() + " " + getLastName();
}
}
如此一來,GWT 就會瞭解所有 Customer 的 instance 實際上是來自 GWT
module 以外的 JavaScript object。這包含了很多意義。舉例來說,看到
getFirstName() 跟 getLastName() 裡頭的 this reference。它實質上是代表
一個 JavaScript object,所以你操作這個 this 就像在 JavaScript 裡頭一樣
。在這個例子中,我們可以直接存取 JSON 中那些我們已知的 field:
this.FirstName 跟 this.LastName。
那麼,你要如何才能真正得到一個被包裝成 Java type 的 JavaScript object
呢?你不能用 new Customer() 來建構它,因為重點是把一個既有的
JavaScript object 包裝成 Java type。因此,我們必須使用 JSNI 來得到這樣
一個 object:
class MyModuleEntryPoint implements EntryPoint {
public void onModuleLoad() {
Customer c = getFirstCustomer();
// Yay! Now I have a JS object that appears to be a Customer
Window.alert("Hello, " + c.getFirstName());
}
// Use JSNI to grab the JSON object we care about
// The JSON object gets its Java type implicitly
// based on the method's return type
private native Customer getFirstCustomer() /*-{
// Get a reference to the first customer in the JSON array from earlier
return $wnd.jsonData[0];
}-*/;
}
現在來搞清楚我們做了啥。我們拿到了一個 plain old JSON object(譯註:源
自於 POJO)並且建立一個看起來很正常的 Java type,讓 GWT 程式碼中能夠使
用它。於是你就有了 code completion、refactoring、compile 階段的檢查——
這些寫 Java 時所擁有的好處。然而,你還是可以靈活地操作任何 JavaScript
object,這使得存取 JSON service(使用 RequestBuilder)變得很輕而易舉。
為一些 compiler 強者岔題一下。overlay type 另一個美妙的事情是你可以增
加 Java 的 type,但是卻不用影響底層的 JavaScript object。注意到上面例
子中,我們加入的 getFullName() 這個 method。它是純粹的 Java 程式碼(並
不存在於底層的 JavaScript object),但卻是依照底層 JavaScript object
所寫的。也就是說,處理同一個 JavaScript object,以 Java 的角度會比用
JavaScript 功能豐富得多;而且不用動到底層的 JavaScript object——無論
是 instance 或是 prototype。
(接續上一段的題外話)在 overlay type 增加 method 這個很酷的怪招是可行
的,因為 overlay type 的設計規則是不允許 polymorphic 呼叫,所有的
method 必須是 final 且/或 private。因此,compiler 是靜態地解讀每一個
overlay type 的 method,所以不需要在 runtime 的時候動態 dispatch。這是
為甚麼我們不用拘泥在 object 的 function pointer;compiler 可以直接對
method 呼叫,就好像是 global function、獨立於 object 之外。很明顯的,
直接呼叫 function 會比間接快得多。更棒的是,因為呼叫 overlay type 的
method 是靜態解讀的,這些動作會嘗試自動 inline;這在為了 script 語言的
效率而奮戰時,是非常強大的火力支援。接下來我們會重新來一遍,展示給你看
這個方法有多成功。
範例:lightweight collection
我們在上面的例子當中掩蓋了某些事情。getFirstCustomer() 這個 method 是
非常不切實際的。你一定會希望存取全部的 customer 陣列。所以,我們需要一
個 overlay type 來表示這個 JavaScript 陣列。幸運的是,這很簡單:
//泛型在 overlay type 裡頭也運作正常!
class JsArray<E extends JavaScriptObject> extends JavaScriptObject {
protected JsArray() { }
public final native int length() /*-{ return this.length; }-*/;
public final native E get(int i) /*-{ return this[i]; }-*/;
}
現在我們可以寫出更有趣的程式了:
class MyModuleEntryPoint implements EntryPoint {
public void onModuleLoad() {
JsArray<Customer> cs = getCustomers();
for (int i = 0, n = cs.length(); i < n; ++i) {
Window.alert("Hello, " + cs.get(i).getFullName());
}
}
// Return the whole JSON array, as is
private final native JsArray<Customer> getCustomers() /*-{
return $wnd.jsonData;
}-*/;
}
這是一個很乾淨的程式碼,尤其是以建立靈活配置的角度來看。正如上頭提到的
,compiler 可以作一些十分 fancy 的事情,讓它相當有效率。看一下
onModuleLoad() 這個 method 在沒有 obfuscate 的 compile 結果:
function $onModuleLoad(){
var cs, i, n;
cs = $wnd.jsonData;
for (i = 0, n = cs.length; i < n; ++i) {
$wnd.alert('Hello, ' + (cs[i].FirstName + ' ' + cs[i].LastName));
}
}
這個最佳化真的是 xx 的好。即使是 getFullName() 這個 method 的 overhead
也沒了。事實上, 所有 Java method 的呼叫動作都不見了。當我們說:「GWT
給你可負擔的 abstraction」,這就是其中之一。不僅 inline 的程式碼執行速
度明顯變快、我們不再需要定義 function 的內容、也因而得以將 script 簡短
化(雖然持平而論,inline 的方式也很容易讓 script 量變多,所以我們小心
地在速度與程式碼大小之間取得平衡)。現在回顧上頭原始的 Java 程式碼是十
分有趣的,而試著推導 compiler 最佳化的步驟就展示到這邊。不過,我們還是
忍不住要 show 一下對應、obfuscate 過的程式碼:
function B(){var a,b,c;a=$wnd.jsonData;for(b=0,c=a.length;b<c;
++b){ $wnd.alert(l+(a[b].FirstName+m+a[b].LastName))}}
注意在這個版本當中,唯一沒有 obfuscate 的是 JavaScript 當中的識別字,
例如 FirstName、 LastName、jsonData 等。這是為甚麼即使 GWT 努力讓大量
JavaScript 交互溝通的操作變得容易,但我們還是努力說服別人盡量用純 Java
來寫程式、而不是混著 JavaScript 寫。希望你聽到我們講這些之後,你會明白
我們不是要打擊 JavaScript——只是我們不能對它們最佳化,這會讓我們很沮
喪。
摻在一起作撒尿牛丸
overlay type 是 GWT 1.5 的重要特性。這個技術讓直接與 JavaScript
library 互相溝通變得相當容易。希望在讀完這篇文章之後,你可以想像如何以
一組 Java type 直接導入任何 JavaScript library 到 GWT 裡頭,進而使用
Java IDE 來進行高效率的開發跟 debug,卻不會因為任何類型的 GWT overhead
而影響程式碼大小或執行速度。同時,overlay type 作為一個強大的
abstraction 工具,提供更優雅的低階 API,例如新的 GWT DOM package 。
--
錢鍾書: 說出來的話
http://www.psmonkey.org
比不上不說出來的話
Java 版 cookcomic 版
只影射著說不出來的話
and more......
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.228.193.140
GWT 一直處在一個很尷尬的角色
我一直不知道該放在 Java 版還是在 Ajax 版討論
之前都是在介紹 or 教學,跟 JavaScript 還沒啥關係
所以就都放在 Java 版
這篇因為談到了 GWT 處理 JavaScript object 的思維
所以就貼在這裡
或許對於 JavaScript 感到厭煩的卻又不得不寫的人
這是一條生路.... [炸]
如果想了解 GWT 的版友,可以到