一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

面向?qū)ο筌浖_(kāi)發(fā)和過(guò)程(六)

 figol 2006-05-27

面向?qū)ο筌浖_(kāi)發(fā)和過(guò)程(六)

針對(duì)契約設(shè)計(jì)

developerWorks

級(jí)別: 初級(jí)

林星, 項(xiàng)目經(jīng)理

2003 年 12 月 01 日

針對(duì)契約設(shè)計(jì)是一種嚴(yán)謹(jǐn)?shù)能浖O(shè)計(jì)思路,它有助于提高軟件的質(zhì)量。軟件設(shè)計(jì)中經(jīng)常出現(xiàn)的bug往往是由于需要的前提條件或數(shù)據(jù)不能夠得到滿足而導(dǎo)致的。針對(duì)契約設(shè)計(jì)通過(guò)一種約束性的方法,解決了這個(gè)問(wèn)題。

1.針對(duì)契約設(shè)計(jì)

我們知道,現(xiàn)代的社會(huì)是一種生人社會(huì),這和我們幾千年的熟人社會(huì)已經(jīng)不一樣了,人和人的關(guān)系變得很復(fù)雜,如何保證每個(gè)人的利益,如何保證這種復(fù)雜的關(guān)系不會(huì)對(duì)社會(huì)的穩(wěn)定性造成影響?,F(xiàn)代社會(huì)的解決方法是采用契約,或說(shuō)是合同。我們和用人單位需要簽訂勞動(dòng)合同,購(gòu)買(mǎi)房產(chǎn)需要商品房買(mǎi)賣(mài)合同,甚至我們上車(chē)買(mǎi)票,車(chē)票本身也是一種合同。為什么合同如此的重要呢?因此它規(guī)定了人和人之間的一種關(guān)系,并為這種關(guān)系定義了嚴(yán)謹(jǐn)?shù)呢?zé)任和權(quán)利。軟件設(shè)計(jì)也是類(lèi)似的。一個(gè)大型的系統(tǒng),類(lèi)之間的關(guān)系非常的復(fù)雜,方法間相互調(diào)用,因此,我們也需要一種類(lèi)似于契約一樣的嚴(yán)謹(jǐn)規(guī)范,來(lái)約束每個(gè)類(lèi)、每個(gè)方法,以保證軟件整體的穩(wěn)定性。這就是針對(duì)契約設(shè)計(jì)的實(shí)質(zhì)。

Eiffel語(yǔ)言天生就是一種嚴(yán)謹(jǐn)、甚至可以說(shuō)是保守的語(yǔ)言。例如,對(duì)于Eiffel中的公有字段,默認(rèn)的情況下就是只讀的,以此保證公有屬性被不當(dāng)修改。而Eiffel值得稱(chēng)道之處,在于在使用Eiffel語(yǔ)言的時(shí)候,你的大部分的精力都花在如何設(shè)計(jì)類(lèi)的前置條件(precondition)、后置條件(postcondition)和不變式(invariant)上。不要小看這三者的作用,雖然看起來(lái)簡(jiǎn)單,在嘗試著設(shè)計(jì)它們的時(shí)候,你就會(huì)發(fā)現(xiàn),你的類(lèi)將會(huì)變得非常的強(qiáng)壯。為什么呢?我們都知道,要保證信息傳遞的正確性,就需要有反饋機(jī)制。而在軟件設(shè)計(jì)的時(shí)候如何引入這種反饋機(jī)制呢?Eiffel就用它自己的方式實(shí)現(xiàn)了這一點(diǎn)。對(duì)前置條件的檢查,保證了方法開(kāi)始之前狀態(tài)的正確性,后置條件和不變式保證了方法執(zhí)行完畢后我們得到了我們所需要的狀態(tài)。雖然我們還可以找到很多其它的反饋機(jī)制,但是Eiffel的這種機(jī)制,無(wú)疑是很有效的。

Eiffel的特性粗看起來(lái)并沒(méi)有什么特別之處,舉一個(gè)最小的例子:

對(duì)于一個(gè)將內(nèi)部count值加一的Inc的方法來(lái)說(shuō),它的后置條件是


                        count=old count+1
                        

