你好,C++(38)從問題描述中發現對象的屬性和行為 6.4 工資程序成長記:類與對象(上)


6.4  工資程序成長記:類與對象

“夜半三更喲,盼天明;寒冬臘月喲,盼春風。若要盼得喲,漲工資,嶺上……”自從上次老板許諾給小陳漲工資以后,一轉眼又過去幾個月了,可是漲工資的事一點動靜都沒有。小陳只好天天哼着這首歌,自己安慰自己,天總會亮的,春天總會來的,而工資也總會漲的。這天,小陳正在哼這首歌,沒想到老板又讓他去辦公室。小陳心中那個高興啊,心想,盼星星盼月亮,總算盼到了這一天啊。

於是,小陳趕緊來到老板的辦公室。可是,當他一進辦公室,看到老板那陰雲密布的臉就知道情況不妙。果然,老板一見小陳就抱怨起來:

“小陳啊,你這個工資程序怎么搞得嘛?你是知道的,我們公司的工資是按照員工的入職年數來計算的,並且高級員工和一般員工的計算方法不同。可是過了一年了,每個人的工資還是第一次輸入的數據,沒有變化嘛!還有還有,你這個程序只能找到最高工資的人的序號,只知道序號有什么用啊,我要知道名字,名字,這樣我才好直接把他給開了啊……”

一聽老板這一通抱怨,小陳心涼了半截,心想這次漲工資肯定又沒戲了。於是有氣無力地說:

“老板,你別着急,程序就是這樣不斷改進不斷完善的。讓我回去按照你的要求修改修改,保證讓你滿意。”

就這樣,在老板那里挨了一頓訓之后,小陳又帶着老板的新要求回來了。小陳簡單地分析了一下老板的新要求:要讓每個員工的工資動態計算,而員工又分為高級員工和一般員工兩種,每種員工的工資計算方法各不相同。在統計的時候,不僅需要給出最高工資者的序號,還要給出姓名的信息。這些新的要求看起來還挺復雜的,小陳正撓頭細想解決之道,突然靈光一閃:這個問題,正好可以用C++中的面向對象思想來解決啊——利用封裝機制,可以把員工的序號、入職年份、姓名、工資等信息封裝成員工類,這樣在統計得到最高工資的員工序號的同時也就得到了對應的姓名;利用繼承機制,可以從員工類派生出高級員工類和一般員工類,再配合多態機制,就可以實現對兩類員工的工資采取不同的計算方式了。想到這里,小陳不由得一拍小腿,心中感嘆,面向對象思想在解決復雜問題時果然威力無比啊!巧的是,小陳這段時間剛好學過了C++中用類來體現面向對象思想,於是他決定用類來對這個工資程序進行改寫。

6.4.1 需求分析:老板要的是這樣一個工資程序

所謂需求分析,就是搞清楚客戶到底要的是一個什么樣的軟件。無論這個軟件是用於飛天登月的大型系統,還是僅供孩子們玩的游戲程序,需求分析永遠都是我們開發工作的第一步。所以,當小陳接到老板下達的任務后,他做的第一件事不是立即修改程序代碼,而是先進行需求的分析,搞清楚老板到底要的是怎樣一個工資程序。

根據老板的抱怨(在實際的開發實踐中,這往往來自前期的用戶調查),這個工資程序必須能夠輸入員工的工資數據,而輸入數據又包括直接從數據文件讀取和手工輸入;完成數據輸入以后,這個程序還要對工資數據進行處理,包括統計最高的工資,以及根據員工的姓名對工資進行查詢;最后,就是將所有的工資數據輸出到文件,以便於下次直接讀取。

經過這樣的簡單需求分析,小陳對老板想要的工資程序就比較清楚了。為了讓這些需求更加清晰而直觀,小陳將其繪制成了UML用例圖,老板要的工資程序,不過就是實現了這些用例的工資程序。

最佳實踐:全世界程序員都在說UML

