| HTTL (Hyper-Text Template Language) 是一個高性能的開源JAVA模板引擎, 適用于動態(tài)HTML頁面輸出, 可替代JSP頁面, 指令和Velocity相似。作者是阿里巴巴工程師梁飛,本文是在拜讀了HTTL的設(shè)計原則之后提煉出的部分通用設(shè)計原則。 模型劃分原則按實體域,服務(wù)域,會話域劃分。 不管你做一個什么產(chǎn)品,都一定有一個被操作的主體,比如:服務(wù)框架管理的Service,任務(wù)框架管理的Task,Spring管理的Bean等,這就是實體域。 即然有被操作者,就一定有操作者,它管理被操作者的生命周期,發(fā)起動作,比如:服務(wù)框架的ServiceInvoker,,任務(wù)框架的TaskScheduler,Spring的BeanFactory等,這就是服務(wù)域。 服務(wù)域發(fā)起動作,在執(zhí)行過程中,會有一些臨時狀態(tài)需要存儲交換,比如:Invacation,Execution,Request等,這就是會話域。 
 相應(yīng)的,在HTTL中: 
 
 這樣劃分的好處是,職責清晰,可變狀態(tài)集中,每個域都是無鎖線程安全的,保證在大并發(fā)下,不會降低系統(tǒng)的活性。 這些核心領(lǐng)域模型也就是HTTL的API(Application Programming Interface),它是HTTL暴露給用戶的最少概念,也就是上面類圖中的第一列。 擴展點組裝原則按“微核 插件”體系組裝。 但凡有生命力的產(chǎn)品,都是在擴展性方面設(shè)計的比較好的,因為沒有哪個產(chǎn)品可以覆蓋所有需求,對于開源軟件尤其如此。 所以,產(chǎn)品只有具有良好的擴展性,允許用戶或第三方參與進來,進行二次開發(fā),才能保持生命力。 怎么樣的擴展性才是最好的?通常來講,就是沒有任何功能是硬編碼的,所有的功能都可被用戶替換。 那要如何才能做到這樣?一個重要的原則就是:平等對待第三方。 也就是凡是原作者能實現(xiàn)的功能,第三方也要能夠在不改變源代碼的前提下實現(xiàn)。 換言之,原作者應(yīng)把自己也當作擴展者,自己添加功能時,也要用第三方擴展者同樣的方式進行,而不要有特權(quán)。 要做到這一點,就需要一個良好的框架支撐,“微核 插件”是一個不錯的選擇,Eclipse, Maven等知名軟件都采用該體系。 
 什么是“微核 插件”?微核,即最小化核心,內(nèi)核只負責插件的組裝,不帶任何功能邏輯,所有功能都由可替換的插件實現(xiàn), 并且,組裝過程應(yīng)基于統(tǒng)一的規(guī)則,比如基于setter注入,而不能對不同插件硬編碼組裝,這樣可以確保沒有任何功能在內(nèi)核中硬編碼。 比如:Spring, OSGI, JMX, ServiceLoader等都是常見的微核容器,它們負責基于統(tǒng)一規(guī)則的組裝,但不帶功能邏輯。 當然,如果你不想帶這么重的框架,也可以自行實現(xiàn),HTTL就采用自行實現(xiàn)的httl.util.BeanFactory作為組裝微核。 在Engine.getEngine()中調(diào)用了BeanFatory.createBean(Engine.class, properties), 其中,properties即為httl.properties配置,BeanFatory基于setter方法,遞歸注入所有對象的屬性。 比如:httl.properties中配置了parser=httl.spi.parsers.CommentParser, 而DefaultEngine中有setParser(Parser parser)方法,就會被注入,并且Parser本身的屬性也會遞歸注入。 如果你需要擴展或替換HTTL的實現(xiàn),請參見:擴展集成 既然非功能性的插件組裝過程,可以由微核框架來完成,那功能性的組裝怎么辦呢? 我們應(yīng)該把功能性的組裝過程也封裝成插件,即讓大插件組裝小插件,形成級聯(lián)組裝關(guān)系。 
 比如,HTTL的入口類Engine的實例也是一個插件,它負責模板的緩存,加載,解析的總調(diào)度,即你可以替換DefaultEngine實現(xiàn)。 只需在httl.properties中配置:engine=com.your.YourEngine,可以將現(xiàn)有Parser等SPI注入你的Engine。 這些插件的接口,也就是HTTL的SPI(Service Provider Interface),它是HTTL暴露給擴展者的最小粒度的替換單元,也就是上面類圖中的第二列。 整體分包原則按復用度,抽象度,穩(wěn)定度分包。 
 穩(wěn)定度與抽象度關(guān)系如下圖: 
 也就是分包應(yīng)該如下: 
 其中上面那個包不依賴其它包。所以它很穩(wěn)定,應(yīng)盡量把抽象類或接口放在這一層, 而下面那個包依賴了三個包,三個包變化都會引起它跟隨變化,所以它是不穩(wěn)定的,應(yīng)盡量把具體實現(xiàn)類放在這一層。 因穩(wěn)定度與抽象度成正比,所以不穩(wěn)定度與抽象度成反比,用反比方便畫圖,計算方式如下: 
 應(yīng)該保持偏差越小越好,即下圖所示交點都落在綠色反比線左右: 
 基于上面的原則,HTTL的包結(jié)構(gòu)整體上劃分為三層:(對應(yīng)上面類圖中的三列) 
 采用子包依賴父包風格,所以將API放在根目錄,SPI接口獨立子包,各種實現(xiàn)放在SPI的下一級子包中。 
 下圖是HTTL所有包的不穩(wěn)定度與抽象度的比值距陣:(下圖為JDepend繪制) 
 HTTL所有核心包都是靠近反比線的,即上圖中用綠色標識的點,表示分包是合理的。 注:圖中黑色的點為util相關(guān)包,它們不抽象,卻被很多包依賴,只是內(nèi)部復用代碼,不影響整體設(shè)計,用戶請不要依賴HTTL的util類。來源:http://www./content-4-120101.html | 
|  |