這里的old count指的是未被改變的值,即舊值。你可能會(huì)說(shuō),這不是吃飽了撐著嗎,代碼本身做的事情就是另count值加一,最后還要檢驗(yàn)一次加一的結(jié)果,純屬浪費(fèi)機(jī)器資源。這里例子非常的小,因此我們無(wú)法看出更為具體的思路。但是我們知道,在面向?qū)ο笤O(shè)計(jì)中,各個(gè)類(lèi)、各個(gè)方法之間構(gòu)成了細(xì)密的協(xié)作網(wǎng)。在這種情況下,即容易犯錯(cuò)誤。這時(shí)候,后置條件的根本作用,就是強(qiáng)迫你找到另外一種方法,來(lái)驗(yàn)證你剛才的工作是正確的。這就好像我們?cè)隍?yàn)算數(shù)學(xué)題的時(shí)候,如果方法相同,那么這個(gè)結(jié)果還未必是對(duì)的,因?yàn)榉椒ㄒ粯?,你可能漏掉了一些信息,但是如果我們能夠從另一個(gè)渠道來(lái)驗(yàn)證結(jié)果,例如和同桌對(duì)對(duì)答案,這個(gè)結(jié)果正確的可能性就大了許多,你的把握也會(huì)大很多。所以,后置條件可以看作是另一個(gè)渠道的驗(yàn)算。

Eiffel的機(jī)制還導(dǎo)致了另一個(gè)結(jié)果,那就是優(yōu)秀的面向?qū)ο筌浖O(shè)計(jì)。面向?qū)ο蟮淖罨镜墓Φ?,在于設(shè)計(jì)微小的、完成一個(gè)簡(jiǎn)單任務(wù)的類(lèi)和方法??上姆敲嫦?qū)ο筠D(zhuǎn)型來(lái)的程序員,仍然喜歡編寫(xiě)一些很長(zhǎng)的代碼塊。使用Eiffel完全不會(huì)出現(xiàn)這種情況,使用這些冗長(zhǎng)的方法,你根本無(wú)法實(shí)現(xiàn)前置條件和后置條件。學(xué)習(xí)使用它們,你可以很自然的學(xué)習(xí)重用的思路?;谶@種考慮,建議向面向?qū)ο筠D(zhuǎn)型的程序員們都學(xué)學(xué)Eiffel,你的面向?qū)ο笤O(shè)計(jì)功力會(huì)大有長(zhǎng)進(jìn)的。

Eiffel并不是本文討論的重點(diǎn),因此本文并不打算花費(fèi)太多的精力來(lái)介紹它,遺憾的是,國(guó)內(nèi)關(guān)于Eiffel的資料比較少,我了解到的中文資料是人民郵電出版社即將出版的面向契約設(shè)計(jì)一書(shū)。

另外仍需要提及的一點(diǎn)是,Eiffel并不是一種國(guó)內(nèi)流行的開(kāi)發(fā)語(yǔ)言,但是這并不影響我們?cè)谄渌Z(yǔ)言中吸收這種優(yōu)秀的思路。Java語(yǔ)言在其新的JDK版本中引入了斷言機(jī)制,就可以用于實(shí)現(xiàn)前置條件和后置條件。即使是一些不支持?jǐn)嘌缘恼Z(yǔ)言,也很容易編寫(xiě)自己的斷言機(jī)制。

前置條件和后置條件的應(yīng)用還擴(kuò)展到了其它的方面。例如,在設(shè)計(jì)中和用例中,都引入了前置條件和后置條件的用法。不管是應(yīng)用在哪一個(gè)地方,思路都是一樣的。前置條件最大的好處就是排除非法的輸入值,而后置條件的最大好處就是對(duì)結(jié)果進(jìn)行驗(yàn)證,以保證過(guò)程的正確性。不同應(yīng)用的前置條件和后置條件都有兩個(gè)共同的收益;

  • 更好的結(jié)構(gòu)性
  • 更優(yōu)的重用性