UML(統一建模語言,Unified Modeling Language),一種描述軟件的常用方式,它通過為軟件建立模型,並通過一系列圖(用例圖、類圖、活動圖等)來直觀地描述軟件的結構和行為,從而讓程序員對軟件有一個清晰的認識和理解。因此,在具體實現一個軟件之前,我們都使用它來描述我們即將開發的軟件,以期在項目團隊中達成對軟件的共識。也正因為如此,整個項目團隊中的成員,甚至是全世界的程序員,都必須掌握這門建模語言。

 

圖6-13 工資程序的用例圖

 

6.4.2  從問題描述中發現對象

完成程序的需求分析后,小陳明白了自己要做的是怎樣的一個軟件,接下來的問題就是怎么做了。按照面向對象思想解決問題的一般順序,首先就是從問題描述中發現對象。而小陳知道,問題描述中的那些名詞實際上就是對象。

按照“尋找對象就是尋找名詞”的思路,小陳開始尋找這個問題描述中的名詞。首先,遇到的第一個名詞是工資系統(SalarySys)。然后就是該系統所管理的員工(Employee),因為級別的不同,員工又分為高級員工(Officer)和普通員工(Staff),這些就是整個問題中的名詞,也就構成了整個問題所涉及的對象。

從問題描述中除了可以找到對象之外,還可以發現對象之間的各種關系:工資系統管理員工對象,它們之間是一對多的關系;同時,高級員工和普通員工同屬於員工,這就表示它們應該有着共同的基類,都是從員工類所派生出來的。圖6-14描述了整個問題中的對象及對象之間的關系。

 

 

圖6-14  工資程序中的對象及對象之間的關系

6.4.3  分析對象的屬性和行為

在找到對象之后,就可以進一步分析這些對象所擁有的屬性和行為,然后利用面向對象的封裝機制將其封裝成具體的類。首先,分析這個問題中最基礎的員工類Employee。根據老板的要求,為了找到工資最高的員工,我們必須記錄每個員工的姓名(m_strName);為了根據在職時間(現在時間減去入職時間)動態地計算員工的工資,我們必須記錄員工的入職時間(m_nYear);員工有級別的差別,各個級別的員工工資計算方式不同,應該有一個屬性級別(m_nLevel)來記錄。所以這個對象必需的屬性就是姓名、入職時間和級別。

分析了員工類Employee的屬性,那么它又該擁有什么樣的行為呢?類的行為都是用來完成需求分析中的用例的,所以,Employee類的行為跟它要完成的用例密切相關。為了完成“計算最大值”用例,它應該有一個計算工資的行為(GetSalary()),可以根據員工的在職時間動態地計算員工的工資。但是,Employee類作為具體的員工類Officer和Staff的基類,並不知道工資的具體計算方法,所以這個行為只是一個接口而已,需要留待它的派生類來具體實現,所以在Employee中這個函數應該是一個純虛函數;而要計算工資,它又必須知道員工的在職時間,所以它還必須有一個獲得在職時間的行為(GetWorkTime());同時,為了完成“查詢工資”這個用例,程序需要知道員工的姓名,所以員工類應該提供一個獲得名字的行為(GetName());最后,為了完成“輸出數據到文件”的用例,Employee類還必須提供獲得員工級別(GetLevel())和入職年份(GetYear())的行為,從而可以獲取員工的信息並將其輸出。

經過這樣的分析,小陳得出了員工類Employee應該具備的屬性和行為。為了記錄自己的分析結果,讓結果一目了然,小陳將分析結果畫成了UML類圖:

 

圖6-15 Employee類的屬性和行為

具體的員工類Officer和Staff是Employee的派生類,在Employee類的基礎上,這兩個具體的員工類並沒有額外的需要描述的內容,所以它們不需要新添加屬性,只需要從基類繼承已有的屬性即可。而至於行為,具體的員工類需要負責具體的工資計算和返回不同的員工級別,所以它們需要實現基類中的GetSalary()和GetLevel()這兩個虛函數。經過這樣的分析,Officer和Staff類應該具備的屬性和方法就很清楚了。小陳將它們用如下的UML類圖來表示:

 

圖6-16 Officer和Staff類的屬性和行為。

