关于面向构件的一些思考
author:emu(黄希彤)
一、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来获取(更不要说java在解析xml方面确实不占优势,刚听说java在一个测试中败给.net就是被xml性能低下所拖累)。
我们再看看接口脆弱性是不是真的被解决了。不错,在一致的接口之下,我们几乎始终都可以进行有效的调用,在处理接口参数的时候自适应各种数据,用默认值代替缺少的参数。但是这样做的代价就是我们失去了编译期参数检查的好处,并且在接口发生变化的时候没有办法(至少我想不出办法)提醒接口的潜在使用者。还是用前面的例子。在我们添加“国籍”这个参数的时候,用传统的方式,函数的调用者会知道,但是不管是用map还是用xml,我们只能在没有接收到nationality参数的时候使用默认值Chinese,但是可以想像很多开发人员并不知道计算所得税的时候还要知道国籍。我们怎么防止模块的使用者在传递一个外国雇员的数据时忘了传递国籍呢?我能想得出的最好的办法也只是把这个问题列入潜在问题清单里面,在code review的时候人工检查。
严格的接口定义,可以让机器帮助我们维持我们的正确性,但是牺牲的是灵活性和可重用性。宽松的接口在带来灵活性和可重用性的同时,付出的代价是犯错误的可能性和排错的困难性。
使用xml的额外的好处是,我们可以很容易的在不同的平台和语言之间交互,但是至少在现在,我看不到这个优势能有任何体现:EOS好像完全是java开发的。
因此,我看不出xml+元数据在解决接口脆弱性上的银弹般的神奇共用,在我看来,它甚至不如相对比较传统的Map接口。
很遗憾的是,关于EOS的“总线”概念我现在没有办法搜集的足够的资料,我很不理解xml数据是在什么样的一条“总线”上流动的,而Map形式的数据包在这样一条“总线”上是否能够发挥相同的作用author:emu(黄希彤) 。