和Eiffel的思路一樣,我們把現(xiàn)實(shí)中的業(yè)務(wù)對(duì)象看作是由基本查詢(xún)、派生查詢(xún)、操作這三者組成的。同時(shí)利用這三種機(jī)制,才能夠有效的運(yùn)用前置條件和后置條件。將問(wèn)題域中的問(wèn)題劃分為這三種類(lèi)型,無(wú)疑提高了問(wèn)題域組織的有效性,也就是獲得了更好的結(jié)構(gòu)性。另外,前置條件和后置條件使用的是半形式化的表述方式,因此問(wèn)題域的表述是清晰的,嚴(yán)謹(jǐn)?shù)摹?

在獲得結(jié)構(gòu)性的同時(shí),我們得到了更優(yōu)的重用性,怎么說(shuō)呢?派生查詢(xún)是由基本查詢(xún)構(gòu)成的,而操作中又運(yùn)用了兩種查詢(xún)。由于分類(lèi)清晰,我們可以很方便的進(jìn)行重用。

這樣的說(shuō)法可能過(guò)于抽象了。我們說(shuō)一個(gè)現(xiàn)實(shí)中的故事。我接觸過(guò)一段的路由器,在學(xué)習(xí)路由器的第一堂課上,我學(xué)會(huì)了一個(gè)最重要的操作,就是在對(duì)任何的配置進(jìn)行修改時(shí)候,你必須查看配置文件,以保證配置正確。這是一個(gè)很基本的操作,但是我卻是在實(shí)踐中吃過(guò)虧之后才發(fā)現(xiàn)它的重要性的。查看配置文件其實(shí)就是配置這個(gè)操作的后置條件,由它來(lái)保證配置操作過(guò)程的正確性,只要后置條件為真,出錯(cuò)的概率將會(huì)降低。當(dāng)然,我們還可以加入更多的后置條件來(lái)進(jìn)一步降低概率。而這里的前置條件是你已經(jīng)正確登錄到路由器,這是一個(gè)基本的條件,可能還有操作系統(tǒng)支持該配置條件等。

前置條件和后置條件確實(shí)是個(gè)好東西,不過(guò),它并不是沒(méi)有成本的。(作為精益編程的擁護(hù)者,我們做任何事情都需要考慮成本和收益的)。最大的成本是時(shí)間,在同一個(gè)問(wèn)題域上花費(fèi)的時(shí)間大大增多了,影響到了整體的軟件過(guò)程,這對(duì)于很多的項(xiàng)目是要命的。如何看待這一成本呢?應(yīng)該說(shuō),一開(kāi)始應(yīng)用前置條件和后置條件的時(shí)候,確實(shí)是需要付出額外的成本的。隨著對(duì)應(yīng)用的熟悉,這個(gè)成本會(huì)慢慢降低。而后續(xù)因?yàn)檐浖|(zhì)量改進(jìn)帶來(lái)的其它方面的收益,將會(huì)超過(guò)這個(gè)成本。它們的曲線大致會(huì)是這樣的:(遺憾的是,我們暫時(shí)做不到定量的分析)

當(dāng)然,我們一方面注重效益,另一方面仍然要考慮盡可能降低成本。在成本方面,度是最重要的。前置條件和后置條件的應(yīng)用的最精妙之處也在于此。要多少的前置條件和后置條件才能夠滿足需要?條件編寫(xiě)的細(xì)致程度如何?對(duì)不同的應(yīng)用是否采用同樣的度?這些數(shù)據(jù)都只能夠來(lái)源于實(shí)踐經(jīng)驗(yàn)。度的不足難以表現(xiàn)前置條件和后置條件的威力,度的過(guò)剩又增加了投入成本。

前置條件和后置條件的思路在生活中到處可見(jiàn),在數(shù)學(xué)中的應(yīng)用就更多了。對(duì)我們軟件開(kāi)發(fā)人員來(lái)說(shuō),重要的是形成這樣的操作思路,設(shè)計(jì)出穩(wěn)定的軟件。在Eiffel語(yǔ)言中,另一個(gè)重要的特性是不變式。由于篇幅所限,我們這里不可能進(jìn)行大量的介紹,大家可以參考相關(guān)的資料。對(duì)于我們來(lái)說(shuō),最重要的是理解針對(duì)契約設(shè)計(jì)的優(yōu)勢(shì),并運(yùn)用到項(xiàng)目當(dāng)中。

