- 面向?qū)ο蟪绦蛟O(shè)計(jì)綜合實(shí)踐
- 駱力明等編著
- 504字
- 2018-12-27 17:36:24
第1章 面向?qū)ο筌浖_(kāi)發(fā)方法
1.1 概述
計(jì)算機(jī)發(fā)展早期軟件開(kāi)發(fā)的個(gè)體化特點(diǎn),造成了許多錯(cuò)誤的認(rèn)識(shí)和做法,表現(xiàn)為忽視軟件需求和軟件分析的重要性,認(rèn)為軟件開(kāi)發(fā)就是寫(xiě)程序并使之運(yùn)行。隨著軟件規(guī)模的增大,計(jì)算機(jī)軟件開(kāi)發(fā)和維護(hù)過(guò)程中遇到了一系列嚴(yán)重問(wèn)題,出現(xiàn)了軟件危機(jī)。
在軟件開(kāi)發(fā)工作中,以下幾個(gè)觀念常常被忽略。
① 軟件的生命周期(參見(jiàn)圖1.1)大體分為規(guī)劃、分析、設(shè)計(jì)、編碼、維護(hù)等一系列階段組成。

圖1.1 軟件生命周期
在開(kāi)發(fā)過(guò)程中,每個(gè)階段都可以直接和間接地回饋到前面的階段。整個(gè)軟件生命周期是一個(gè)迭代、漸增的開(kāi)發(fā)過(guò)程,這種迭代過(guò)程不僅貫穿整個(gè)軟件生命周期,并且表現(xiàn)在每個(gè)階段中,特別是在分析(全局分析、局部分析)和設(shè)計(jì)(全局設(shè)計(jì)、局部設(shè)計(jì)) 階段。
② 程序只是完整產(chǎn)品的一個(gè)組成部分,Boehm對(duì)軟件的定義是:“軟件是程序、數(shù)據(jù)和開(kāi)發(fā)、使用和維護(hù)程序所需要的所有文檔。”
③ 在軟件開(kāi)發(fā)不同階段進(jìn)行錯(cuò)誤修改所付出的代價(jià)是很不相同的,在后期引入一個(gè)變動(dòng)比在早期引入變動(dòng),代價(jià)高達(dá)2~3個(gè)數(shù)量級(jí),所以做好軟件定義時(shí)期的工作是降低軟件成本,提高軟件質(zhì)量的關(guān)鍵。
④ 軟件維護(hù)是極端艱巨復(fù)雜的工作,需要花費(fèi)極大的代價(jià),統(tǒng)計(jì)數(shù)據(jù)表明,軟件維護(hù)費(fèi)用占軟件總費(fèi)用的55%~70%,所以要采取措施提高軟件的可維護(hù)性,減少維護(hù)費(fèi)用。
為了解決軟件危機(jī),必須要用現(xiàn)代工程的概念、原理、技術(shù)和方法進(jìn)行軟件開(kāi)發(fā)、管理和維護(hù)。
軟件開(kāi)發(fā)不是某種個(gè)體勞動(dòng)的神秘技巧,而應(yīng)該是一種組織良好、管理嚴(yán)密、各類(lèi)人員協(xié)同配合、共同完成的工程項(xiàng)目。另外,在軟件開(kāi)發(fā)的每個(gè)階段都有許多煩瑣重復(fù)的工作需要做,應(yīng)當(dāng)學(xué)會(huì)使用軟件輔助工具,在適當(dāng)?shù)能浖ぞ咻o助下,開(kāi)發(fā)人員可以把工作做得既快又好。
1.2 軟件生命周期各階段的基本任務(wù)
軟件生命周期是指一個(gè)軟件項(xiàng)目被提出并著手實(shí)施開(kāi)始,到該軟件報(bào)廢或停止使用為止。軟件生命周期由軟件定義、軟件開(kāi)發(fā)和運(yùn)行維護(hù)(也稱(chēng)為軟件維護(hù)) 三個(gè)時(shí)期組成,每個(gè)時(shí)期又進(jìn)一步劃分成若干個(gè)階段:
● 問(wèn)題定義
● 可行性研究
● 需求分析
● 總體設(shè)計(jì)
● 詳細(xì)設(shè)計(jì)
● 編碼和單元測(cè)試
● 綜合測(cè)試
● 運(yùn)行與維護(hù)
(1)問(wèn)題定義
確定“要解決的問(wèn)題是什么?”通過(guò)調(diào)研,寫(xiě)出關(guān)于問(wèn)題性質(zhì)、工程目標(biāo)和工程規(guī)模的書(shū)面報(bào)告,并得到客戶(hù)的確認(rèn)。
(2)可行性研究
確定對(duì)于問(wèn)題定義階段所確定的問(wèn)題是否有行得通的解決方法。研究并論證軟件系統(tǒng)的可行性,對(duì)方案進(jìn)行選擇并形成可行性分析報(bào)告。
(3)需求分析
這個(gè)階段的任務(wù)主要是確定所完成的系統(tǒng)必須具備哪些功能,并用正式文檔準(zhǔn)確地記錄結(jié)果,這個(gè)文檔通常稱(chēng)為系統(tǒng)規(guī)格說(shuō)明書(shū)。
(4)總體設(shè)計(jì)(概要設(shè)計(jì))
軟件設(shè)計(jì)的一條基本原理就是,程序應(yīng)該模塊化,也就是說(shuō),一個(gè)程序應(yīng)該由若干個(gè)規(guī)模適中的模塊按合理的層次結(jié)構(gòu)組織而成。因此,總體設(shè)計(jì)的主要任務(wù)就是設(shè)計(jì)程序的體系結(jié)構(gòu),也就是確定程序由哪些模塊組成及模塊間的關(guān)系。
(5)詳細(xì)設(shè)計(jì)(模塊設(shè)計(jì))
將解法具體化,確定應(yīng)該怎樣具體地實(shí)現(xiàn)這個(gè)系統(tǒng)。主要工作是模塊詳細(xì)設(shè)計(jì)。模塊詳細(xì)設(shè)計(jì)包括:模塊的詳細(xì)功能、算法、數(shù)據(jù)結(jié)構(gòu)、模塊間的接口等設(shè)計(jì),擬訂模塊測(cè)試方案。詳細(xì)設(shè)計(jì)的工作體現(xiàn)在詳細(xì)規(guī)格說(shuō)明書(shū)。
(6)編碼和單元測(cè)試
根據(jù)模塊詳細(xì)規(guī)格說(shuō)明書(shū),把詳細(xì)設(shè)計(jì)的結(jié)果翻譯成用選定的語(yǔ)言書(shū)寫(xiě)的程序。還要對(duì)模塊程序進(jìn)行測(cè)試,驗(yàn)證模塊功能及接口與詳細(xì)設(shè)計(jì)文檔的一致性,并形成單元測(cè)試報(bào)告。
(7)綜合測(cè)試
通過(guò)各種類(lèi)型的測(cè)試(及相應(yīng)的調(diào)試)使軟件達(dá)到預(yù)定的要求。
● 集成測(cè)試:根據(jù)設(shè)計(jì)的軟件結(jié)構(gòu),把經(jīng)過(guò)單元測(cè)試檢驗(yàn)的模塊按某種選定的策略裝配起來(lái),在裝配過(guò)程中對(duì)程序進(jìn)行必要的測(cè)試。
● 驗(yàn)收測(cè)試:按照規(guī)格說(shuō)明書(shū)的規(guī)定,由用戶(hù)對(duì)目標(biāo)系統(tǒng)進(jìn)行驗(yàn)收。
● 現(xiàn)場(chǎng)測(cè)試或平行運(yùn)行:平行運(yùn)行就是同時(shí)運(yùn)行新開(kāi)發(fā)出來(lái)的系統(tǒng)和將被它取代的舊系統(tǒng),以便比較新舊兩個(gè)系統(tǒng)的處理結(jié)果。
用正式的文檔資料把測(cè)試計(jì)劃、詳細(xì)測(cè)試方案以及實(shí)際測(cè)試結(jié)果保存下來(lái),作為軟件配置的一個(gè)組成部分。
(8)運(yùn)行與維護(hù)
維護(hù)階段的關(guān)鍵任務(wù)是,通過(guò)各種必要的維護(hù)活動(dòng)使系統(tǒng)持久地滿(mǎn)足用戶(hù)的需要。
● 改正性維護(hù):診斷和改正在使用過(guò)程中發(fā)現(xiàn)的軟件錯(cuò)誤。
● 適應(yīng)性維護(hù):修改軟件以適應(yīng)環(huán)境的變化。
● 完善性維護(hù):根據(jù)用戶(hù)的要求改進(jìn)或擴(kuò)充軟件使它更完善。
● 預(yù)防性維護(hù):修改軟件為將來(lái)的維護(hù)活動(dòng)預(yù)先做準(zhǔn)備。
每項(xiàng)維護(hù)活動(dòng)都應(yīng)該經(jīng)過(guò)提出維護(hù)要求(或報(bào)告問(wèn)題),分析維護(hù)要求,提出維護(hù)方案,審批維護(hù)方案,確定維護(hù)計(jì)劃,修改軟件設(shè)計(jì),修改程序,測(cè)試程序,復(fù)查驗(yàn)收等一系列步驟。
使用面向?qū)ο蠓椒ń鉀Q問(wèn)題的過(guò)程可以大體劃分為面向?qū)ο蠓治觯∣bject Oriented Analysis, OOA)、面向?qū)ο笤O(shè)計(jì)(Object Oriented Design, OOD)、面向?qū)ο缶幊蹋∣bject Oriented Programming, OOP)和面向?qū)ο鬁y(cè)試(Object Oriented Test, OOT)等步驟。
面向?qū)ο蠓治龅闹饕饔檬敲鞔_使用程序的用戶(hù)、用戶(hù)可以進(jìn)行的操作,以及數(shù)據(jù)的輸入、輸出和儲(chǔ)存,并且用標(biāo)準(zhǔn)化的面向?qū)ο竽P鸵?guī)范地表述這些內(nèi)容,最后形成面向?qū)ο蠓治瞿P停碠OA模型。在分析問(wèn)題時(shí),要抽取所有需要的對(duì)象實(shí)體,然后確定這些對(duì)象的狀態(tài)和行為,以及它們之間的相互關(guān)系。一般來(lái)說(shuō),解決一個(gè)問(wèn)題會(huì)涉及多個(gè)對(duì)象,所以這些對(duì)象之間的關(guān)系一定要明確,從而反映出整個(gè)程序的功能和狀態(tài)。
面向?qū)ο笤O(shè)計(jì)是將在面向?qū)ο蠓治霾襟E中創(chuàng)建的OOA模型加以擴(kuò)展并得到面向?qū)ο笤O(shè)計(jì)步驟中的OOD模型。面向?qū)ο笤O(shè)計(jì)在OOA模型的基礎(chǔ)上引入界面管理、任務(wù)管理和數(shù)據(jù)管理三部分的內(nèi)容,進(jìn)一步擴(kuò)充OOA模型。界面管理負(fù)責(zé)整個(gè)系統(tǒng)的人機(jī)對(duì)話(huà)界面的設(shè)計(jì),任務(wù)管理負(fù)責(zé)處理整個(gè)程序資源管理功能的工作及設(shè)置客戶(hù)與服務(wù)器之間的接口,數(shù)據(jù)管理負(fù)責(zé)設(shè)計(jì)程序與數(shù)據(jù)庫(kù)的交換方式。面向?qū)ο笤O(shè)計(jì)還需要明確每個(gè)類(lèi)方法的參數(shù)、返回值、功能等,以及各類(lèi)之間的相容性和一致性的驗(yàn)證,對(duì)各個(gè)類(lèi)、類(lèi)內(nèi)成員的訪問(wèn)權(quán)限的嚴(yán)格合理性的驗(yàn)證,也包括驗(yàn)證對(duì)象類(lèi)的功能是否符合用戶(hù)的需求。
面向?qū)ο缶幊叹褪蔷唧w的程序編寫(xiě)階段,其主要過(guò)程是先選擇一種合適的面向?qū)ο缶幊陶Z(yǔ)言,再用選定的語(yǔ)言編寫(xiě)程序?qū)崿F(xiàn)設(shè)計(jì)步驟中對(duì)各個(gè)對(duì)象的詳盡描述,然后將編寫(xiě)好的各個(gè)類(lèi)根據(jù)其關(guān)系集成為整個(gè)程序,最后通過(guò)各種實(shí)例測(cè)試找出程序的漏洞并改善程序,最終完成整個(gè)軟件的開(kāi)發(fā)。
1.3 面向?qū)ο蠓治?/h2>
1.3.1 確定客戶(hù)需要什么
人們通常認(rèn)為確定客戶(hù)需要什么是一件非常容易的事,只需向客戶(hù)詢(xún)問(wèn)就能輕松獲得。其實(shí)它遠(yuǎn)比我們想象的困難,原因主要有三個(gè)。
① 首先是客戶(hù)說(shuō)不清需求。有些客戶(hù)對(duì)需求只有模糊不清的感覺(jué),自然不能很好地用語(yǔ)言描述出來(lái);有些客戶(hù)心里非常清楚想要什么,但卻表達(dá)不清楚。少數(shù)客戶(hù)本身就懂得軟件開(kāi)發(fā),能把需求說(shuō)得清清楚楚,這樣的需求分析將會(huì)非常輕松、愉快,但這種可能性很小。
② 其次是需求自身不斷變化。有些客戶(hù)對(duì)目標(biāo)系統(tǒng)的預(yù)期一天一個(gè)想法,一拍腦袋就變一個(gè)主意,這是軟件開(kāi)發(fā)人員最頭疼的事情,但是也只能面對(duì)現(xiàn)實(shí)尋找策略應(yīng)對(duì)這種情況。分析人員在進(jìn)行需求分析時(shí)就要注意以下兩點(diǎn):
● 盡可能地分析清楚哪些是穩(wěn)定的需求,哪些是易變的需求。以便在進(jìn)行系統(tǒng)設(shè)計(jì)時(shí),將軟件的核心建筑在穩(wěn)定的需求上。
● 在合同中一定要說(shuō)清楚“做什么”和“不做什么”。如果合同不清晰明確,日后會(huì)引起很多糾紛。
③ 最后就是需求分析人員和用戶(hù)交流中產(chǎn)生誤解。
分析人員和目標(biāo)系統(tǒng)客戶(hù),一方是計(jì)算機(jī)專(zhuān)業(yè)人員,另一方是系統(tǒng)應(yīng)用領(lǐng)域?qū)<摇km然彼此都對(duì)對(duì)方的領(lǐng)域有所了解,但離專(zhuān)業(yè)人員還是存在一定的距離,這樣他們?cè)跍贤ń涣髦芯筒豢杀苊獾乜赡軙?huì)產(chǎn)生誤解。
由于需求分析存在眾多困難,所以對(duì)軟件需求分析人員的要求是非常高的。他們通常都是資深的計(jì)算機(jī)專(zhuān)家,同時(shí)具備豐富的業(yè)務(wù)領(lǐng)域知識(shí)和良好的溝通技能。
1.3.2 需求階段概述
需求階段的第一步是理解應(yīng)用領(lǐng)域,也就是目標(biāo)系統(tǒng)應(yīng)用的特定環(huán)境,例如銀行、證券公司、學(xué)校、政府等。一旦開(kāi)發(fā)團(tuán)隊(duì)充分了解應(yīng)用領(lǐng)域,就可以實(shí)施目標(biāo)系統(tǒng)的系統(tǒng)建模,一種很主流的建模方法就是使用統(tǒng)一建模語(yǔ)言UML來(lái)描述目標(biāo)系統(tǒng)的業(yè)務(wù)邏輯。通過(guò)模型,開(kāi)發(fā)團(tuán)隊(duì)可以和目標(biāo)系統(tǒng)的用戶(hù)進(jìn)行充分交流以確定客戶(hù)的業(yè)務(wù)需求,確定客戶(hù)的最終需求是一個(gè)反復(fù)迭代的過(guò)程,經(jīng)過(guò)多次溝通、理解、修正才能比較客觀地確定客戶(hù)對(duì)系統(tǒng)的真實(shí)需求。
1.3.3 理解應(yīng)用域
為了有效地挖掘出客戶(hù)的真實(shí)需求,技術(shù)人員必須熟悉目標(biāo)系統(tǒng)的應(yīng)用領(lǐng)域。如果不了解系統(tǒng)的業(yè)務(wù)領(lǐng)域,很難向客戶(hù)提出有意義的問(wèn)題,所以不可能成功完成系統(tǒng)的需求分析。理解應(yīng)用域的方法就是親臨目標(biāo)系統(tǒng)將來(lái)應(yīng)用的真實(shí)環(huán)境,去了解目標(biāo)系統(tǒng)將完成哪些業(yè)務(wù),這些業(yè)務(wù)手工完成的流程是怎樣的,目前的業(yè)務(wù)流程有哪些優(yōu)點(diǎn)和不足,等等,只有完全弄明白了這些問(wèn)題,才有可能與客戶(hù)進(jìn)行充分且有效的交流。
1.3.4 用例建模
使用UML中的“用例圖”描述擬建軟件與外部環(huán)境之間的關(guān)系。一個(gè)用例表示一個(gè)外部角色Actor(例如,用戶(hù)或其他外部軟件環(huán)境)與擬建軟件之間一個(gè)單獨(dú)交互。將所有的用例集中在一起,就可以描述一個(gè)OO軟件的總體功能需求。例如,一個(gè)網(wǎng)上拍賣(mài)系統(tǒng)的拍賣(mài)過(guò)程用例圖(見(jiàn)圖1.2)。

