免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
從HTTL模板引擎看軟件設(shè)計(jì)原則

HTTL (Hyper-Text Template Language) 是一個(gè)高性能的開(kāi)源JAVA模板引擎, 適用于動(dòng)態(tài)HTML頁(yè)面輸出, 可替代JSP頁(yè)面, 指令和Velocity相似。作者是阿里巴巴工程師梁飛,本文是在拜讀了HTTL的設(shè)計(jì)原則之后提煉出的部分通用設(shè)計(jì)原則。

模型劃分原則

按實(shí)體域,服務(wù)域,會(huì)話域劃分。

不管你做一個(gè)什么產(chǎn)品,都一定有一個(gè)被操作的主體,比如:服務(wù)框架管理的Service,任務(wù)框架管理的Task,Spring管理的Bean等,這就是實(shí)體域。

即然有被操作者,就一定有操作者,它管理被操作者的生命周期,發(fā)起動(dòng)作,比如:服務(wù)框架的ServiceInvoker,,任務(wù)框架的TaskScheduler,Spring的BeanFactory等,這就是服務(wù)域。

服務(wù)域發(fā)起動(dòng)作,在執(zhí)行過(guò)程中,會(huì)有一些臨時(shí)狀態(tài)需要存儲(chǔ)交換,比如:Invacation,Execution,Request等,這就是會(huì)話域。

相應(yīng)的,在HTTL中:

  • Engine 為服務(wù)域
    • 它是API的入口,并負(fù)責(zé)實(shí)體域Template的生命周期管理,它是Singleton單一實(shí)例的,加載后不可變,所以是線程安全的,它的初始化過(guò)程較重,請(qǐng)復(fù)用單例。
  • Template 為實(shí)體域
    • 代表著被操作者,它是Prototype原型實(shí)例的,即每個(gè)模板產(chǎn)生一個(gè)實(shí)例,加載后不可變,同樣也是線程安全的,模板變化后,將產(chǎn)生不同的實(shí)例,而不改變?cè)瓕?shí)例。
  • Context 為會(huì)話域
    • 持有操作過(guò)程中的所有可變狀態(tài),它是ThreadLocal線程內(nèi)實(shí)例的,即不和其它線程競(jìng)爭(zhēng)使用,所以也是線程安全的,請(qǐng)不要跨線程傳遞,它的初始化過(guò)程很輕量,每次模板執(zhí)行前都新建實(shí)例,執(zhí)行完即銷(xiāo)毀。

這樣劃分的好處是,職責(zé)清晰,可變狀態(tài)集中,每個(gè)域都是無(wú)鎖線程安全的,保證在大并發(fā)下,不會(huì)降低系統(tǒng)的活性。

這些核心領(lǐng)域模型也就是HTTL的API(Application Programming Interface),它是HTTL暴露給用戶的最少概念,也就是上面類(lèi)圖中的第一列。

擴(kuò)展點(diǎn)組裝原則

按“微核 插件”體系組裝。

但凡有生命力的產(chǎn)品,都是在擴(kuò)展性方面設(shè)計(jì)的比較好的,因?yàn)闆](méi)有哪個(gè)產(chǎn)品可以覆蓋所有需求,對(duì)于開(kāi)源軟件尤其如此。

所以,產(chǎn)品只有具有良好的擴(kuò)展性,允許用戶或第三方參與進(jìn)來(lái),進(jìn)行二次開(kāi)發(fā),才能保持生命力。

怎么樣的擴(kuò)展性才是最好的?通常來(lái)講,就是沒(méi)有任何功能是硬編碼的,所有的功能都可被用戶替換。

那要如何才能做到這樣?一個(gè)重要的原則就是:平等對(duì)待第三方。

也就是凡是原作者能實(shí)現(xiàn)的功能,第三方也要能夠在不改變?cè)创a的前提下實(shí)現(xiàn)。

換言之,原作者應(yīng)把自己也當(dāng)作擴(kuò)展者,自己添加功能時(shí),也要用第三方擴(kuò)展者同樣的方式進(jìn)行,而不要有特權(quán)。

要做到這一點(diǎn),就需要一個(gè)良好的框架支撐,“微核 插件”是一個(gè)不錯(cuò)的選擇,Eclipse, Maven等知名軟件都采用該體系。

什么是“微核 插件”?微核,即最小化核心,內(nèi)核只負(fù)責(zé)插件的組裝,不帶任何功能邏輯,所有功能都由可替換的插件實(shí)現(xiàn),

并且,組裝過(guò)程應(yīng)基于統(tǒng)一的規(guī)則,比如基于setter注入,而不能對(duì)不同插件硬編碼組裝,這樣可以確保沒(méi)有任何功能在內(nèi)核中硬編碼。

比如:Spring, OSGI, JMX, ServiceLoader等都是常見(jiàn)的微核容器,它們負(fù)責(zé)基于統(tǒng)一規(guī)則的組裝,但不帶功能邏輯。

當(dāng)然,如果你不想帶這么重的框架,也可以自行實(shí)現(xiàn),HTTL就采用自行實(shí)現(xiàn)的httl.util.BeanFactory作為組裝微核。

在Engine.getEngine()中調(diào)用了BeanFatory.createBean(Engine.class, properties),

其中,properties即為httl.properties配置,BeanFatory基于setter方法,遞歸注入所有對(duì)象的屬性。

比如:httl.properties中配置了parser=httl.spi.parsers.CommentParser,

而DefaultEngine中有setParser(Parser parser)方法,就會(huì)被注入,并且Parser本身的屬性也會(huì)遞歸注入。

如果你需要擴(kuò)展或替換HTTL的實(shí)現(xiàn),請(qǐng)參見(jiàn):擴(kuò)展集成

既然非功能性的插件組裝過(guò)程,可以由微核框架來(lái)完成,那功能性的組裝怎么辦呢?

我們應(yīng)該把功能性的組裝過(guò)程也封裝成插件,即讓大插件組裝小插件,形成級(jí)聯(lián)組裝關(guān)系。

比如,HTTL的入口類(lèi)Engine的實(shí)例也是一個(gè)插件,它負(fù)責(zé)模板的緩存,加載,解析的總調(diào)度,即你可以替換DefaultEngine實(shí)現(xiàn)。

只需在httl.properties中配置:engine=com.your.YourEngine,可以將現(xiàn)有Parser等SPI注入你的Engine。

這些插件的接口,也就是HTTL的SPI(Service Provider Interface),它是HTTL暴露給擴(kuò)展者的最小粒度的替換單元,也就是上面類(lèi)圖中的第二列。

整體分包原則

按復(fù)用度,抽象度,穩(wěn)定度分包。

  • 復(fù)用度:
    • 每種用戶所需用到的類(lèi),就是同一復(fù)用粒度的,比如:使用者和擴(kuò)展者,這樣可以減少代碼干擾,以及最大化復(fù)用。
  • 穩(wěn)定度:
    • 被依賴包和依賴包的占比,如果一個(gè)包依賴很多包,那別的包變化都會(huì)引起它跟隨變化,所以它就不穩(wěn)定,反之即穩(wěn)定, 保持被依賴者總是比依賴者的穩(wěn)定度高,形成金子塔關(guān)系,這樣可以防止不穩(wěn)定性傳染,比如a包只依賴3個(gè)包,而b包依賴10個(gè)包,那就不要讓a包去依賴b包。
  • 抽象度:
    • 包中抽象類(lèi)個(gè)數(shù)占比,比如包中有10個(gè)類(lèi),其中3個(gè)為抽象類(lèi)(包括接口),則抽象度為3/10, 保持包的穩(wěn)定度和抽象度成正比,即把抽象類(lèi)(包括接口)放到穩(wěn)定的包中,把具體實(shí)現(xiàn)類(lèi)放到不穩(wěn)定的包中,這樣可以保持每層都有足夠的擴(kuò)展性。

穩(wěn)定度與抽象度關(guān)系如下圖:

也就是分包應(yīng)該如下:

其中上面那個(gè)包不依賴其它包。所以它很穩(wěn)定,應(yīng)盡量把抽象類(lèi)或接口放在這一層,

而下面那個(gè)包依賴了三個(gè)包,三個(gè)包變化都會(huì)引起它跟隨變化,所以它是不穩(wěn)定的,應(yīng)盡量把具體實(shí)現(xiàn)類(lèi)放在這一層。

因穩(wěn)定度與抽象度成正比,所以不穩(wěn)定度與抽象度成反比,用反比方便畫(huà)圖,計(jì)算方式如下:

  • (1) I = Ce / (Ca Ce)
    • I: Instability (不穩(wěn)定度)
    • Ca: Afferent Coupling (傳入依賴,也就是被其它包依賴的個(gè)數(shù))
    • Ce: Efferent Coupling (輸出依賴,也就是依賴其它包的個(gè)數(shù))
  • (2) A = Na / Nc
    • A: Abstractness (抽象度)
    • Na: Number of abstract classes (抽象類(lèi)的個(gè)數(shù))
    • Nc: Number of classes (類(lèi)的個(gè)數(shù),包括抽象類(lèi))
  • (3) D = abs(1 - I - A) * sin(45)
    • D: Distance (偏差)
    • I: Instability (不穩(wěn)定度)
    • A: Abstractness (抽象度)

應(yīng)該保持偏差越小越好,即下圖所示交點(diǎn)都落在綠色反比線左右:

基于上面的原則,HTTL的包結(jié)構(gòu)整體上劃分為三層:(對(duì)應(yīng)上面類(lèi)圖中的三列)

  • API (Application Programming Interface)
    • 模板引擎的使用者依賴的接口類(lèi),也是核心領(lǐng)域模型所在,保持最少概念,并隱藏實(shí)現(xiàn)細(xì)節(jié),其中Engine類(lèi)相當(dāng)于微內(nèi)核,只管理非功能性的擴(kuò)展點(diǎn)的加載,不硬編碼模板加載解析渲染的任何部分。
  • SPI (Service Provider Interface)
    • 模板引擎的擴(kuò)展者依賴的接口類(lèi),它依賴于API的領(lǐng)域模型,它是模板引擎功能正交分解的抽象層,以保證用戶可以最小粒度替換需要改寫(xiě)的地方,方便二次開(kāi)發(fā)。
  • BUILT-IN (Built-in Implementation)
    • 內(nèi)置擴(kuò)展實(shí)現(xiàn),它是SPI標(biāo)準(zhǔn)實(shí)現(xiàn),也是可被用戶替換的類(lèi),它包含引擎所有做的事,包括擴(kuò)展點(diǎn)之間的組裝過(guò)程(可替換DefaultEngine),以確保沒(méi)有功能換不掉,即平等對(duì)待擴(kuò)展者。

采用子包依賴父包風(fēng)格,所以將API放在根目錄,SPI接口獨(dú)立子包,各種實(shí)現(xiàn)放在SPI的下一級(jí)子包中。

  • 使用者API導(dǎo)入:import httl.*;
  • 擴(kuò)展者SPI導(dǎo)入:import httl.spi.*;

下圖是HTTL所有包的不穩(wěn)定度與抽象度的比值距陣:(下圖為JDepend繪制)

HTTL所有核心包都是靠近反比線的,即上圖中用綠色標(biāo)識(shí)的點(diǎn),表示分包是合理的。

注:圖中黑色的點(diǎn)為util相關(guān)包,它們不抽象,卻被很多包依賴,只是內(nèi)部復(fù)用代碼,不影響整體設(shè)計(jì),用戶請(qǐng)不要依賴HTTL的util類(lèi)。

來(lái)源:http://www.icode9.com/content-4-120101.html
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
類(lèi)加載器
深入探討 Java 類(lèi)加載器
ClassLoader(2)Boot、App、Ext、線程加載器
【golang詳解】go語(yǔ)言GMP(GPM)原理和調(diào)度
android中的LaunchMode詳解
Java的四種線程池
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服