一開(kāi)始我們就說(shuō)過(guò),按契約設(shè)計(jì)是一種嚴(yán)謹(jǐn)?shù)脑O(shè)計(jì)思路,開(kāi)發(fā)的成本隨之提高,因此很多的軟件開(kāi)發(fā)團(tuán)隊(duì)并不愿意采用Eiffel語(yǔ)言,Eiffel語(yǔ)言本身也是一個(gè)陽(yáng)春白雪的存在。但是隨著軟件規(guī)模日益擴(kuò)大,質(zhì)量要求不斷提高,按契約設(shè)計(jì)的思路已經(jīng)慢慢進(jìn)入了很多的語(yǔ)言中了。

對(duì)于項(xiàng)目的開(kāi)發(fā)者來(lái)說(shuō),質(zhì)量的要求最難的就是如何實(shí)際操作。加強(qiáng)測(cè)試的力量和強(qiáng)度固然是一種辦法,但是成本也不菲。審核也是一種有效的辦法,但是對(duì)審核者的要求和壓力都不小,一旦流于形式,也起不到什么效果。將軟件工程的思路徹底貫徹到代碼中一直是本文的主題,這里也不例外。按契約設(shè)計(jì)提供了一種方法,要求程序員按照嚴(yán)謹(jǐn)?shù)姆椒ㄟM(jìn)行方法調(diào)用和方法設(shè)計(jì)。雖然調(diào)用方和被調(diào)用方同時(shí)采用嚴(yán)謹(jǐn)?shù)脑O(shè)計(jì)模式存在浪費(fèi)的可能,但這個(gè)成本是很低的,而從軟件工程文化的角度上來(lái)看,卻能夠逐漸形成高效的編碼習(xí)慣,這還是非常劃算的。





2. 規(guī)范

要定義一個(gè)好的規(guī)范,首先我們需要清楚的知道我們制定規(guī)范的目的。首先可以肯定的,我們的目的不是使用Eiffel語(yǔ)言,而是提高軟件的質(zhì)量,那么,在這個(gè)目的下,我們?nèi)绾沃贫ㄒ?guī)范呢?如果你希望在組織內(nèi)引入面向契約設(shè)計(jì)。那么,可以嘗試著使用下文介紹的iContract工具,并根據(jù)iContract的方式定義你的按契約設(shè)計(jì)規(guī)范。如果你不希望改變現(xiàn)有的開(kāi)發(fā)方式,只是想從按契約設(shè)計(jì)中學(xué)習(xí)一些知識(shí),那么,你更重要的是從基本查詢(xún)、派生查詢(xún)、操作方面來(lái)考慮如何設(shè)計(jì)規(guī)范,來(lái)約束類(lèi)的設(shè)計(jì)。這樣,你同樣可以從按契約設(shè)計(jì)的思路中獲益。





3. 技能

類(lèi)設(shè)計(jì)的學(xué)習(xí)。學(xué)習(xí)按契約設(shè)計(jì),最關(guān)鍵的就是學(xué)習(xí)如何通過(guò)基本查詢(xún)、派生查詢(xún)、操作這三個(gè)方面來(lái)設(shè)計(jì)類(lèi)。

對(duì)象約束語(yǔ)言。對(duì)象約束語(yǔ)言(OCL)是一種描述面向?qū)ο笤O(shè)計(jì)的語(yǔ)言,它由OMG組織管理和維護(hù)。前置條件、后置條件和不變式的描述采用了OCL的一個(gè)子集。學(xué)習(xí)OCL語(yǔ)言,關(guān)鍵并不是在語(yǔ)法本身,而是在于對(duì)象的設(shè)計(jì)上。如果一個(gè)對(duì)象的設(shè)計(jì)不夠規(guī)范,你會(huì)發(fā)現(xiàn),你無(wú)法使用OCL語(yǔ)言來(lái)描述它。如果你能夠熟練的使用OCL來(lái)描述類(lèi)和類(lèi)之間的關(guān)系,那么,你會(huì)發(fā)現(xiàn),軟件的質(zhì)量會(huì)得到大幅度的提高。