圖1.2 拍賣(mài)過(guò)程用例圖
用例圖在軟件的建模過(guò)程中是必不可少的。
1.4 面向?qū)ο笤O(shè)計(jì)
1.4.1 有效應(yīng)用設(shè)計(jì)模式
眾所周知,人是一種經(jīng)驗(yàn)性的動(dòng)物。我們常說(shuō):據(jù)我所知,據(jù)我所了解,據(jù)我的經(jīng)驗(yàn),等等。生活中很多事情都是依靠自己或他人的經(jīng)驗(yàn),軟件設(shè)計(jì)也類(lèi)同。建筑大師Christopher Alexander說(shuō)過(guò):“每一個(gè)模式描述了一個(gè)在我們周?chē)粩嘀貜?fù)發(fā)生的問(wèn)題,以及該問(wèn)題的解決方案的核心。這樣,你就能一次又一次地使用該方案而不必做重復(fù)勞動(dòng)。”他所指的是建筑領(lǐng)域,軟件設(shè)計(jì)模式則是描述軟件設(shè)計(jì)過(guò)程中某一類(lèi)常見(jiàn)問(wèn)題的一般性的解決方案。1995年, Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides四人合著了一本經(jīng)典巨作《設(shè)計(jì)模式——可復(fù)用面向?qū)ο筌浖幕A(chǔ)》,該書(shū)奠定了堅(jiān)實(shí)的面向?qū)ο笤O(shè)計(jì)模式理論的基礎(chǔ),它介紹了23種基本設(shè)計(jì)模式的結(jié)構(gòu)、特性和使用方法。《設(shè)計(jì)模式》一書(shū)被軟件人士當(dāng)作“模式的圣經(jīng)”,是所有面向?qū)ο蠓治鲈O(shè)計(jì)人員必讀的書(shū)籍。四位作者被大家稱(chēng)為“四人幫”(Gang of Four, GoF)。
由于《設(shè)計(jì)模式——可復(fù)用面向?qū)ο筌浖幕A(chǔ)》一書(shū)奠定了設(shè)計(jì)模式的地位,人們通常所說(shuō)的設(shè)計(jì)模式隱含地表示“面向?qū)ο笤O(shè)計(jì)模式”。但這并不意味“設(shè)計(jì)模式”就等于“面向?qū)ο笤O(shè)計(jì)模式”,也不意味著GoF 23種模式就表示了所有的“面向?qū)ο笤O(shè)計(jì)模式”。除了“面向?qū)ο笤O(shè)計(jì)模式”外,還有其他設(shè)計(jì)模式。除了GoF 23種設(shè)計(jì)模式外,還有更多的面向?qū)ο笤O(shè)計(jì)模式。
面向?qū)ο笤O(shè)計(jì)模式精髓是隱藏在背后的三條面向?qū)ο笤O(shè)計(jì)原則和設(shè)計(jì)理念:適應(yīng)需求的變化;針對(duì)接口編程,而不要針對(duì)實(shí)現(xiàn)編程;優(yōu)先使用聚合,而不是繼承。
根據(jù)目標(biāo)系統(tǒng)的特點(diǎn)和需要,選擇合適的模式加以應(yīng)用,應(yīng)用模式后最大的優(yōu)點(diǎn)就是系統(tǒng)可以適應(yīng)需求的變化,從而具有更好的可復(fù)用性、可擴(kuò)展性和可維護(hù)性。
1.4.2 類(lèi)建模
使用“類(lèi)圖”描述所設(shè)計(jì)的軟件中包含的類(lèi),以及這些類(lèi)之間的靜態(tài)關(guān)系,從而描繪了整個(gè)軟件的靜態(tài)組成和結(jié)構(gòu)。
1.類(lèi)的一般描述圖

