領(lǐng)域特定語言(domain-specific languages,簡稱DSL)
在定義DSL是什么的問題上,F(xiàn)lowler認(rèn)為目前經(jīng)常使用的一些特征,例如“關(guān)注于領(lǐng)域”、“有限的表現(xiàn)”和“語言本質(zhì)”是非常模糊的。因此,唯一能夠確定DSL邊界的方法是考慮“一門語言的一種特定用法”和“該語言的設(shè)計(jì)者或使用者的意圖”:
如果XSLT的設(shè)計(jì)者將其設(shè)計(jì)為XML的轉(zhuǎn)換工具,那么我認(rèn)為XSLT是一個(gè)DSL。如果一個(gè)用戶使用DSL的目的是該DSL所要達(dá)到的目的,那么它一個(gè)DSL,但是如果有人以通用的方式來使用一個(gè)DSL,那么它(在這種用法下)就不再是一個(gè)DSL了。
以Fowler的觀點(diǎn),DSL首先是一種幫助用戶從一個(gè)系統(tǒng)中抽象出某些部分的工具。所以“當(dāng)你意識(shí)到你需要一個(gè)組件,或者當(dāng)你已經(jīng)有了一個(gè)組件而你希望簡化操作它的方式的時(shí)候”,DSL是有用的。使用DSL確實(shí)提供了某些益處。DSL不僅提高了代碼的易讀性,讓開發(fā)者可以和領(lǐng)域?qū)<腋玫慕涣?,而且是改變?zhí)行上下文的一種手段,例如:把邏輯從編譯時(shí)切換到運(yùn)行時(shí),或者當(dāng)命令式編程不是很合適的時(shí)候轉(zhuǎn)用聲明式計(jì)算模型。
DSL包含哪些部分,有哪些分類
DSL主要分為三類:外部DSL、內(nèi)部DSL,以及語言工作臺(tái)。
外部DSL是一種“不同于應(yīng)用系統(tǒng)主要使用語言”的語言。外部DSL通常采用自定義語法,不過選擇其他語言的語法也很常見(XML就是一個(gè)常見選擇)。宿主應(yīng)用的代碼會(huì)采用文本解析技術(shù)對(duì)使用外部DSL編寫的腳本進(jìn)行解析。一些小語言的傳統(tǒng)UNIX就符合這種風(fēng)格??赡芙?jīng)常會(huì)遇到的外部DSL的例子包括:正則表達(dá)式、SQL、Awk,以及像Struts和Hibernate這樣的系統(tǒng)所使用的XML配置文件。
內(nèi)部DSL是一種通用語言的特定用法。用內(nèi)部DSL寫成的腳本是一段合法的程序,但是它具有特定的風(fēng)格,而且只用到了語言的一部分特性,用于處理整個(gè)系統(tǒng)一個(gè)小方面的問題。用這種DSL寫出的程序有一種自定義語言的風(fēng)格,與其所使用的宿主語言有所區(qū)別。這方面最經(jīng)典的例子是Lisp。Lisp程序員寫程序就是創(chuàng)建和使用DSL。Ruby社區(qū)也形成了顯著的DSL文化:許多Ruby庫都呈現(xiàn)出DSL的風(fēng)格。特別是,Ruby最著名的框架Rails,經(jīng)常被認(rèn)為是一套DSL。
語言工作臺(tái)是一個(gè)專用的IDE,用于定義和構(gòu)建DSL。具體來說,語言工作臺(tái)不僅用來確定DSL的語言結(jié)構(gòu),而且是人們編寫DSL腳本的編輯環(huán)境。最終的腳本將編輯環(huán)境和語言本身緊密結(jié)合在一起。
多年來,這三種風(fēng)格分別發(fā)展了自己的社區(qū)。你會(huì)發(fā)現(xiàn),那些非常擅長使用內(nèi)部DSL的人,完全不了解如何構(gòu)造外部DSL。我擔(dān)心這可能會(huì)導(dǎo)致人們不能采用最適合的工具來解決問題。我曾與一個(gè)團(tuán)隊(duì)討論過,他們采用了非常巧妙的內(nèi)部DSL處理技巧來支持自定義語法,但我相信,如果他們使用外部DSL的話,問題會(huì)變得簡單許多。但由于對(duì)如何構(gòu)造外部DSL一無所知,他們別無選擇。因此,在本書中,把內(nèi)部DSL和外部DSL講清楚對(duì)我來說格外重要,這樣你就可以了解這些信息,做出適當(dāng)?shù)倪x擇。(語言工作臺(tái)稍顯粗略,因?yàn)樗鼈兒苄?,尚在演化之中。?/p>
另一種看待DSL的方式是:把它看做一種處理抽象的方式。在軟件開發(fā)中,我們經(jīng)常會(huì)在不同的層面上建立抽象,并處理它們。建立抽象最常見的方式是實(shí)現(xiàn)一個(gè)程序庫或框架。操縱框架最常見的方式是通過命令/查詢式API調(diào)用。從這種角度來看,DSL就是這個(gè)程序庫的前端,它提供了一種不同于命令/查詢式API風(fēng)格的操作方式。在這樣的上下文中,程序庫成了DSL的“語義模型”,因此,DSL經(jīng)常伴隨著程序庫出現(xiàn)。事實(shí)上,我認(rèn)為,對(duì)于構(gòu)建良好的DSL 而言,語義模型是一個(gè)不可或缺的附屬物。
談及DSL,人們很容易覺得構(gòu)造DSL很難。實(shí)際上,通常是難在構(gòu)造模型上,DSL只是位于其上的一層而已。雖然讓DSL 工作良好需要花費(fèi)一定的精力,但相對(duì)于構(gòu)建底層模型,這一部分的付出要少多了。
1. 我們常常會(huì)看到這樣一種劃分:一方面是程序庫/框架或者組件的實(shí)現(xiàn)代碼;另一方面是配置代碼或組件組裝代碼。從本質(zhì)上說,這種做法分開了公共代碼和可變代碼。用公共代碼構(gòu)建一套組件,然后根據(jù)不同的目的進(jìn)行配置。
2. “聲明式”是一個(gè)非常模糊的術(shù)語,但是它通常適應(yīng)于所有遠(yuǎn)離了命令式編程的方式。。。。遠(yuǎn)離變量倒換,用xml的子元素表示狀態(tài)的動(dòng)作和轉(zhuǎn)換。
3. DSL扮演領(lǐng)域?qū)<液蜆I(yè)務(wù)分析人員之間的交流媒介。。。
4. 文本DSL有兩種,稱為外部DSL和內(nèi)部DSL。外部DSL是指,在主程序設(shè)計(jì)語言之外,用一種單獨(dú)的語言表示領(lǐng)域?qū)S谜Z言。內(nèi)部DSL是指,用通用語言的語法表示的DSL;
5. 是什么讓內(nèi)部DSL不同于通常的api呢?。。。連貫接口,這個(gè)術(shù)語強(qiáng)調(diào)這樣一個(gè)事實(shí):內(nèi)部DSL實(shí)際只是某種形式的api,只不過其設(shè)計(jì)考慮了連貫性難以琢磨的質(zhì)量。
xx:后續(xù)在4.1節(jié)還會(huì)論述這個(gè)問題,DSL與api調(diào)用的區(qū)別,從這里看,兩者都提供一種抽象,但DSL在抽象的設(shè)計(jì)上考慮了連貫性。
在講完以上內(nèi)容后,提出DSL由三部分組成,即語言,語義模型和代碼生成。語言只是用一種可讀的方式來組裝語義模型。
6. 我強(qiáng)烈建議,幾乎始終應(yīng)該使用語義模型。。。。語義模型,清晰的將語言解析和結(jié)果語義的關(guān)注點(diǎn)切分開,。。??梢詥为?dú)推究狀態(tài)機(jī)的運(yùn)作機(jī)制,增強(qiáng)和調(diào)試,無須估計(jì)語言。
DSL只是模型一個(gè)薄薄的門面
7.許多人用了代碼生成之后,就舍棄了語義模型,他們在解析 輸入文本之后,就直接產(chǎn)生生成的代碼。。。不推薦任何人這么做。語義模型的存在,可以將解析,執(zhí)行語義以及代碼生成分開。
最后推薦一個(gè)開發(fā)DSL的語言工作臺(tái),MetaEdit
為何需要DSL
DSL只是一種工具,關(guān)注點(diǎn)有限,無法像面向?qū)ο缶幊袒蛎艚莘椒ㄕ撃菢?,引發(fā)軟件開發(fā)思考方式的深刻變革。相反,它是在特定條件下有專門用途的一種工具。一個(gè)普通的項(xiàng)目可能在多個(gè)地方采用了多種DSL——事實(shí)上很多項(xiàng)目這么做了。
DSL有其自身的價(jià)值。當(dāng)考慮采用DSL時(shí),要仔細(xì)衡量它的哪些價(jià)值適合于我們的情況。
1)提高開發(fā)效率
DSL的核心價(jià)值在于,它提供了一種手段,可以更加清晰地就系統(tǒng)某部分的意圖進(jìn)行溝通。拿格蘭特小姐控制器的定義來說,相比于采用命令–查詢API,DSL形式對(duì)我們而言更容易理解。
這種清晰并非只是審美追求。一段代碼越容易看懂,就越容易發(fā)現(xiàn)錯(cuò)誤,也就越容易對(duì)系統(tǒng)進(jìn)行修改。因此,我們鼓勵(lì)變量名要有意義,文檔要寫清楚,代碼結(jié)構(gòu)要寫清晰?;谕瑯拥睦碛?,我們應(yīng)該也鼓勵(lì)采用DSL。
人們經(jīng)常低估缺陷對(duì)生產(chǎn)率的影響。缺陷不僅損害軟件的外部質(zhì)量,還浪費(fèi)開發(fā)人員的時(shí)間去調(diào)查以及修復(fù),降低開發(fā)效率,并使系統(tǒng)的行為異常,播下混亂的種子。DSL的受限表達(dá)性,使其難于犯錯(cuò),縱然犯錯(cuò),也易于發(fā)現(xiàn)。
模型本身可以極大地提升生產(chǎn)率。通過把公共代碼放在一起,它可以避免重復(fù)。首先,它提供了一種“用于思考問題”的抽象,這樣,更容易用一種可理解的方式指定系統(tǒng)行為。DSL提供了一種“對(duì)閱讀和操作抽象”更具表達(dá)性的形式,從而增強(qiáng)了這種抽象。DSL還可以幫助人們更好地學(xué)習(xí)使用API,因?yàn)樗鼘⑷藗兊年P(guān)注點(diǎn)轉(zhuǎn)移到怎樣將API方法整合在一起。
我還遇到過一個(gè)有趣的例子,使用DSL封裝一個(gè)棘手的第三方程序庫。當(dāng)命令–查詢接口設(shè)計(jì)得很糟糕時(shí),DSL 慣常的連貫性就得以凸現(xiàn)。此外,DSL只須支持客戶真正用到的部分,這大大降低了客戶開發(fā)人員學(xué)習(xí)的成本。
2)與領(lǐng)域?qū)<业臏贤?/strong>
我相信,軟件項(xiàng)目中最困難的部分,也是項(xiàng)目失敗最常見的原因,就是開發(fā)團(tuán)隊(duì)與客戶以及軟件用戶之間的溝通。DSL提供了一種清晰而準(zhǔn)確的語言,可以有效地改善這種溝通。
相比于關(guān)于生產(chǎn)率的簡單爭論,改善溝通所帶來的好處顯得更加微妙。首先,很多DSL并不適用于溝通領(lǐng)域問題,比如,用于正則表達(dá)式或構(gòu)建依賴關(guān)系的DSL,在這些情況下就不合適。只有一部分獨(dú)立DSL確實(shí)應(yīng)用這種溝通手段。
當(dāng)在這樣的場景下討論DSL時(shí),經(jīng)常會(huì)有人說:“好吧,現(xiàn)在我們不需要程序員了,領(lǐng)域?qū)<铱梢宰约褐付I(yè)務(wù)規(guī)則?!蔽野堰@種論調(diào)稱為“COBOL謬論”——因?yàn)镃OBOL曾被人寄予這樣的厚望。這種爭論很常見,不過,我覺得這種爭論不值得在此重復(fù)。
雖然存在“COBOL謬論”,我仍然覺得DSL可以改善溝通。不是讓領(lǐng)域?qū)<易约喝慏SL,但他們可以讀懂,從而理解系統(tǒng)做了什么。能夠閱讀DSL代碼,領(lǐng)域?qū)<揖涂梢灾赋鰡栴}所在。他們還可以同編寫業(yè)務(wù)規(guī)則的程序員更好地交流,也許,他們還可以編寫一些草稿,程序員們可以將其細(xì)化成適當(dāng)?shù)腄SL規(guī)則。
但我不是說領(lǐng)域?qū)<矣肋h(yuǎn)不能編寫DSL。我遇見過很多團(tuán)隊(duì),他們成功地讓領(lǐng)域?qū)<矣肈SL編寫了大量系統(tǒng)功能。但我仍然認(rèn)為,使用DSL的最大價(jià)值在于,領(lǐng)域?qū)<夷軌蜃x懂。所以編寫DSL的第一步,應(yīng)該專注于易讀性,這樣即便后續(xù)的目標(biāo)達(dá)不到,我們也不會(huì)失去什么。
使用DSL是為了讓領(lǐng)域?qū)<夷軌蚩炊?,這就引出了一個(gè)值得爭議的問題。如果希望領(lǐng)域?qū)<依斫庖粋€(gè)“語義模型”的內(nèi)容,可以將模型可視化。這時(shí)就要考慮一下,相比于支持一種DSL,是不是只使用可視化會(huì)是一種更有效的辦法。可視化對(duì)于DSL而言,是一種有益的補(bǔ)充。
讓領(lǐng)域?qū)<覅⑴c構(gòu)建DSL,與讓他們參與構(gòu)建模型是同樣的道理。我發(fā)現(xiàn),與領(lǐng)域?qū)<乙黄饦?gòu)建模型能夠帶來很大的好處,在構(gòu)建一種Ubiquitous Language [Evans DDD] 的過程中,程序員與領(lǐng)域?qū)<抑g可以深入溝通。DSL提供了另一種增進(jìn)溝通的手段。隨著項(xiàng)目的不同,我們可能發(fā)現(xiàn),領(lǐng)域?qū)<铱赡軙?huì)參與模型和DSL,也可能只參與 DSL。
實(shí)際上,有些人發(fā)現(xiàn),即便不實(shí)現(xiàn)DSL,有一種描述領(lǐng)域知識(shí)的DSL,也能帶來很大的好處。即使只把它當(dāng)做溝通平臺(tái)也可以獲益。
總的來說,讓領(lǐng)域?qū)<覅⑴c構(gòu)建DSL比較難,但回報(bào)很高。即使最終不能讓領(lǐng)域?qū)<覅⑴c,但是開發(fā)人員在生產(chǎn)率方面的提升,也足以讓我們大受裨益,因此,DSL值得投入。
3)執(zhí)行環(huán)境的改變
當(dāng)談及將狀態(tài)機(jī)表述為XML的理由時(shí),一個(gè)重要的原因是,狀態(tài)機(jī)定義可以在運(yùn)行時(shí)解析,而非編譯時(shí)。在這種情況下,我們希望將代碼運(yùn)行于不同的環(huán)境,這類理由也是使用DSL一個(gè)常見的驅(qū)動(dòng)力。對(duì)于XML配置文件而言,將邏輯從編譯時(shí)移到運(yùn)行時(shí)就是一個(gè)這樣的理由。
還有一些需要遷移執(zhí)行環(huán)境的情況。我曾見過一個(gè)項(xiàng)目,它要從數(shù)據(jù)庫里找出所有滿足某種條件的合同,給它們打上標(biāo)簽。他們編寫了一種DSL,以指定這些條件,并用它以Ruby語言組裝“語義模型”。如果用Ruby將所有合同讀入內(nèi)存,再運(yùn)行查詢邏輯,那會(huì)非常慢,但是團(tuán)隊(duì)可以用語義模型的表示生成SQL,在數(shù)據(jù)庫里做處理。直接用SQL編寫規(guī)則,對(duì)開發(fā)人員都很困難,遑論業(yè)務(wù)人員。然而,業(yè)務(wù)人員可以讀懂(在這種情況下,甚至編寫)DSL里有關(guān)的表達(dá)式。
這樣用DSL常常可以彌補(bǔ)宿主語言的局限性,將事物以適宜的DSL形式表現(xiàn)出來,然后,生成可用于實(shí)際執(zhí)行環(huán)境的代碼。
模型的存在有助于這種遷移。一旦有了一個(gè)模型,或者直接執(zhí)行它,或者根據(jù)它產(chǎn)生代碼都很容易。模型可以由表單風(fēng)格的界面創(chuàng)建,也可以由DSL創(chuàng)建。DSL相對(duì)于表單有一些優(yōu)勢。在表述復(fù)雜邏輯方面,DSL比表單做得更好。而且,可以用相同的代碼管理工具,比如版本控制系統(tǒng),管理這些規(guī)則。當(dāng)規(guī)則經(jīng)由表單輸入,存入數(shù)據(jù)庫中,版本控制就無能為力了。
下面會(huì)談及DSL的一個(gè)偽優(yōu)點(diǎn)。我聽說,有人宣稱DSL的一個(gè)好處是,它能夠在不同的語言環(huán)境下執(zhí)行相同的行為。一個(gè)人編寫了業(yè)務(wù)規(guī)則,然后生成C#或Java代碼,或者,描述校驗(yàn)邏輯之后,在服務(wù)器端以C#形式運(yùn)行,在客戶端則是JavaScript。這是一個(gè)偽優(yōu)勢,因?yàn)閮H僅使用模型就可以做到這一點(diǎn),根本無需DSL。當(dāng)然,DSL有助于理解這些規(guī)則,但那是另外一個(gè)問題。
4)其他計(jì)算模型
幾乎所有主流的編程語言都采用命令式的計(jì)算模型。這意味著,我們要告訴計(jì)算機(jī)做什么事情,按照怎樣的順序來做。通過條件和循環(huán)處理控制流,還要使用變量——確實(shí),還有很多我們以為理所當(dāng)然的東西。命令式計(jì)算模型之所以流行,是因?yàn)樗鼈兿鄬?duì)容易理解,也容易應(yīng)用到許多問題上。然而,它并不總是最佳選擇。
狀態(tài)機(jī)是這方面的一個(gè)良好例子??梢圆捎妹钍酱a和條件處理這種行為,也確實(shí)可以很好地構(gòu)建出這種行為。但如果直接把它當(dāng)做“狀態(tài)機(jī)”來思考,效果會(huì)更好。另外一個(gè)常見的例子是,定義軟件構(gòu)建方式。我們固然可以用命令式邏輯實(shí)現(xiàn)它,但后來,人們發(fā)現(xiàn)用“依賴網(wǎng)絡(luò)”(比如,運(yùn)行測試必須依賴于最新的編譯結(jié)果)解決會(huì)更容易。結(jié)果,人們設(shè)計(jì)出了專用于描述構(gòu)建的語言(比如Make和Ant),其中將任務(wù)間的依賴關(guān)系作為主要的結(jié)構(gòu)化機(jī)制。
你可能經(jīng)常聽到,人們把非命令式方式稱為聲明式編程。之所以叫做聲明式,是因?yàn)檫@種風(fēng)格讓人定義做什么,而不是用一堆命令語句來描述怎么做。
采用其他計(jì)算模型,并不一定非要有DSL。其他編程模型的核心行為也源自“語義模型”,正如前面所講的狀態(tài)機(jī)。然而,DSL還是能夠帶來很大的轉(zhuǎn)變,因?yàn)椴僮髀暶魇匠绦?,組裝語義模型會(huì)容易一些。
總感覺項(xiàng)目組寫的代碼不規(guī)范,有時(shí)一個(gè)類能有幾千行代碼。那么應(yīng)該如何規(guī)范代碼那?
領(lǐng)域特定語言的目標(biāo)是主要關(guān)注我們應(yīng)該做什么,而不是怎樣去實(shí)現(xiàn)某種特定的業(yè)務(wù)邏輯。
Linq簡化了代碼
如果使用c#開發(fā)則對(duì)應(yīng)的領(lǐng)域特定語言就是Linq技術(shù)了。
這是個(gè)表示分組的對(duì)象,用于保存分類的名稱和產(chǎn)品數(shù)量。然后我們就會(huì)寫一些十分丑陋的代碼
DSL是對(duì)模型的一個(gè)有益的補(bǔ)充。
Dictionary《string, Grouping》 groups = new Dictionary《string, Grouping》();
foreach (Product p in products)
{
if (p.UnitPrice 》= 20)
{
if (!groups.ContainsKey(p.CategoryName))
{
Grouping r = new Grouping();
r.CategoryName = p.CategoryName;
r.ProductCount = 0;
groups[p.CategoryName] = r;
}
groups[p.CategoryName].ProductCount++;
}
}
List《Grouping》 result = new List《Grouping》(groups.Values);
result.Sort(delegate(Grouping x, Grouping y)
{
return
x.ProductCount 》 y.ProductCount ? -1 :
x.ProductCount 《 y.ProductCount ? 1 :
0;
});
不過如果這里我們使用DSL,也就是LINQ,就像這樣:
var result = products
.Where(p =》 p.UnitPrice 》= 20)
.GroupBy(p =》 p.CategoryName)
.OrderByDescending(g =》 g.Count())
.Select(g =》 new { CategoryName = g.Key, ProductCount = g.Count() });
方法鏈
其實(shí)我們在C#代碼中除了Linq,其他地方也可以做類似的設(shè)計(jì),學(xué)名叫方法鏈(Method chaining),類型如下實(shí)現(xiàn):
Object.DoSomething().DoSomethingElse().DoAnotherThing();
class Person
{
private string _name;
private byte _age;
public Person SetName(string name)
{
_name = name;
return this;
}
public Person SetAge(byte age)
{
_age = age;
return this;
}
public Person Introduce()
{
Console.WriteLine(“Hello my name is {0} and I am {1} years old.”, _name, _age);
return this;
}
}
//Usage:
static void Main()
{
Person user = new Person();
// Output of this sequence will be: Hello my name is Peter and I am 21 years old.
user.SetName(“Peter”).SetAge(21).Introduce();
}
學(xué)習(xí)Linq之前需要學(xué)習(xí)的一些必備知識(shí)
var 關(guān)鍵字
C#擴(kuò)展方法和擴(kuò)展庫
namespace MyExtensionsLibrary
{
public static class Class1
{
public static void DispAssembly(this object obj)
{
Console.WriteLine(“該對(duì)象所在的程序集位置是:{0}/n-》{1}‘/t”, obj.GetType().Name, System.Reflection.Assembly.GetAssembly(obj.GetType()));
}
public static int ReverseInt(this int i)
{
char []digits=i.ToString ().ToCharArray ();
Array .Reverse(digits );
string newDigits=new string (digits );
return int.Parse (newDigits );
}
}
}
對(duì)象初始化器
var point3=new Point{x=7,y=4};
匿名類型
匿名對(duì)象
var Apeople=new{Sex=”male”,Name=”Linc”,Age=”26”};
匿名方法
public partial class Form1 : Form
{
delegate void Printer(string s);
public Form1()
{
InitializeComponent();
// 匿名方法
Printer p = delegate(string j)
{
textBox1.Text += j+“/r/n”;
};
// 匿名委托調(diào)用后返回的結(jié)果
p(“The delegate using the anonymous method is called.”);
//命名方法
p = new Printer(DoWork);
// 傳統(tǒng)的調(diào)用方式
p(“The delegate using the named method is called.”);
}
void DoWork(string k)
{
textBox1.Text += k + “/r/n”;
}
}
Lambda表達(dá)式
Lambda表達(dá)式語法看上去真怪異,說白了是更好的匿名方法。廢話不多說,先來看看使用匿名方法:
//首先使用集合初始化語法建立一個(gè)整型列表
List《int》 list = new List《int》() { 1, 2, 3, 4, 5, 6, 7 };
//匿名方法粉墨登場
List《int》 oddNumbers = list.FindAll(
delegate(int i)
{
return (i % 2) != 0;
}
);//匿名方法結(jié)束
foreach (var oddNumber in oddNumbers)
{
//輸出奇數(shù)
Console.WriteLine(oddNumber);
}
觀察上面的匿名方法,我們使用delegate,而且還要保證輸入參數(shù)的類型匹配,這種語法確實(shí)還是讓人覺得冗長。下面看看Lambda表達(dá)式是如何簡化FindAll()方法的:
//通過Lambda表達(dá)式就一句就搞定了!多神奇啊!傳統(tǒng)的委托語法通通消失了
List《int》 oddNumbers = list.FindAll(i =》 (i % 2) != 0);
解剖Lambda表達(dá)式
i =》 (i % 2) != 0
你一定注意到了Lambda表達(dá)式的 =》 標(biāo)記(讀作 goes to),它的前面是一個(gè)參數(shù)列表,后面是一個(gè)表達(dá)式。
很明顯,前面的參數(shù)列表并沒有定義參數(shù)的類型(由編譯器根據(jù)上下文推斷出i是一個(gè)整型),所以它是隱式的。當(dāng)然,我們也可以顯示定義: (int i)=》(i%2)!=0);
我們這里參數(shù)列表只有一個(gè)參數(shù),所以那個(gè)括號(hào)可以被省略。
Linq
自己也沒有把所有資料都看完,個(gè)人對(duì)于Linq的用法大致是這樣設(shè)想的,我們在做項(xiàng)目時(shí)會(huì)建立許多聚合根,如果我們的查詢會(huì)跨多個(gè)聚合根則使用存儲(chǔ)過程,否則使用Linq進(jìn)行查詢。Linq有個(gè)LinqPad的小工具用于測試,
聚合與組合
組合的話是類似共生共滅的關(guān)系,例如大雁和大雁的翅膀。對(duì)于我們營收系統(tǒng)來說,就好比營業(yè)賬和營業(yè)賬子表
而聚合則沒有這么強(qiáng)的從屬關(guān)系,比如用戶和冊本信息,冊本信息作為一個(gè)用戶的只讀屬性存在,但也可以單獨(dú)操作冊本信息。
賬戶可以獨(dú)立存在,但用戶又有一個(gè)賬戶信息的只讀屬性
系統(tǒng)架構(gòu)
這里說的系統(tǒng)架構(gòu)主要是邏輯上的分層,不是物理上的。主要是想利用Entity Framework在系統(tǒng)架構(gòu)里面,替換以前的codesmith生成entity和dal,同時(shí)想引入領(lǐng)域模型的概念,不直接操作entity framework中的對(duì)象,而是對(duì)應(yīng)的領(lǐng)域模型。對(duì)于領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)我會(huì)在后面的領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的文章中介紹。
評(píng)論
查看更多