4. 過(guò)程

按契約設(shè)計(jì)屬于設(shè)計(jì)范疇,所以,它可以很方便的和接口設(shè)計(jì)、測(cè)試等活動(dòng)結(jié)合起來(lái)。例如,iContract中就提供了這方面的例子:


                        /**
                        */
                        public interface IEmployee {
                        /**
                        * @pre hasOffice()
                        *
                        * @return iContract.examples.office_management_system.API.IRoom
                        */
                        public IRoom getOffice();
                        /**
                        * @post return == (office != null) // implementation, exposes null
                        *
                        * @return boolean
                        */
                        public boolean hasOffice();
                        /**
                        * @pre office != null
                        *
                        * @post hasOffice()
                        * @post getOffice() == office
                        *
                        * @param office IRoom
                        */
                        public void setOffice(IRoom office);
                        }
                        

同樣的,測(cè)試活動(dòng)中也可以針對(duì)以上的接口描述進(jìn)行重點(diǎn)測(cè)試。測(cè)試前置條件違反的情況,測(cè)試后置條件和不變式是否滿足。





5. 工具

Eiffel是一門(mén)非常優(yōu)秀的語(yǔ)言,但是要在項(xiàng)目中完全采用Eiffel并不是一件容易的事情。除了Eiffel之外,其它的語(yǔ)言都沒(méi)有對(duì)針對(duì)契約設(shè)計(jì)的明顯支持,不過(guò)確實(shí)有人為非Eiffel語(yǔ)言設(shè)計(jì)了針對(duì)契約式設(shè)計(jì)支持工具。而Java中的iContract就是其中的一種。iContract其實(shí)是一種預(yù)編譯器,它把注釋中的特別標(biāo)記翻譯為標(biāo)準(zhǔn)的Java代碼,插入到最終的代碼中:


                        /**
                        * @pre f >= 0.0
                        */
                        public float sqrt(float f) { ... }
                        

@pre是前置條件的標(biāo)志符號(hào),它表示了函數(shù)sqrt的輸入?yún)?shù)f需要滿足的條件。同樣的,還有@post、@inv等標(biāo)識(shí)符,它們分別表示了前面討論的后置條件和不變式。此外,iContract還支持forall、exists、implies等一些OCL語(yǔ)法。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多

    午夜亚洲精品理论片在线观看 | 成人免费视频免费观看| 精品丝袜一区二区三区性色| 色婷婷人妻av毛片一区二区三区| 国产精品涩涩成人一区二区三区 | 欧美一区二区在线日韩| 亚洲精品一区三区三区| 精品日韩国产高清毛片| 亚洲人午夜精品射精日韩| 欧美人妻免费一区二区三区| 懂色一区二区三区四区| 亚洲精品深夜福利视频| 国产又粗又猛又长又黄视频| 不卡中文字幕在线免费看| 麻豆视频传媒入口在线看| 好吊视频一区二区在线| 国产又大又黄又粗的黄色| 日韩亚洲精品国产第二页| 激情中文字幕在线观看| 国产精品伦一区二区三区在线| 黄片免费播放一区二区| 好东西一起分享老鸭窝| 激情综合五月开心久久| 日本不卡在线视频中文国产| 国产一区一一一区麻豆| 冬爱琴音一区二区中文字幕| 九九热精彩视频在线免费| 五月天丁香婷婷一区二区| 好吊日在线视频免费观看| 好吊日成人免费视频公开| a久久天堂国产毛片精品| 亚洲成人久久精品国产| 欧美日韩中黄片免费看| 亚洲在线观看福利视频| 厕所偷拍一区二区三区视频| 91日韩在线观看你懂的| 亚洲精品高清国产一线久久| 久久精品a毛片看国产成人| 国产精品一区二区成人在线| 久久精品欧美一区二区三不卡| 91亚洲国产成人久久精品麻豆|