按照同樣的方法,小陳接着分析用於管理這些員工對象的SalarySys類。為了保存和管理多個Employee對象,SalarySys類必須有一個數組來保存這些對象,而為了應用面向對象的多態機制來動態地計算員工工資,數組中保存的不應該是這些對象本身,而應該是指向這些對象的指針;同時,數組只是表示了SalarySys所能夠保存的最多的對象指針,但是並不是數組中的每個指針都是有效的,具體保存了多少個指針還不清楚,我們還必須用一個屬性來表示當前有效的指針的個數(m_nCount);另外,SalarySys需要從文件讀取數據,最后還需要將數據寫入文件,所以它還需要一個記錄數據文件名的屬性(m_strFileName)。

在SalarySys類的行為上,小陳還是同樣從它要完成的用例來分析。根據他之前對這個程序進行的簡單需求分析,SalarySys首先需要完成“輸入數據”這個用例,而這個用例又包含了“從文件讀取”和“手工輸入”這兩個用例,這就要求SalarySys類應該具有從文件讀取數據(Read())和讓用戶手工輸入(Input())的行為;完成“輸入數據”之后,就是“處理數據”,它也同樣包括了“計算最大值”和“查詢工資”兩個用例,這就要求SalarySys類具有查找所有工資數據中的最大值(GetMax())和根據用戶輸入的姓名查詢相應工資信息(Find())的行為;最后,就是“輸出數據”這個用例,它要求SalarySys具有將所有工資數據保存到數據文件(Write())的行為。

分析完成之后,小陳同樣將分析結果繪制成了UML類圖:

 

圖6-17 SalarySys類的屬性和行為

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



猜您在找 你好,C++(23) 4.4.2 工資程序成長記:用數組處理批量數據,用循環結構執行重復動作 你好,C++(30)“大事化小,小事化了”5.4.3 工資程序成長記:函數 你好,C++(31)我終於找到對象啦!6.1 從結構化設計到面向對象程序設計 按要求編寫Java應用程序。 (1)創建一個叫做People的類: 屬性:姓名、年齡、性別、身高 行為:說話、計算加法、改名 編寫能為所有屬性賦值的構造方法; (2)創建主類: 創建一個對象:名叫“張三”,性別“男”,年齡18歲,身高1.80; 讓該對象調用成員方法: 說出“你好!” 計算23+45的值 將名字改為“李四” 按要求編寫Java應用程序。 (1)創建一個叫做People的類: 屬性:姓名、年齡、性別、身高 行為:說話、計算加法、改名 編寫能為所有屬性賦值的構造方法; (2)創建主類: 創建一個對象:名叫“張三”,性別“男”,年齡18歲,身高1.80; 讓該對象調用成員方法: 說出“你好!” 計算23+45的值 將名字改為“李四” 10.按要求編寫Java應用程序。 (1)創建一個叫做People的類: 屬性:姓名、年齡、性別、身高 行為:說話、計算加法、改名 編寫能為所有屬性賦值的構造方法; (2)創建主類: 創建一個對象:名叫“張三”,性別“男”,年齡18歲,身高1.80; 讓該對象調用成員方法: 說出“你好!” 計算23+45的值 將名字改為“李四” 按要求編寫Java應用程序。 (1)創建一個叫做People的類: 屬性:姓名、年齡、性別、身高 行為:說話、計算加法、改名 編寫能為所有屬性賦值的構造方法; (2)創建主類: 創建一個對象:名叫“張三”,性別“男”,年齡18歲,身高1.80; 讓該對象調用成員方法: 說出“你好!” 計算23+45的值 將名字改為“李四” 你好,C++(3)2.1 一個C++程序的自白 創建一個叫做People的類: 屬性:姓名、年齡、性別、身高 行為:說話、計算加法、改名 編寫能為所有屬性賦值的構造方法; (2)創建主類: 創建一個對象:名叫“張三”,性別“男”,年齡18歲,身高1.80; 讓該對象調用成員方法: 說出“你好!” 計算23+45的值 將名字改為“李四” 你好,C++(33)對象生死兩茫茫 6.2.3 一個對象的生與死:構造函數和析構函數
 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM