2009年4月28日 星期二

Why Interface? 下集: 海大王的堅持

接著進入主題了,也是解釋為何我如此感嘆的原因。
我的報告結束後,一位海大的王教授,就叫他海大王吧!對我的設計提供了諸多指教。
我們來看看他說了什麼:

海大王觀點下的問題
CustomerMgr 跟 HotelMgr 你用 UML 裡面的 Component 圖示來表示, Component 怎麼可以被繼承。

看來這位平常都不怎麼發表意見的海大王,今天突然變得很精確,看來今天是衝著我來的。
首先我同意他的講法, Component 不會被繼承,沒有人在繼承一個 EJB 的 jar 檔吧?應該是繼承這個 jar 裡面的某個 class ,其實我想表達的也是這個意思而已,但我這樣畫你就看不懂我的梗了喔?應該不至於這麼沒有慧根吧?
我最重要的梗是:「不要為了 Referential Integrity 而改 CustomerMgr ,而應該 extend 他」,這個這麼重要的梗竟然看不到,反而只看到表面的瑕疵?
如果是黃阿公看到一定會很開心的說:這就是我這學期一直強調的 Open/Close Principle 。

海大王堅持
Component 去用 Component 外的東西一定要透過 Interface , Component 被用,也應該透過 Interface ,你的 Interface 在哪裡?

然後我解釋後,他 Repeat 他對 Interface 的堅持,感覺他頗激動,不知是什麼動力讓他如此激動地堅持他的膚淺?

我想他應該是在批評我 ChildCustomerMgr 直接去用 Subject ,沒有透過 Interface ,還有就是批評我 DeploymentMechanism 頭上的那兩條虛線箭頭,沒有透過 Interface 。
我跟他解釋, Subject 跟 Observer 我都假設他屬於 Framework 的一部份,可以直接用,不需要透過 Interface 。

用 Framework 可透過 Interface ,可透過繼承 Framework 中的 Abstract Class ,也可直接用 Framework 裡的 Concrete Class 。
這邊講的 Framework 是比較廣義的 Framework ,如 .Net Framework , Spring Framework , Struts Framework ,狹義的 Framework 應該是比喻成 Abstract Class 比較恰當。

但這位海大王,真的非常堅持 Component 要用 Component 以外的東西一定要透過 Interface ,這樣的意思就是:
我的 Component 要用 .Net Framework 裡面的 string 要透過介面。
我的 Component 要用 Java 的 LinkedList, TreeSet, TreeMap 也要透過介面。
Java 本身就提供 Subject 這種 Class 給我們使用,在 Java 叫做 Observable ,他是一個 Concrete Class ,我難道要用 Java 本身提供的東西或 .Net 本身提供的東西都還要透過 Interface ?如果是這樣,應該寫不出任何程式來吧?

我真的笑了...
好一個死讀書的海大王阿!
課本怎麼說的倒是不加思索直接輸入腦袋裡了,也不思考一下課本是不是真的想傳達那個意思給你。

至於 DeploymentMechanism 頭上的那兩條虛線,需不需要透過 Interface ,我覺得無妨,反正我之前提過了, ChildCustomerMgr, ChildHotelMgr, HotelMgrObserverCustomer 這三個 Class 都是 Deploy 的時候,由 Container Gen 出來的,而 DeploymentMechanism 也是 Container 的一部份,大家都自己人,幹嘛還透過 Interface 。

而且,透過這樣 Business Technology 分開的設計,以及 Code Gen 的機制,我真正寫 Code 的時候我只會看到 Business 框框裡面的那三個元件,完全符合海大王的要求,要透過 Interface ,只有到 Deploy 的時候, Container 才會幫我把 Technology 框框裡面的 Code Gen 出來,因此 Developer 、 User 、 Tester 都感覺不出有下面那個框框的存在,那我下面框框的部分有沒有透過 Interface 到底影響到誰了?應該不會有影響吧?


Why Interface?
海大王對 Interface 非常堅持,但他到底有沒有仔細想過,使用 Interface 帶來了什麼好處?
我覺得有必要說明一下 Interface 的用途,避免海大王迷思未來持續上演。

Interface 在 Component Base Software 上,最明顯的好處之一就是:讓你的元件可以拆下來,換成一個新元件,只要新元件的 Interface 一樣,就隨插即用。

Component Base Software 的梗也就是這個,這學期快完了,三位助教努力的在台上表演,但我卻一直沒聽到他們提這個最重要的梗,其實也讓我頗心寒的。

參透不深者一講到 Component Base Software 一定會講:「好處是 Reuse ,因為同一個 Component 寫完了以後可以賣給別人 Reuse ,也可以給下一個專案 Reuse 。」這是大部分學生的答案,因為老師課本就這樣教,他們也就像海大王一樣不加思索直接輸入腦袋裡了。

但實務上,業界那個 Component 被 Reuse 了?尤其是 business component ,根本連個鬼影子都看不到。

我認為 Replaceable 才是 Component 最重要的梗,因為 Replaceable 超越了傳統 reuse 的思維!
我引述一位前輩講的話來說明,什麼叫做超越傳統 reuse 的思維,這個前輩叫做高煥堂,幾年前有幸聽他幾堂課,給了我一些指點,讓我早幾年參透一些事情,他說:

汽車是一個系統,輪胎是這個系統裡面的一個 Component ,我今天輪胎壞了,我去買一顆新輪胎來換,換了輪胎後,我 Reuse 了整台車。

想想看,如果今天輪胎是不能拆下來的,輪胎壞了你車還能開嗎?是不是整台車就丟了?
再買一台新車?為了一個破輪胎買一台車?真是極度不合理阿!

所以在真實世界,被 reuse 的不是 component 本身, component 是被換下來淘汰的,真正 reuse 的是沒被淘汰的其他部分。

不只 component ,只要你覺得未來可能會需要被換掉的東西,最好都要透過介面來使用他,隨便翻個 Design Pattern 就會發現,都在講這個梗。

因此,什麼時候要透過 Interface 呢? Interface 使用的時機呢?當然就是你 suppose 那個東西在不久的將來會被換掉,為了換掉的時候不造成太大的痛苦,給他個 Interface ,讓他未來比較容易被換掉。

那你的 Component 使用 .Net Framework 或使用一些 J2EE Framework ,或你自己寫的 Framework ,的時候要不要透過 Interface ?就看你未來會不會把他換掉。

基本上換掉的機會不大,因為 Framework 構成了你系統的骨幹,要換通常工程浩大,所以 Framework 通常是被 Reuse 的,而且是被重度依賴的,如果用 Framework 都還要透過 Interface ,那也太多 Interface 了吧,而且最終總要用到幾個 Concrete Class ,要不然誰幫你把物件 create 出來阿?(高手應該聽得出來我在影射那個 Design Pattern 吧...)

因此海大王堅持用 Framework 也要透過 Interface 似乎是...我真不知道他在想什麼...

那你今天用了 .Net Framework 有辦法做到不改一支程式,換成 J2EE 嗎?其實也可以啦,但是就不是 Interface 可以幫你的了,有興趣請參考 Model Driven Architecture ,黃阿公有開課,作法就是用 Code Gen 的方式。

你有沒有注意到跟我的設計又有點符合處?又是 Code Gen !因為要做到 Plug and play ,除了 Interface 這招以外, Code Gen 也是一招。
有沒有看過類似的科幻電影,一個怪物手斷了,他就從地上檢起一隻備用的庫存手,靠近他的斷臂,說也奇怪,斷臂跟這隻備用手竟然長出骨肉連了起來,然後就可以用手了。
OK...以上科幻電影是我虛構的,但...有點想像力嘛...

這也是我前面所說的 DeploymentMechanism 為何不需要透過 Interface 來使用 ChildCustomerMgr, HotelMgrObserverCustomer ,因為他用 Code Gen 這種方法來完成 plug and play 阿!我還需要 Interface 嗎?

也因為 Code Gen 的機制,一個 EJB Component 可以保持 Container 的中立性,也就是說,今天你寫的 EJB 可以 Run 在 WebSphere ,也可以 Run 在 WebLogic ,也可以 Run 在 Jboss ,因為你 Deploy 的時候, Container 才會依照他的方式,把你留給 Container 發揮的程式碼 Gen 出來,每個 Container Gen 出來的 Code 不盡相同,但都 extend 你的 Component 。

跟 MDA 的 Code Gen 比較不同的是, MDA 的 Code Gen 比較絕,全部幫你 Gen 出整個系統來,當然,理論上。 EJB 這種 Code Gen 機制則只幫你 Gen 出你懶得寫的部分,比如說 Transaction 控制、 Persistence Code 、 Referential Integity Code,等等...
但目前為止,應該還沒有一個 Container 有 Gen Referential Integity Code ,應該是未來 Container 的一個發展方向。

另外,嚴格的說, EJB Component 還是會留一個 Interface 給 Container 所使用,讓每個 Container 都能以相同的介面來管理這些 Container ,但如果沒這些介面,應該也 OK ,還是可以做到 Plug and play ,只是管理 Component 的方法會變得比較千奇百怪,不統一,也比較容易造成 Container 的品質不一致,所以這裡也引出了 Interface 的另一個用途,「可以用來規範 Implementation 」,但這個用途就沒促成 Replaceable 那麼重要了。

總結

其實上課的第一天,海大王對平行四邊形應該要繼承四角形還是繼承矩形跟我就有不同的見解,他的答案就是:應該要看幾何學的定義,平行四邊行屬於四角形還是矩形。
我那時候心裡就 Oz :哇!這真的就是某八股物件導向書籍的講法阿!恩﹍這個老師應該有看一些書,四年前的我,搞不好也會講出這麼八股的話。
我的答案是:要看現況被繼承成什麼鬼樣子了,如何設計,才能產生最少的 Side Effect 。總不能為了達成完美幾何學,要我改寫大半個系統吧?

唉,我想我該解釋的都解釋了,比較感嘆的是,如果一個教授做學問都只會照著課本講的堅持,而不去思考 Why ,那教出來的學生呢?
如果海大王真的瞭解課本說的,要透過 Interface 是為了什麼?或許今天也不會那麼激動的堅持他的膚淺吧!我也沒有必要在這邊感嘆到兩點半才睡。

沒有留言:

張貼留言