(1)類(lèi)名
類(lèi)名即類(lèi)的名稱(chēng)。
(2)屬性
屬性描述的語(yǔ)法:
visibility name [N] : type = initialValue {property-string}
① visibility:屬性的可見(jiàn)性:+ 表示public; # 表示protected; - 表示private。
② name:屬性的名稱(chēng)。
③ [N]:屬性的多值性:[2..*]表示屬性能接受多值;如果屬性描述中無(wú)此項(xiàng),則表示該屬性只允許接受一個(gè)值。
④ type:屬性的實(shí)現(xiàn)類(lèi)型(依賴(lài)于實(shí)現(xiàn)語(yǔ)言的規(guī)范)。
⑤ initialValue:屬性的初始值。
⑥ property-string:表示屬性的一些無(wú)法用上述語(yǔ)法描述的特性。例如,一個(gè)只讀屬性(如C++的const成員或Java的final成員), 則property-string將可以設(shè)置為{frozen}。
(3)操作
操作描述的語(yǔ)法:
visibility name (parameter-list) : return-type {operation-string}
① visibility:操作的可見(jiàn)性:+ 表示public; # 表示protected; - 表示private。
② name:操作的名稱(chēng)。
③ parameter-list:操作的形參列表,表中允許有多個(gè)形參,形參之間由逗號(hào)分隔。每個(gè)參數(shù)的表示語(yǔ)法:kind name : type = defaultValue。
● kind:表示參數(shù)的作用分類(lèi)
in表示參數(shù)向操作中傳入一個(gè)值。
out表示參數(shù)從操作中提取一個(gè)值。
inout表示參數(shù)既可以向操作中傳入一個(gè)值又可以從操作中提取一個(gè)值。
● name:表示形參名。
● type:表示形參類(lèi)型。
● defaultValue:表示形參的默認(rèn)值。
④ return-type:操作的返回類(lèi)型(因編譯器而異)。
⑤ operation-string:表示操作的一些無(wú)法用上述語(yǔ)法描述的特性。例如,一個(gè)操作是抽象操作,則operation-string可以設(shè)置為{abstract}。
2.類(lèi)的相互關(guān)系圖
用于描述類(lèi)之間的靜態(tài)關(guān)系。在關(guān)系圖中的類(lèi)圖除了類(lèi)名部分不能省略外,其他兩部分都可以根據(jù)需要省略。主要的靜態(tài)關(guān)系有:
(1)歸納關(guān)系(Generalization)
歸納關(guān)系表示兩個(gè)類(lèi)之間的繼承和派生關(guān)系,如右圖中的類(lèi)Employee是類(lèi)Manager的超類(lèi)(基類(lèi)),而類(lèi)Manager是類(lèi)Employee的子類(lèi)(派生類(lèi))。

(2)關(guān)聯(lián)關(guān)系(Association)
關(guān)聯(lián)關(guān)系表示兩個(gè)類(lèi)之間的關(guān)聯(lián)關(guān)系,如下圖中類(lèi)Employee和類(lèi)Corporation之間的關(guān)聯(lián)關(guān)系。

圖中employeeBy是Employee的屬性成員,其類(lèi)型為Corporation。通過(guò)該屬性employeeBy使兩個(gè)類(lèi)關(guān)聯(lián);0..1表示關(guān)聯(lián)的多樣性,此關(guān)聯(lián)表示一個(gè)Employee對(duì)象不會(huì)被超過(guò)一個(gè)Corporation對(duì)象所雇用。同樣,employees是Corporation的屬性成員,其類(lèi)型為Employee。*表示一個(gè)Corporation對(duì)象允許有0至任意數(shù)量的Employee對(duì)象,即雇用任意多個(gè)雇員。上述兩端關(guān)聯(lián)關(guān)系也可以用兩條箭頭線分別表示,箭頭線的方向是從關(guān)聯(lián)屬性所在類(lèi)指向?qū)傩缘念?lèi)型類(lèi)。
下面的關(guān)聯(lián)關(guān)系表示同一類(lèi)的兩個(gè)以上不同對(duì)象間的關(guān)聯(lián)。它的含義是該雇員可以管理1~10個(gè)其他員工。

注意,參與一個(gè)關(guān)聯(lián)的兩個(gè)對(duì)象常常是獨(dú)立存在的,即關(guān)聯(lián)關(guān)系中的一個(gè)對(duì)象的存在與否不會(huì)影響到所關(guān)聯(lián)的另一個(gè)對(duì)象的存在。
(3)類(lèi)之間的聚合和合成關(guān)系
表示對(duì)象之間的“整體”和“部分”之間的關(guān)系,即在整體和部分之間可能存在生命期的依賴(lài)性。合成關(guān)系表示當(dāng)整體不再存在時(shí),部分同時(shí)被銷(xiāo)毀的緊密關(guān)系。例如,下圖中的Window和Slider、TitleBar、Panel之間的關(guān)系。

聚合關(guān)系表示當(dāng)整體不再存在之后,部分還會(huì)繼續(xù)存在的關(guān)系。例如,類(lèi)Orchestra和Performer之間的關(guān)系。當(dāng)然這種關(guān)系也可以通過(guò)前面介紹過(guò)的關(guān)聯(lián)關(guān)系表示。但是,聚合關(guān)系可以很形象地說(shuō)明一些概念。如本例中說(shuō)明:樂(lè)隊(duì)是由演奏人員所組成的,但樂(lè)隊(duì)的生存期與演奏人員的壽命并不存在緊密依賴(lài)的關(guān)系。
(4)類(lèi)模板和類(lèi)模板的實(shí)例化
類(lèi)模板是具有成員類(lèi)型參數(shù)的類(lèi)。例如,下圖中的類(lèi)就是一個(gè)具有兩種成員類(lèi)型參數(shù)T和Y的類(lèi)模板,和將該類(lèi)模板的成員類(lèi)型實(shí)例化后的類(lèi)。


(5)類(lèi)的實(shí)例——對(duì)象
對(duì)象是按照類(lèi)定義創(chuàng)建的實(shí)例,在對(duì)象的圖形描述中實(shí)例被命名,同時(shí)類(lèi)的各個(gè)屬性被賦予特定的值。例如,下圖就是一個(gè)用Employee類(lèi)創(chuàng)建的對(duì)象john_1。

顯然,在建模的主要工作——類(lèi)設(shè)計(jì)中,使用類(lèi)圖是十分必要的,也是十分方便的。
1.4.3 狀態(tài)圖建模
狀態(tài)圖最適合用于顯示一個(gè)類(lèi)對(duì)象在經(jīng)歷一系列相關(guān)用例的過(guò)程中,所呈現(xiàn)的不同狀態(tài)。它們可以幫助我們更好地理解一個(gè)OO程序中單一對(duì)象的生命期行為。狀態(tài)圖主要由三種圖示構(gòu)件組成:
① 對(duì)象狀態(tài):對(duì)象的一個(gè)狀態(tài)用圓角矩形表示。在該矩形中,狀態(tài)名稱(chēng)用粗體字顯示在矩形最上方;如果還有額外信息,用一條線將這些額外信息與狀態(tài)名分隔開(kāi),以“do:/”為前綴的信息項(xiàng)目表示處于此狀態(tài)下的一個(gè)活動(dòng)。開(kāi)始和結(jié)束是兩個(gè)特殊狀態(tài)。
② 轉(zhuǎn)換路徑:對(duì)象從一個(gè)狀態(tài)轉(zhuǎn)換到另一個(gè)狀態(tài)用一條箭頭線(箭頭指向轉(zhuǎn)換后的狀態(tài))表示。
③ 狀態(tài)轉(zhuǎn)換標(biāo)簽:描述引起狀態(tài)轉(zhuǎn)換的原因,描述語(yǔ)法是
Event[Guard]/Action
該語(yǔ)法的含義是:事件Event的出現(xiàn)將導(dǎo)致以Guard為條件的狀態(tài)轉(zhuǎn)換結(jié)果為T(mén)RUE。但在實(shí)際轉(zhuǎn)換到新?tīng)顟B(tài)之前,動(dòng)作Action必須先執(zhí)行。由于對(duì)象從一個(gè)狀態(tài)到其他狀態(tài)只能進(jìn)行一次轉(zhuǎn)換,因此從一個(gè)給定狀態(tài)可能出現(xiàn)的所有轉(zhuǎn)換路徑必須相互排斥。注意,轉(zhuǎn)換描述的三個(gè)部分(事件、條件和動(dòng)作)都是可選擇的。
圖1.3描述了一次拍賣(mài)程序中Buyer對(duì)象的一個(gè)狀態(tài)圖。

圖1.3 Buyer對(duì)象的一個(gè)狀態(tài)圖
顯然,使用狀態(tài)圖對(duì)類(lèi)對(duì)象的深入研究是有效的,但并不是必不可少的。在建模的過(guò)程中是否需要使用狀態(tài)圖對(duì)類(lèi)對(duì)象的生存過(guò)程進(jìn)行狀態(tài)進(jìn)行,一般與軟件的復(fù)雜程度有關(guān)。通常情況下,一個(gè)簡(jiǎn)單的軟件建模中,不需要繪制狀態(tài)圖。
1.4.4 順序圖建模
順序圖按時(shí)間順序描述了參與功能事務(wù)的一組對(duì)象在功能事務(wù)的執(zhí)行過(guò)程中的交互操作。構(gòu)成順序圖的要素如下(見(jiàn)圖1.4)。

