關于面向構件的一些思考
一、xml和元數據解決了接口脆弱性問題嗎?
其實面向構件的基本理念和傳統的模塊、對象并沒有大的區別,我們的目標仍然是把“大問題”分解成“小問題”來解決。那我們為什么需要面向構件呢?關鍵是我們要重用對“小問題”的解決,來解決新的“大問題”。
傳統的問題分解手段為什么在重用上有問題呢?關鍵在于黃柳青博士說說的“接口脆弱性”問題:在新的上下文之下,同一個“小問題”的解決往往略有一點差異。就是這點差異,我們沒有辦法直接重用原來的模塊,必需“略微”改變一下接口,添加一個新的參數,這樣這個模塊往往就和原來的模塊無法兼容了(如果想保持兼容,就要修改對原來的模塊的引用,這又帶來了新的問題)。下次我們再想重用的時候,也許又需要添點不同的玩意兒了,如果上次添的玩意兒還有用,就在上次的的基礎上改,不然就在舊的模塊上面改……
那么,標簽數據和xml真的能解決我們遇到的問題嗎?我們假設一個場景來看看:
首先,我做一個模塊來計算個人所得稅,接口很簡單,接受一個金額,按照預定的公式計算出所得稅額,輸出計算出來的金額。在第一個產品里面這個模塊工作的很好。
接著,有一個新的產品也需要計算個人所得稅,那么理所當然我們會重用這個模塊,不過這次的需求有點不同,我的新客戶的雇員里面有外籍雇員,對外籍雇員我們的計算方式有點不同。那么現在接口需要添加一個國籍字段。
又來一個單子。我們這個新客戶也有外籍雇員,而且這些外籍雇員還有不同的簽證類型,臨時工作簽證和長期工作簽證的稅率又有不同,這次我們需要添加一個簽證類型字段……
如果我們用傳統的接口,那么我們一開始會這樣寫接口:
currency incomeTax(currency salary)
第二次則是
currency incomeTax(currency salary, Nationality nationality)
第二次則是
currency incomeTax(currency salary, Nationality nationality, VisaType visaType)
很顯然,我們在重用的時候會遇到麻煩。
換種方式寫接口,也許會有幫助
第一次:
currency incomeTax(Parameter parameter)
第二次:
currency incomeTax(Parameter parameter)
第三次:
currency incomeTax(Parameter parameter)
通過Parameter的多態,我們可以保持住接口。在函數里面我們可以判斷Parameter的類型來決定怎么計算。這樣做有兩個主要問題,一是我們需要多維護一組Parameter類,二是有人說如果我們試圖在計算的時候先判斷參數類型的話,先賞自己兩耳光。
Ok,看來我們還需要更寬松的接口,那么還可以這樣
第一次:
currency incomeTax(Map parameter)
第二次:
currency incomeTax(Map parameter)
第三次:
currency incomeTax(Map parameter)
最后如果用xml,我們會得到:
第一次:
currency incomeTax(String parameterXML)
第二次:
currency incomeTax(String parameterXML)
第三次:
currency incomeTax(String parameterXML)
我們可以看到,這個接口和Map接口實質上沒有區別,一個可以做到的原則上另一個也可以,但是使用上有兩點區別:一是Map容器里面我們可以放任意的對象,而用xml的話我們要用String來表示一切,因此還要在調用過程中進行編碼、解碼(想像一下拿一部電影做base64編碼吧);二是即使傳遞的都是簡單的串,Map容器里面的數據可以快速的引用,而xml的數據我們要分析xml來獲?。ǜ灰fjava在解析xml方面確實不占優勢,剛聽說java在一個測試中敗給.net就是被xml性能低下所拖累)。
我們再看看接口脆弱性是不是真的被解決了。不錯,在一致的接口之下,我們幾乎始終都可以進行有效的調用,在處理接口參數的時候自適應各種數據,用默認值代替缺少的參數。但是這樣做的代價就是我們失去了編譯期參數檢查的好處,并且在接口發生變化的時候沒有辦法(至少我想不出辦法)提醒接口的潛在使用者。還是用前面的例子。在我們添加“國籍”這個參數的時候,用傳統的方式,函數的調用者會知道,但是不管是用map還是用xml,我們只能在沒有接收到nationality參數的時候使用默認值Chinese,但是可以想像很多開發人員并不知道計算所得稅的時候還要知道國籍。我們怎么防止模塊的使用者在傳遞一個外國雇員的數據時忘了傳遞國籍呢?我能想得出的最好的辦法也只是把這個問題列入潛在問題清單里面,在code review的時候人工檢查。
嚴格的接口定義,可以讓機器幫助我們維持我們的正確性,但是犧牲的是靈活性和可重用性。寬松的接口在帶來靈活性和可重用性的同時,付出的代價是犯錯誤的可能性和排錯的困難性。
使用xml的額外的好處是,我們可以很容易的在不同的平臺和語言之間交互,但是至少在現在,我看不到這個優勢能有任何體現:EOS好像完全是java開發的。
因此,我看不出xml+元數據在解決接口脆弱性上的銀彈般的神奇共用,在我看來,它甚至不如相對比較傳統的Map接口。
很遺憾的是,關于EOS的“總線”概念我現在沒有辦法搜集的足夠的資料,我很不理解xml數據是在什么樣的一條“總線”上流動的,而Map形式的數據包在這樣一條“總線”上是否能夠發揮相同的作用 。