圖1.4 順序圖的要素
圖1.5的順序圖描述了在網(wǎng)上拍賣(mài)事務(wù)中,銷(xiāo)售者對(duì)象和競(jìng)拍者對(duì)象,以及完成一次拍賣(mài)事務(wù)所需要的其他服務(wù)對(duì)象之間相互協(xié)作的順序圖。

圖1.5 對(duì)象之間相互協(xié)作的順序圖
圖中的各種類(lèi)型的交互消息必須遵循以下6種語(yǔ)法規(guī)則:
① 狀態(tài)消息:由一個(gè)對(duì)象將一個(gè)狀態(tài)值轉(zhuǎn)送給另一個(gè)對(duì)象,例如:[bidAcceptable]。
② 方法名:一個(gè)對(duì)象調(diào)用另一個(gè)對(duì)象的方法。例如:selectItem( )。
③ *[迭代依據(jù)]方法:其中“*”是迭代標(biāo)記。這個(gè)命名方法在目標(biāo)對(duì)象的多個(gè)實(shí)例上調(diào)用,至于具體在哪個(gè)實(shí)例上調(diào)用則由方括號(hào)中的表達(dá)式控制。例如:*[for all items in Auctionlist] getCurrentMaxBid( )。
④ flag := 方法:flag被設(shè)置為T(mén)RUE或FALSE,這取決于在這條消息接收對(duì)象上調(diào)用這個(gè)指定的方法所產(chǎn)生的結(jié)果。例如:minAcceptBidExceeded := check( )。
⑤ [條件]方法:只有在條件滿(mǎn)足時(shí)才在消息接收對(duì)象上調(diào)用這個(gè)指定的方法。例如:[minAcceptBidExceeded] notifySeller( )。
⑥ 特殊符號(hào)new:表示創(chuàng)建消息接收對(duì)象的新實(shí)例。例如:[bidAccepttable] new。
由于順序圖既能較好地描述功能事務(wù)執(zhí)行過(guò)程中各個(gè)參與對(duì)象的動(dòng)作順序,又能較好地描述對(duì)象之間的交互操作,因此,一般多用順序圖來(lái)描述類(lèi)之間的動(dòng)態(tài)交互關(guān)系。
1.4.5 協(xié)作圖建模
協(xié)作圖著眼于參與功能事務(wù)的一組對(duì)象在功能事務(wù)的執(zhí)行過(guò)程中的相互協(xié)作關(guān)系,而不按照?qǐng)?zhí)行過(guò)程的時(shí)間順序描述對(duì)象之間的交互操作。協(xié)作圖雖然在表示對(duì)象之間的交互操作方面優(yōu)于順序圖,但在其他方面都不及順序圖,因此,一般只用于順序圖所描述的類(lèi)之間動(dòng)態(tài)交互關(guān)系的補(bǔ)充。上述的網(wǎng)上拍賣(mài)事務(wù)的協(xié)作圖如圖1.6所示。

圖1.6 網(wǎng)上拍賣(mài)事務(wù)的協(xié)作圖
不難看出,使用類(lèi)的交互關(guān)系圖(特別是“順序圖”)對(duì)于類(lèi)設(shè)計(jì)中研究類(lèi)的屬性和行為,最后確定類(lèi)的結(jié)構(gòu)和接口設(shè)計(jì)是必不可少的,也是十分方便的。
1.4.6 活動(dòng)圖建模
活動(dòng)圖描述如何通過(guò)一組相互協(xié)作的活動(dòng)產(chǎn)生一個(gè)期望的結(jié)果。在創(chuàng)建活動(dòng)圖時(shí)需要注意的一個(gè)重要問(wèn)題是:確認(rèn)那些可以同時(shí)執(zhí)行的子活動(dòng)(通過(guò)多進(jìn)程或多線程)以及那些必須線性順序執(zhí)行的子活動(dòng)。活動(dòng)圖中的主要圖示構(gòu)件如下所示。
① 活動(dòng):用橢圓矩形表示。

② 觸發(fā)器:用指向活動(dòng)和從活動(dòng)出來(lái)的箭頭線表示。一個(gè)活動(dòng)有流入觸發(fā)器,表示這個(gè)活動(dòng)可以在接收到這個(gè)觸發(fā)器時(shí)執(zhí)行,在絕大多數(shù)情況下前一個(gè)活動(dòng)的成功執(zhí)行就是觸發(fā)器源(流出觸發(fā)器)。對(duì)于具有多個(gè)流入觸發(fā)器的活動(dòng)而言,它是非連接性的。這意味著如果這個(gè)活動(dòng)收到其中一條觸發(fā),目標(biāo)活動(dòng)將會(huì)執(zhí)行。

③ 同步杠:用一條雙線或一條粗黑線表示。一些活動(dòng)流入它,一些活動(dòng)自它流出,并且它帶有附加條件[condition]。對(duì)于流入活動(dòng),同步杠是連接性(conjunctive)的,即所有流入的活動(dòng)必須在控制到達(dá)同步杠之前成功執(zhí)行。這些流入活動(dòng)的成功執(zhí)行受制于同步杠的附加條件。對(duì)于流出活動(dòng),同步杠表示這些活動(dòng)允許并發(fā)執(zhí)行,彼此之間相互獨(dú)立。

④ 判定活動(dòng):在絕大多數(shù)情況下,判定活動(dòng)是通過(guò)測(cè)試一個(gè)布爾值來(lái)實(shí)現(xiàn)的。這類(lèi)活動(dòng)是由一個(gè)菱形表示的,如下圖所示。

圖1.7顯示了拍賣(mài)處理過(guò)程的活動(dòng)圖。圖中那些可以并發(fā)進(jìn)行的活動(dòng)是從標(biāo)簽為“fork”的同步杠中流出的。標(biāo)簽為“merge”的同步杠用于表示一個(gè)條件,就是發(fā)生在該同步杠上的多個(gè)活動(dòng)必須同時(shí)成功結(jié)束,控制流才能繼續(xù)向前。特別要注意從P到Q的活動(dòng)段。在P處與同步杠相關(guān)聯(lián)的條件是
*[for each item in the group]
這里的“*”表示多個(gè)觸發(fā)器,就是說(shuō)它指定了從P到Q所顯示的活動(dòng)線程實(shí)際上由一組平行的線程所組成,每個(gè)線程都由圖中所示的活動(dòng)組成。因此,在P處源于同步杠的并發(fā)路徑的數(shù)量等于購(gòu)買(mǎi)者感興趣的那組項(xiàng)目的數(shù)量。

圖1.7 拍賣(mài)處理過(guò)程的活動(dòng)圖
不難看出,UML的活動(dòng)圖與一般的程序流程圖在形狀和作用上是類(lèi)似的,但活動(dòng)圖的描述能力要遠(yuǎn)遠(yuǎn)超過(guò)一般的程序流程圖。在模型中使用活動(dòng)圖來(lái)討論和描述軟件的部分和整個(gè)運(yùn)行過(guò)程的活動(dòng)也是必要的。
1.4.7 用戶(hù)界面設(shè)計(jì)
1.交互設(shè)計(jì)
用戶(hù)界面設(shè)計(jì)的目標(biāo)就是使軟件讓用戶(hù)能簡(jiǎn)單使用。任何軟件功能的實(shí)現(xiàn)都是通過(guò)人和計(jì)算機(jī)的交互完成的,因此,人的因素應(yīng)作為設(shè)計(jì)的核心被體現(xiàn)出來(lái),界面設(shè)計(jì)的原則如下:
① 執(zhí)行有較大破壞性的動(dòng)作前要求確認(rèn)。
② 允許用戶(hù)非惡意錯(cuò)誤,系統(tǒng)應(yīng)保護(hù)自己不受致命錯(cuò)誤的破壞。
③ 只顯示與當(dāng)前用戶(hù)語(yǔ)境環(huán)境有關(guān)的信息。
④ 盡量減少用戶(hù)輸入動(dòng)作的數(shù)量。
⑤ 維護(hù)信息顯示和數(shù)據(jù)輸入的一致性。
⑥ 允許兼用鍵盤(pán)和鼠標(biāo)。
⑦ 使用軟件最終用戶(hù)的語(yǔ)言,而不是計(jì)算機(jī)專(zhuān)用術(shù)語(yǔ)。
⑧ 詳盡的幫助信息。
⑨ 允許工作中斷,例如:本次操作到一半,可以把中間狀態(tài)暫存,下次啟動(dòng)軟件可以繼續(xù)完成。
⑩ 有清楚的錯(cuò)誤提示,誤操作后,軟件提供有針對(duì)性地提示。
?提供快速反饋,給用戶(hù)心理上的暗示,避免用戶(hù)焦急。如時(shí)間較長(zhǎng)的操作響應(yīng)期間,可以出現(xiàn)進(jìn)度條顯示操作進(jìn)度。
2.視覺(jué)設(shè)計(jì)
① 堅(jiān)持圖形用戶(hù)界面(GUI)設(shè)計(jì)原則:界面直觀、對(duì)用戶(hù)透明:用戶(hù)使用軟件后對(duì)界面上對(duì)應(yīng)的功能一目了然、不需要過(guò)多培訓(xùn)就可以使用軟件。
② 界面一致性原則:在界面設(shè)計(jì)中應(yīng)該保持界面的一致性。一致性既包括使用標(biāo)準(zhǔn)的控件,也指使用相同的信息表現(xiàn)方法,如在字體、標(biāo)簽風(fēng)格、顏色、術(shù)語(yǔ)、顯示錯(cuò)誤信息等方面確保一致。
1.5 面向?qū)ο缶幊?/h2>
1.5.1從設(shè)計(jì)到C++代碼
為了把面向?qū)ο笤O(shè)計(jì)結(jié)果順利地轉(zhuǎn)變成面向?qū)ο蟪绦颍紫葢?yīng)該選擇一種適當(dāng)?shù)某绦蛟O(shè)計(jì)語(yǔ)言。面向?qū)ο蟮某绦蛟O(shè)計(jì)語(yǔ)言適合用來(lái)實(shí)現(xiàn)面向?qū)ο笤O(shè)計(jì)結(jié)果。事實(shí)上,具有方便的開(kāi)發(fā)環(huán)境和豐富的類(lèi)庫(kù)的面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言,是實(shí)現(xiàn)面向?qū)ο笤O(shè)計(jì)的最佳選擇。
良好的程序設(shè)計(jì)風(fēng)格對(duì)于面向?qū)ο髮?shí)現(xiàn)來(lái)說(shuō)格外重要。它既包括傳統(tǒng)的程序設(shè)計(jì)風(fēng)格準(zhǔn)則,也包括與面向?qū)ο蠓椒ǖ奶攸c(diǎn)相適應(yīng)的一些新準(zhǔn)則。
在軟件生命周期中,編碼工作在整個(gè)項(xiàng)目中所占的比例最多不會(huì)超過(guò)1/2,通常在1/3的時(shí)間,所謂磨刀不誤砍柴工,設(shè)計(jì)過(guò)程完成的好,編碼效率就會(huì)極大提高。有人說(shuō),用C語(yǔ)言編寫(xiě)代碼,代碼量超過(guò)10 000行就會(huì)失控,用C++,這個(gè)限制可以放寬到100 000行。這說(shuō)明面向?qū)ο笳Z(yǔ)言要比非面向?qū)ο笳Z(yǔ)言能夠支持更大規(guī)模的軟件。
我們知道,在一個(gè)小企業(yè)中,沒(méi)有什么管理成本,管理人員也很少。但是一個(gè)大企業(yè),一般有很多的管理人員,因?yàn)槠髽I(yè)規(guī)模增大之后,需要付出管理成本。這些管理人員的主要職責(zé),就是管理那些能夠直接產(chǎn)生效益的工作人員。我們還知道,現(xiàn)代社會(huì)存在的基礎(chǔ)是分工,分工明確,每個(gè)人做的事情少而精,這樣整個(gè)社會(huì)就會(huì)有效率。而面向?qū)ο笳w現(xiàn)了這兩種思路。首先,一個(gè)面向?qū)ο蟮能浖渲袝?huì)有很多看起來(lái)什么都不做的代碼,只是簡(jiǎn)單地把對(duì)它的調(diào)用轉(zhuǎn)給另一個(gè)對(duì)象的方法,有的只是做一些判斷,或是類(lèi)型處理。這些代碼看起來(lái)有些浪費(fèi)。但是它們就好像是企業(yè)的管理者一樣,雖然消耗了一些資源(所幸的是,面向?qū)ο笳Z(yǔ)言設(shè)計(jì)的高效性讓這種資源消耗是可接受的),但是它們能夠讓其他產(chǎn)生效益的代碼工作更加有效。其次,面向?qū)ο蠓浅W⒅仡?lèi)的職責(zé),每個(gè)類(lèi)處理的事情集中而單一,每個(gè)方法的目標(biāo)都十分專(zhuān)一。一件事情一般是幾個(gè)類(lèi)共同完成的,而不是像傳統(tǒng)方法那樣,一個(gè)函數(shù)一包到底。
1.5.2 編程舉例
實(shí)驗(yàn)描繪:編寫(xiě)一個(gè)能模擬簡(jiǎn)單猜?lián)淇伺拼笮∮螒虻膽?yīng)用程序。該游戲的名稱(chēng)為Hi-Low,其玩法和規(guī)則如下所述。
1.玩法
① 洗牌:每盤(pán)游戲開(kāi)始之前,使撲克牌的排列順序充分隨機(jī)。
② 發(fā)牌:每局開(kāi)始時(shí),從未使用的撲克牌集合中順序發(fā)給玩家5張撲克牌(明牌)。
③ 猜點(diǎn):從未使用的撲克牌集合中按順序取出一張撲克牌(即莊家的暗牌),要求玩家將手中的第一張撲克牌和這張莊家的暗牌進(jìn)行比較,確定哪張牌大?
④ 積分:玩家確定回答后,翻開(kāi)被猜的撲克牌(暗牌變成明牌),同時(shí)根據(jù)玩家回答的正確與否顯示相應(yīng)的提示,并為玩家的游戲成績(jī)積分。然后將這兩張已經(jīng)比較過(guò)的牌回收到已經(jīng)使用過(guò)的撲克牌集合中,玩家手中的下一張撲克牌成為新的一張撲克牌。
⑤ 對(duì)玩家手中剩余的撲克牌順序重復(fù)第③和④步操作,直至玩家手中不再有剩余的撲克牌時(shí),一局游戲結(jié)束。
⑤ 如果未使用的撲克牌集合中的撲克牌數(shù)目多余10張,則從第②步開(kāi)始進(jìn)行本盤(pán)游戲的下一局。
⑦ 詢(xún)問(wèn)玩家是否繼續(xù)進(jìn)行下一盤(pán)游戲,如果繼續(xù),則從第①步開(kāi)始進(jìn)行新的一盤(pán)游戲。
2.規(guī)則
① 積分規(guī)則:
● 猜中1次,積1分;猜錯(cuò)1次,不積分。
● 1局中連續(xù)猜中3次,除正常積分外獎(jiǎng)勵(lì)1分;連續(xù)猜錯(cuò)3次,罰1分。
● 1局全部猜中,除正常積分外獎(jiǎng)勵(lì)3分;1局全部猜錯(cuò),罰3分。
● 玩家的最低積分為0,即不出現(xiàn)負(fù)分。
② 牌面大小比較規(guī)則:每張撲克牌的牌面由花色(梅花Club、方塊Diamond、紅心Heart和黑桃Spade)和牌點(diǎn)(A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K)組成。
確定兩張撲克牌牌面大小的規(guī)則有兩條:
● 如果兩張牌面的牌點(diǎn)不同,則牌面大小僅與牌點(diǎn)有關(guān),而與牌面的花色無(wú)關(guān)。牌點(diǎn)的大小順序?yàn)椋? < 3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 < J < Q < K < A。
● 如果兩張牌面的牌點(diǎn)相同,則牌面大小僅與牌面的花色有關(guān)。花色的大小順序?yàn)椋篊lub < Diamond < Heart < Spade。
3.要求
① 按照面向?qū)ο蟮乃枷敕治鲱}意要求實(shí)現(xiàn)的需求,合理地分解對(duì)象類(lèi)。
② 設(shè)計(jì)和實(shí)現(xiàn)各個(gè)組成類(lèi)。
③ 在主函數(shù)main( )中,創(chuàng)建各個(gè)組成類(lèi)對(duì)象,并通過(guò)這些類(lèi)對(duì)象使用類(lèi)功能實(shí)現(xiàn)游戲Hi-Low。
④ 要求編寫(xiě)編程文檔,文檔內(nèi)容包括:
● 繪制各個(gè)組成類(lèi)的類(lèi)圖與類(lèi)圖之間的靜態(tài)關(guān)系圖。
● 各個(gè)組成類(lèi)的類(lèi)定義描述。
● 主要功能函數(shù)的算法描述。
● main( )函數(shù)的流程圖。
4.分析
分析各種撲克牌游戲,可以歸納出如下幾條規(guī)律。
① 一副撲克牌,即撲克牌的全集是有54張具有不同牌面的撲克牌組成的。
② 任何一種撲克牌游戲都需要使用由n張撲克牌組成的集合,該集合可以是一副撲克牌的全集,也可以是一副撲克牌的子集,甚至可以是多副撲克牌的并集。例如Hi-Low游戲需要使用一副撲克牌中除大小王牌以外的52張牌組成的子集。
③ 任何一種撲克牌游戲都會(huì)根據(jù)自己的玩法和規(guī)則,確定一種若干步特定操作構(gòu)成的游戲程式。
④ 每一種撲克牌游戲都會(huì)根據(jù)積分規(guī)則確定一個(gè)相對(duì)獨(dú)立的積分計(jì)算器,依據(jù)游戲結(jié)果為玩家計(jì)算積分。
根據(jù)上述分析,可以考慮進(jìn)行如下的對(duì)象類(lèi)分解。
① 將撲克牌對(duì)象設(shè)計(jì)為一個(gè)類(lèi)Card,用于定義標(biāo)示每一張?zhí)囟〒淇伺频呐泼妫ɑㄉ团泣c(diǎn))和顯示操作。為此該類(lèi)可以用如下屬性和操作描述。
屬性
● 索引標(biāo)志屬性index作為每張撲克牌唯一標(biāo)志,是確定牌面花色和牌點(diǎn)的依據(jù)。該屬性應(yīng)聲明為私有,它的值域?yàn)?~53的整數(shù)值,每一個(gè)index值與一張?zhí)囟ㄅ泼娴幕ㄉ团泣c(diǎn)相對(duì)應(yīng):
0~12對(duì)應(yīng)梅花Club的A 2 3 4 5 6 7 8 9 10 J Q K
13~25對(duì)應(yīng)方塊Diamond的A 2 3 4 5 6 7 8 9 10 J Q K
26~38對(duì)應(yīng)紅心Heart的A 2 3 4 5 6 7 8 9 10 J Q K
39~51對(duì)應(yīng)黑桃Spade的A 2 3 4 5 6 7 8 9 10 J Q K
52對(duì)應(yīng)小王牌L Trump
53對(duì)應(yīng)大王牌B Trump
顯然,index除以13所得到的整數(shù)商可以表示花色,而index模13所得到的余數(shù)恰恰是牌點(diǎn)。大小王牌的index值除外。
● 牌面顯示屬性face。在圖形用戶(hù)界面的應(yīng)用程序中該屬性是描述牌面圖形的復(fù)雜圖形類(lèi);而在控制臺(tái)文本界面的應(yīng)用程序中該屬性可以是字符數(shù)組類(lèi)型, 用于存放描述牌面的字符串。例如:“C-A”表示梅花A, “D-6”表示方塊6, “H-10”表示紅心10,“S-Q”表示黑桃Q, “LT”表示小王牌,“BT”表示大王牌等。該屬性應(yīng)聲明為私有。
操作
● 構(gòu)造函數(shù):無(wú)參數(shù),便于創(chuàng)建對(duì)象數(shù)組。
● 初始化操作Init:依據(jù)傳入?yún)?shù)值,為索引標(biāo)志屬性index賦值,并確定牌面顯示屬性face。該操作應(yīng)向外提供服務(wù)。
● 獲取標(biāo)志操作Index:返回索引標(biāo)志屬性index的當(dāng)前值。該操作應(yīng)向外提供服務(wù)。
● 顯示牌面操作Show:輸出牌面顯示屬性face。該操作應(yīng)向外提供服務(wù)。
② 考慮到結(jié)構(gòu)的合理性,可以將計(jì)算游戲積分所需要屬性和操作封裝在一個(gè)類(lèi)中。該類(lèi)可以命名為Counter,它所包含的屬性和操作如下。
屬性
● 積分屬性score:用于記錄游戲的積分值。為了能記錄足夠大的積分值,該屬性應(yīng)聲明為長(zhǎng)整型long。
● 連續(xù)標(biāo)志屬性sequence:用于存放玩家當(dāng)前猜點(diǎn)操作的連續(xù)狀態(tài):
連續(xù)猜中時(shí),sequence > 0(連續(xù)猜中的次數(shù))。
連續(xù)猜錯(cuò)時(shí),sequence < 0(連續(xù)猜錯(cuò)的次數(shù))。
即未連續(xù)猜中,也未連續(xù)猜錯(cuò)時(shí),sequence = 0。
操作
● 構(gòu)造函數(shù):將積分屬性score和連續(xù)標(biāo)志屬性sequence初始設(shè)置為0。
● 累計(jì)積分操作accumulate:根據(jù)玩家當(dāng)前猜點(diǎn)操作的結(jié)果(布爾類(lèi)型值,過(guò)實(shí)參傳遞該操作)修改玩家當(dāng)前的連續(xù)猜中狀態(tài)sequence,并根據(jù)猜點(diǎn)操作的結(jié)果和連續(xù)猜中狀態(tài),按積分規(guī)則玩家累計(jì)積分。該操作應(yīng)向外提供服務(wù)。
● 顯示積分操作Show:顯示游戲積分值。該操作應(yīng)向外提供服務(wù)。
● 清除連續(xù)標(biāo)志操作ClearSequece:在游戲新的一盤(pán)開(kāi)始前,設(shè)置Sequece為0。
③ 根據(jù)撲克牌游戲的玩法和規(guī)則,將撲克牌游戲設(shè)計(jì)成一個(gè)類(lèi)。在類(lèi)的定義中描述游戲所需要使用的撲克牌集合和所需要的輔助屬性,以及滿(mǎn)足游戲玩法和規(guī)則的各種操作。本題中的撲克牌游戲類(lèi)可以直觀地命名為HiLow,它應(yīng)該包括如下屬性和操作。
屬性
● 撲克牌集合屬性container:存放HiLow游戲所要使用的52張撲克牌(大小王牌除外)。該屬性是一個(gè)Card類(lèi)型的數(shù)組。
● 已用牌索引屬性u(píng)sedIndex:指示container中游戲已經(jīng)使用過(guò)的撲克牌的索引。每盤(pán)游戲開(kāi)始時(shí),該屬性應(yīng)被初始化為0(container的第一個(gè)元素的下標(biāo)值);以后每次從container獲取一張牌(為玩家每發(fā)一張牌,取一張被猜的牌)后,屬性值加1。該屬性的值域?yàn)? ≤ usedIndex≥ 51。
● 玩家牌索引屬性playIndex:指示當(dāng)前玩家手中正在進(jìn)行猜點(diǎn)操作的牌在container中的索引。每局游戲開(kāi)始時(shí),該屬性值 = usedIndex;以后每次猜點(diǎn)操作完成后,屬性值加1。該屬性的值域?yàn)? ≤ playIndex ≥ 51。
● 積分計(jì)算器屬性counter:該屬性是一個(gè)Counter類(lèi)對(duì)象,用于為游戲提供積分管理。
操作
● 構(gòu)造函數(shù):完成HiLow游戲?qū)ο蟮膭?chuàng)建。在此創(chuàng)建操作中要完成各個(gè)屬性必要的初始化,其中對(duì)container中每個(gè)元素的初始化是委托card的Init操作完成的。
● 洗牌操作Shuffle:該操作應(yīng)向外提供服務(wù),用于container中的元素(撲克牌)進(jìn)行隨機(jī)排列。模擬真實(shí)的洗牌操作可以通過(guò)52次將container中的兩個(gè)隨機(jī)下標(biāo)索引的元素進(jìn)行交換操作來(lái)實(shí)現(xiàn)。產(chǎn)生隨機(jī)下標(biāo)可以調(diào)用庫(kù)函數(shù)rand來(lái)完成,52次交換操作就需要調(diào)用rand 104次。值得注意的是, 在第一次調(diào)用rand之前應(yīng)該調(diào)用另一個(gè)庫(kù)函數(shù)srand為隨機(jī)數(shù)發(fā)生器播種,即初始隨機(jī)值,否則每次洗牌所產(chǎn)生的104個(gè)隨機(jī)值序列都是一樣的。獲得這個(gè)初始隨機(jī)值的最好方法就是調(diào)用庫(kù)函數(shù)time獲取當(dāng)前的時(shí)間值作為初始隨機(jī)值。因此調(diào)用srand為隨機(jī)數(shù)發(fā)生器播種的表達(dá)式可以寫(xiě)為
srand((unsigned)time(NULL));
庫(kù)函數(shù)rand和srand的原型聲明在系統(tǒng)頭文件stdlib.h中;庫(kù)函數(shù)time的原型聲明在系統(tǒng)頭文件time.h中。另外,庫(kù)函數(shù)rand所產(chǎn)生隨機(jī)數(shù)的值域范圍是0至整型數(shù)最大值,可以通過(guò)對(duì)函數(shù)的返回值模52運(yùn)算,獲得值域范圍為0~51的隨機(jī)下標(biāo)值。調(diào)用洗牌操作意味著新的一盤(pán)游戲的開(kāi)始,因此,在上述隨機(jī)排列操作完成后,需要將usedIndex和playIndex設(shè)置為0,還需要委托積分計(jì)算器屬性counter清除積分連續(xù)標(biāo)志(sequence = 0)。
● 交換操作Swap:用于container中兩個(gè)指定元素的位置交換操作,這是洗牌需要頻繁使用的操作。該操作只為HiLow對(duì)象提供私有服務(wù),不必向外提供服務(wù)。索引兩個(gè)進(jìn)行交換操作的元素的下標(biāo)是作為實(shí)參傳遞給該操作的。
● 發(fā)牌操作Deal:該操作應(yīng)向外提供服務(wù),用于每次為玩家發(fā)5張撲克牌。完成這一操作只需調(diào)整usedIndex和playIndex的值,而無(wú)須發(fā)生撲克牌的獲取操作。
● 顯示玩家手中牌的操作PlaycardShow:該操作應(yīng)向外提供服務(wù),用于顯示當(dāng)前玩家手中所有可以用猜牌操作的撲克牌的牌面信息。這些牌的索引范圍是playIndex至playIndex+4。
● 比較操作Compare:該操作應(yīng)向外提供服務(wù),用于一次比較玩家明牌和莊家暗牌大小的操作,并返回比較結(jié)果(布爾)標(biāo)志(玩家牌大為ture,否則為false)。被猜的兩張牌的索引可以通過(guò)playIndex和usedIndex獲得(注意訪問(wèn)后,需要對(duì)這兩個(gè)屬性值增1,以便索引下一次進(jìn)行比較的兩張牌)。
● 顯示猜牌結(jié)果操作ResultShow:該操作應(yīng)向外提供服務(wù),用于在比較操作Compare被調(diào)用后,顯示用于比較大小的玩家牌和莊家牌的牌面信息,并根據(jù)比較結(jié)果(作為實(shí)參傳遞給操作)顯示相應(yīng)的提示信息。注意,被顯示的兩張牌的索引是playIndex-1至usedIndex-1。
● 積分操作accumulate:該操作應(yīng)向外提供服務(wù),該操作是根據(jù)玩家的本次猜牌結(jié)果(布爾)標(biāo)志(猜中為true,否則為false),委托積分計(jì)算器counter,完成玩家的游戲積分計(jì)算和管理。玩家的本次猜牌結(jié)果應(yīng)通過(guò)布爾類(lèi)型實(shí)參傳遞給操作的。
● 判斷一局結(jié)束操作IsGameOver:該操作應(yīng)向外提供服務(wù),用于提供游戲的局結(jié)束(布爾)標(biāo)志(結(jié)束為ture,未結(jié)束為false)。如何判斷一局是否結(jié)束,可以通過(guò)分析playIndex值的變化規(guī)律發(fā)現(xiàn)。注意,如果一局結(jié)束,還需要委托積分計(jì)算器counter清除積分連續(xù)標(biāo)志(sequence = 0)。
● 判斷一盤(pán)結(jié)束操作IsSetOver:該操作應(yīng)向外提供服務(wù),用于提供游戲的盤(pán)結(jié)束(布爾)標(biāo)志(結(jié)束為ture,未結(jié)束為false)。如何判斷一盤(pán)是否結(jié)束,可以通過(guò)分析usedIndex值的變化規(guī)律發(fā)現(xiàn)。
● 顯示游戲積分ScoreShow:該操作應(yīng)向外提供服務(wù),用于顯示玩家的當(dāng)前游戲積分。此操作是委托積分計(jì)算器屬性counter提供的。
在主函數(shù)main( )中創(chuàng)建HiLow類(lèi)游戲?qū)ο螅褂迷搶?duì)象提供各項(xiàng)操作功能,實(shí)現(xiàn)游戲的玩法所要求的操作和控制。注意,在游戲的各步操作中應(yīng)提供恰當(dāng)?shù)奶崾拘畔ⅲ员闾峁┯押玫牟僮鹘缑妗?/p>
5.參考實(shí)現(xiàn)
(1)各個(gè)組成類(lèi)的類(lèi)圖
① Card類(lèi)

② Counter類(lèi)

③ Menu類(lèi)

④ HiLow類(lèi)


(2)類(lèi)之間的靜態(tài)關(guān)系圖

(3)各個(gè)組成類(lèi)的類(lèi)定義描述
① Card類(lèi)
class Card { private: int index; // 索引標(biāo)志屬性,作為每張撲克牌唯一標(biāo)志,是確定 // 牌面花色和牌點(diǎn)的依據(jù)。值域?yàn)?~53的整數(shù)值。 char* face; // 用于存放描述牌面的字符串。每張撲克牌的牌面由 // 花色(梅花Club、方塊Diamond、紅心Heart和 // 黑桃Spade)和牌點(diǎn)(A, 2, 3, 4, 5, 6, 7, 8, 9, // 10, J, Q, K)組成。 public: Card( ); // 構(gòu)造函數(shù)。 ~Card( ); // 析構(gòu)函數(shù)。 void Init(int inIndex); // 依據(jù)傳入?yún)?shù)值,為索引標(biāo)志屬性index賦值,并確 // 定牌面顯示屬性face。 int Index( ) const; // 返回索引標(biāo)志屬性index的當(dāng)前值。 void Show( ) const; // 輸出牌面顯示屬性face。 };
② Counter類(lèi)
class Counter { private: long score; // 用于記錄游戲的積分值。 int sequence; // 用于存放玩家當(dāng)前猜點(diǎn)操作的連續(xù)狀態(tài): // 連續(xù)猜中時(shí),sequence > 0(連續(xù)猜中的次數(shù)); // 連續(xù)猜錯(cuò)時(shí),sequence < 0(連續(xù)猜錯(cuò)的次數(shù));
// 即未連續(xù)猜中,也未連續(xù)猜錯(cuò)時(shí),sequence = 0。 public: Counter( ); // 構(gòu)造函數(shù)。將積分屬性score和連續(xù)標(biāo)志屬性 // sequence初始設(shè)置為0。 ~Counter( ); // 析構(gòu)函數(shù)。 void Accumulate(bool result); // 根據(jù)玩家當(dāng)前猜點(diǎn)操作的結(jié)果(布爾類(lèi)型值,通過(guò)實(shí)參 // 傳遞該操作)修改玩家當(dāng)前的連續(xù)猜中狀態(tài) // sequence,并根據(jù)猜點(diǎn)操作的結(jié)果和連續(xù)猜中狀態(tài), // 按積分規(guī)則玩家累計(jì)積分。 void Show( ) const; // 顯示游戲積分值。 void ClearSequence( ); // 在游戲新的一盤(pán)開(kāi)始前,設(shè)置Sequece為0。 };
③ Menu類(lèi)
class Menu { public: Menu( ); // 構(gòu)造函數(shù)。 ~Menu( ); // 析構(gòu)函數(shù)。顯示退出信息。 void PrintMainMenu( ) const // PrintMainMenu( )函數(shù),顯示主菜單。 void ShowChose( ) const // ShowChose( )函數(shù),顯示選擇信息。 void ShowError( ) const // ShowError( )函數(shù),顯示錯(cuò)誤信息。 void ShowGameOver( ) const // ShowGameOver( )函數(shù),顯示一局結(jié)束信息。 void ShowSetOver( ) const // ShowSetOver( )函數(shù),顯示一盤(pán)結(jié)束信息。 };
④ HiLow類(lèi)
class HiLow { private: Card container[52]; // 存放HiLow游戲所要使用的52張撲克牌(大小王牌 //除外)。 int usedIndex; // 指示container中游戲已經(jīng)使用過(guò)的撲克牌的索引。 // 每盤(pán)游戲開(kāi)始時(shí),該屬性應(yīng)被初始化為0(container // 的第一個(gè)元素的下標(biāo)值);以后每次從container獲 // 取一張牌(為玩家發(fā)牌,取一張被猜的牌)后,屬性值 // 加1。該屬性的值域?yàn)?≤usedIndex≥51。 int playIndex; // 指示當(dāng)前玩家手中正在進(jìn)行猜點(diǎn)操作的牌在container //中的索引。每局游戲開(kāi)始時(shí),該屬性值 =usedIndex; // 以后每次猜點(diǎn)操作完成后,屬性值加1。 // 該屬性的值域?yàn)?≤playIndex≥51。 Counter counter; // 該屬性是一個(gè)Counter對(duì)象,用于為游戲提供積分管理。 void Swap(int src, int des); // 用于container中兩個(gè)指定元素的位置交換操作,這 // 是洗牌需要頻繁使用的操作。 public: HiLow( ); // 完成HiLow游戲?qū)ο蟮膭?chuàng)建。在此創(chuàng)建操作中要完成 // 各個(gè)屬性必要的初始化,其中對(duì)container中每個(gè)元 // 素的初始化是委托card的Init操作完成的。 ~HiLow( ); // 析構(gòu)函數(shù)。
void Shuffle( ); // 用于container中的元素(撲克牌)進(jìn)行隨機(jī)排列。 void Deal( ); // 用于每次為玩家發(fā)5張撲克牌。 void PlaycardShow( ) const; // 用于顯示當(dāng)前玩家手中所有可以用猜牌操作的撲克牌 // 的牌面信息。 bool Compare( ); // 用于一次比較玩家明牌和莊家暗牌大小的操作,并返回 // 比較結(jié)果(布爾)標(biāo)志(玩家牌大為ture,否則為false)。 void ResultShow (bool result) const; // 用于在比較操作 Compare 被調(diào)用后,顯示用于比較 // 大小的玩家牌和莊家牌的牌面信息,并根據(jù)比較結(jié)果 // (作為實(shí)參傳遞給操作)顯示相應(yīng)的提示信息。 void Accumulate (bool result); // 用于在比較操作 Compare 被調(diào)用后,顯示用于比較 // 大小的玩家牌和莊家牌的牌面信息,并根據(jù)比較結(jié)果 // (作為實(shí)參傳遞給操作)顯示相應(yīng)的提示信息。 bool IsGameOver( ); // 用于提供游戲的局結(jié)束(布爾)標(biāo)志(結(jié)束為ture, // 未結(jié)束為false)。 bool IsSetOver( ); // 用于提供游戲的盤(pán)結(jié)束(布爾)標(biāo)志(結(jié)束為 ture, // 未結(jié)束為false)。 void ScoreShow( ) const; // 用于顯示玩家的當(dāng)前游戲積分。此操作是委托積分計(jì)算 // 器屬性counter提供的。 };
(4)主要功能函數(shù)的算法描述
① Card類(lèi)Init( )函數(shù)
void Init(int inIndex) { index ← inIndex switch(inIndex / 13) { case 1: face[0] ← ' C' , break; case 2: face[0] ← ' D' , break; case 3: face[0] ← ' H' , break; case 4: face[0] ← ' S' , break; } face[1]←' -' switch(inIndex % 13) { case 1: face[2] ← ' A' , break case 2: face[2] ← '2' , break case 3: face[2] ← '3' , break; case 4: face[2] ← '4' , break; case 5: face[2] ← '5' , break; case 6: face[2] ← '6' , break; case 7: face[2] ← '7' , break; case 8: face[2] ← '8' , break; case 9: face[2] ← '9' , break; case 10: face[2] ← '10' , break; case 11: face[2] ← ' J' , break; case 12: face[2] ← ' Q' , break; case 13: face[2] ← ' K' , break; } }
② Counter類(lèi)Accumulate( )函數(shù)
void Accumulate(bool result) { if (result == true) { if (sequence < 0) sequence = 0; ++sequence; if (sequence < 3) ++score; else if (sequence >= 3 && sequence < 5) score += 2; else if (sequence == 5) score += 4; } else { if (sequence > 0) sequence = 0; --sequence; if (sequence > -3) score = score > 0 ? --score : 0; else if (sequence <= -3 && sequence > -5) score = score > 2 ? score -= 2 : 0; else if (sequence == -5) score = score > 4 ? score -= 4 : 0; } }
③ HiLow類(lèi)Shuffle( )函數(shù)
void Shuffle( ) { srand((unsigned)time(NULL)); indexSrc = rand( ) % 52; indexDes = rand( ) % 52; Swap(indexSrc, indexDes); usedIndex = 0; playIndex = 0; counter.ClearSequence( ); }
(5)main( )函數(shù)的流程圖
① main( )函數(shù)的流程圖

② 循環(huán)中的流程圖

③ 執(zhí)行游戲的流程圖

1.6 面向?qū)ο鬁y(cè)試
在軟件開(kāi)發(fā)活動(dòng)中,為保證軟件的可靠性,人們研究并使用多種方法進(jìn)行分析、設(shè)計(jì)及編碼實(shí)現(xiàn)。由于軟件本身是無(wú)形態(tài)、復(fù)雜的、知識(shí)高度密集的產(chǎn)品,不可避免地產(chǎn)生錯(cuò)誤,因此軟件開(kāi)發(fā)總伴隨著軟件質(zhì)量保證的活動(dòng),而軟件測(cè)試是主要活動(dòng)之一。軟件測(cè)試代表了需求分析、設(shè)計(jì)和編碼的最終復(fù)審。
1.6.1 白盒測(cè)試技術(shù)
把程序看成裝在一個(gè)透明的白盒子里,也就是測(cè)試人員完全了解程序的結(jié)構(gòu)和處理過(guò)程,對(duì)程序執(zhí)行的邏輯路徑進(jìn)行測(cè)試。通過(guò)在不同的關(guān)鍵點(diǎn)檢查程序的狀態(tài),確定實(shí)際狀態(tài)是否和預(yù)期狀態(tài)一致。因此,白盒測(cè)試又稱(chēng)為結(jié)構(gòu)測(cè)試、邏輯測(cè)試。
白盒測(cè)試作為結(jié)構(gòu)測(cè)試方法,是按照程序內(nèi)部的結(jié)構(gòu)測(cè)試程序,檢查程序中的每條通路是否能夠按照預(yù)定要求工作,因此其最主要的技術(shù)是邏輯覆蓋技術(shù)。邏輯覆蓋包括:語(yǔ)句覆蓋、判定覆蓋、條件覆蓋、判定/條件覆蓋、條件組合覆蓋和路徑覆蓋等。
① 語(yǔ)句覆蓋就是設(shè)計(jì)若干個(gè)測(cè)試用例,運(yùn)行所測(cè)程序,使得每一個(gè)可執(zhí)行的語(yǔ)句至少執(zhí)行一次。
② 判定覆蓋又稱(chēng)分支覆蓋就是設(shè)計(jì)若干個(gè)測(cè)試用例,不僅使每個(gè)語(yǔ)句至少執(zhí)行一次,而且程序中的每個(gè)取真分支和取假都至少執(zhí)行一次。
③ 條件覆蓋就是設(shè)計(jì)若干個(gè)測(cè)試用例,使判定表達(dá)式的每個(gè)條件的所有可能的取值都至少執(zhí)行一次。
④ 判定/條件覆蓋要求選取足夠多的測(cè)試數(shù)據(jù)使每個(gè)判定表達(dá)式都取得各種可能的結(jié)果,從而測(cè)試比較復(fù)雜的路徑。
⑤ 條件組合覆蓋構(gòu)造一組測(cè)試實(shí)例,保證使判斷語(yǔ)句中的各邏輯條件取值的可能組合至少執(zhí)行一次。
⑥ 路徑覆蓋是設(shè)計(jì)足夠的測(cè)試用例,使得程序中所有可能路徑都至少被執(zhí)行一次。
1.6.2 黑盒測(cè)試技術(shù)
把程序看成一個(gè)黑盒子,完全不考慮程序的內(nèi)部結(jié)構(gòu)和處理過(guò)程。黑盒測(cè)試是在程序接口進(jìn)行的測(cè)試,它只檢查程序功能是否能按照規(guī)格說(shuō)明書(shū)的規(guī)定正常使用,程序是否能適當(dāng)?shù)亟邮蛰斎霐?shù)據(jù)產(chǎn)生正確的輸出信息,并且保持外部信息的完整性。黑盒測(cè)試又叫功能測(cè)試或輸入/輸出驅(qū)動(dòng)測(cè)試。
通過(guò)黑盒測(cè)試主要發(fā)現(xiàn)以下錯(cuò)誤:
● 是否有不正確或遺漏的功能。
● 在接口上,能否正確地接受輸入數(shù)據(jù),能否產(chǎn)生正確的輸出信息。
● 訪問(wèn)外部信息是否正確。
● 性能上是否能滿(mǎn)足要求。
常見(jiàn)的黑盒測(cè)試方法有等價(jià)類(lèi)劃分、邊界值分析、錯(cuò)誤猜測(cè)、基于故障的測(cè)試、因果圖法等。
(1)等價(jià)類(lèi)劃分法
等價(jià)類(lèi)劃分是一種典型的黑盒測(cè)試方法,使用這一方法時(shí),完全不考慮程序的內(nèi)部結(jié)構(gòu),只依據(jù)程序的規(guī)格說(shuō)明來(lái)設(shè)計(jì)測(cè)試用例。使用這一方法設(shè)計(jì)測(cè)試用例要經(jīng)歷劃分等價(jià)類(lèi)(列出等價(jià)類(lèi)表)和選取測(cè)試用例兩步。
所謂等價(jià)分類(lèi),就是把輸入數(shù)據(jù)的可能值劃分為若干等價(jià)類(lèi)(等價(jià)類(lèi)是指某個(gè)輸入域的子集合)。在該集合中,各個(gè)輸入數(shù)據(jù)對(duì)于揭露程序中的錯(cuò)誤都是等價(jià)的)。因此,可以把全部輸入數(shù)據(jù)合理地劃分為若干等價(jià)類(lèi),在每一個(gè)等價(jià)類(lèi)中取一個(gè)數(shù)據(jù)作為測(cè)試的輸入條件,這樣就可以少量的代表性測(cè)試數(shù)據(jù),來(lái)取得較好的測(cè)試結(jié)果。
(2)邊界值分析法
長(zhǎng)期經(jīng)驗(yàn)表明:大量的錯(cuò)誤是發(fā)生在輸入或輸出范圍的邊界上,而不是在輸入范圍的內(nèi)部。邊界是指相當(dāng)于輸入等價(jià)類(lèi)和輸出等價(jià)類(lèi)而言,稍高于其邊界值及稍低于其邊界值的一些特定情況。使用邊界值分析方法設(shè)計(jì)測(cè)試用例,應(yīng)對(duì)確定的邊界,選取正好等于,剛剛大于,或剛剛小于邊界的值作為測(cè)試數(shù)據(jù),而不是選取等價(jià)類(lèi)中的典型值或任意值作為測(cè)試數(shù)據(jù)。
(3)錯(cuò)誤猜測(cè)
猜測(cè)被測(cè)程序中哪些地方容易出錯(cuò),并據(jù)此設(shè)計(jì)測(cè)試實(shí)例。錯(cuò)誤猜測(cè)法依賴(lài)于測(cè)試人員的直覺(jué)和經(jīng)驗(yàn)。錯(cuò)誤猜測(cè)的基本思想是某處發(fā)現(xiàn)了缺陷,則可能會(huì)隱藏更多的缺陷,在實(shí)際操作中,列出程序中所有可能的錯(cuò)誤和容易發(fā)生的特殊情況,然后依據(jù)經(jīng)驗(yàn)做出選擇。
(4)基于故障的測(cè)試
基于故障的測(cè)試是證明某個(gè)規(guī)定的故障不存在于代碼中。
(5)因果圖法
如果在測(cè)試時(shí)必須考慮輸入條件的各種組合,可使用一種適合于描述對(duì)于多種條件的組合,相應(yīng)產(chǎn)生多個(gè)動(dòng)作的形式來(lái)設(shè)計(jì)測(cè)試用例,這就需要利用因果圖。因果圖方法最終生成的就是判定表。它適合于檢查程序輸入條件的各種組合情況。
1.6.3 測(cè)試用例的編寫(xiě)
測(cè)試用例要根據(jù)測(cè)試大綱來(lái)寫(xiě),而測(cè)試大綱要根據(jù)測(cè)試計(jì)劃來(lái)編寫(xiě)。測(cè)試計(jì)劃起到框架作用,測(cè)試的計(jì)劃應(yīng)該作為測(cè)試的起始步驟和重要環(huán)節(jié)。一個(gè)測(cè)試計(jì)劃應(yīng)包括:產(chǎn)品基本情況調(diào)研、測(cè)試需求說(shuō)明、測(cè)試策略和記錄、測(cè)試資源配置、計(jì)劃表、問(wèn)題跟蹤報(bào)告、測(cè)試計(jì)劃的評(píng)審、結(jié)果,等等。
測(cè)試大綱更多的是把握住測(cè)試項(xiàng)的方向,測(cè)試大綱應(yīng)包括測(cè)試目的、測(cè)試環(huán)境(軟件環(huán)境,硬件環(huán)境)、測(cè)試方法及測(cè)試項(xiàng)目。下面是一個(gè)軟件測(cè)試大綱的模板。
X X系統(tǒng)軟件V1.0
軟件測(cè)試大綱
1.測(cè)試目的:通過(guò)測(cè)試驗(yàn)證該系統(tǒng)已經(jīng)達(dá)到設(shè)計(jì)指標(biāo)。
2.測(cè)試環(huán)境(對(duì)于C/S、 B/S結(jié)構(gòu)的軟件請(qǐng)分別說(shuō)明客戶(hù)端和服務(wù)器端的軟、硬件環(huán)境)
● 硬件環(huán)境
● 軟件環(huán)境
3.測(cè)試方法:使用以用戶(hù)文檔為基礎(chǔ)構(gòu)造的測(cè)試用例來(lái)測(cè)試程序和數(shù)據(jù)。
4.測(cè)試項(xiàng)目:
a)系統(tǒng)安裝與卸載(對(duì)于說(shuō)明書(shū)中注明由開(kāi)發(fā)方提供系統(tǒng)安裝和配置服務(wù)的軟件,該部分可免測(cè),請(qǐng)?jiān)跍y(cè)試方法中注明)

b)軟件功能測(cè)試(根據(jù)軟件說(shuō)明書(shū)中提及的功能模塊填寫(xiě)本部分,下表中內(nèi)容僅為示范,行數(shù)可自由增刪,如需提供測(cè)試用例,請(qǐng)附在文檔后或另附文件)

c)安全可靠性(對(duì)于無(wú)安全保密性要求的軟件,本項(xiàng)可免測(cè),請(qǐng)?jiān)跈谀恐凶⒚鳎?/p>

d)用戶(hù)界面

e)用戶(hù)文檔

測(cè)試用例是指導(dǎo)怎么去執(zhí)行測(cè)試。測(cè)試用例的編寫(xiě)要注意以下幾個(gè)問(wèn)題:
● 測(cè)試用例要根據(jù)測(cè)試大綱來(lái)編寫(xiě)。
● 測(cè)試用例也要分測(cè)試項(xiàng)進(jìn)行歸類(lèi),如業(yè)務(wù)流程測(cè)試、安裝測(cè)試、功能測(cè)試、用戶(hù)友好性測(cè)試、兼容性測(cè)試、性能測(cè)試、安全性測(cè)試,等等。
● 編寫(xiě)測(cè)試用例要考慮各種情況,精力主要集中在軟件的主要業(yè)務(wù)流程和風(fēng)險(xiǎn)高的地方。最好能分出測(cè)試優(yōu)先級(jí)別。
下面是一個(gè)軟件測(cè)試用例的模板。

- Mastering Mesos
- 計(jì)算機(jī)應(yīng)用復(fù)習(xí)與練習(xí)
- 數(shù)據(jù)運(yùn)營(yíng)之路:掘金數(shù)據(jù)化時(shí)代
- Mastering Elastic Stack
- Photoshop CS3特效處理融會(huì)貫通
- 基于ARM 32位高速嵌入式微控制器
- 電氣控制與PLC技術(shù)應(yīng)用
- 從零開(kāi)始學(xué)PHP
- 工業(yè)自動(dòng)化技術(shù)實(shí)訓(xùn)指導(dǎo)
- Hands-On Dashboard Development with QlikView
- 網(wǎng)絡(luò)服務(wù)器搭建與管理
- Linux系統(tǒng)管理員工具集
- Redash v5 Quick Start Guide
- 大型機(jī)系統(tǒng)應(yīng)用基礎(chǔ)
- 51單片機(jī)應(yīng)用程序開(kāi)發(fā)與實(shí)踐