第6章

小A:“師兄,用任意一種麵向對象語言實現,就是要用麵向對象的編程方法去實現,對嗎?”

大B:“一般編程初學者都會遇到這樣的問題,碰到問題就直覺地用計算機能夠理解的邏輯來描述和表達待解決的問題及具體的求解過程。其實這是用計算機的方式去考慮它,就好比計算器這個程序,先輸入兩個數和運算符號,再根據運算符號判斷選擇如何運算,得出結果。這樣是對的。但這樣的想法卻使得程序隻為滿足實現當前的需求,而程序就不容易維護,不容易擴展,也更不容易複用。也就達不到高質量代碼的要求了。”

小A:“師兄,你這樣一講我又不懂了,那怎麽程序才能容易維護,容易擴展,也容易複用哩?”

大B:“我再跟你講細點吧!順便也舉些例子,理解一點。發廣告郵件,廣告郵件列表存在數據庫裏麵。倘若用C來寫的話,一般會這樣思考,先把郵件內容讀入,然後連接數據庫,循環取郵件地址,調用本機的qmail的sendmail命令發送。然後考慮用Java來實現,既然是OOP,就不能什麽代碼都塞到main過程裏麵,於是就設計了三個類:一個類是負責讀取數據庫,取郵件地址,調用qmail的sendmail命令發送;一個類是讀郵件內容,MIME編碼成HTML格式的,再加上郵件頭;一個主類負責從命令讀參數,處理命令行參數,調用發email的類。把一件工作按照功能劃分為3個模塊分別處理,每個類完成一件模塊任務。仔細的分析一下,你就會發現這樣的設計完全是從程序員實現程序功能的角度來設計的,或者說,設計類的時候,是自底向上的,從機器的角度到現實世界的角度來分析問題的。因此在設計的時候,就已經把程序編程實現的細節都考慮進去了,企圖從底層實現程序這樣的出發點來達到滿足現實世界的軟件需求的目標。這樣的分析方法其實是不適用於Java這樣麵向對象的編程語言。”

小A:“為什麽?”

大B:“因為,如果改用C語言,封裝兩個C函數,都會比Java實現起來輕鬆得多,邏輯上也清楚得多。”

小A:“我倒覺得麵向對象的精髓在於考慮問題的思路是從現實世界的人類思維習慣出發的,隻要領會了這一點,就領會了麵向對象的思維方法。”

大B:“這樣吧,我再舉一個非常簡單的例子:假使現在需要寫一個網頁計數器,客戶訪問一次頁麵,網頁計數器加1,計數器是這樣來訪問的如:http://hostname/count.cgi?id=xxx後台有一個數據庫表,保存每個id(一個id對應一個被統計訪問次數的頁麵)的計數器當前值,請求頁麵一次,對應id的計數器的字段加1(這裏我們忽略並發更新數據庫表,出現的表鎖定的問題)。”

大B:如果按照一般從程序實現的角度來分析,我們會這樣考慮:首先是從HTTPGET請求取到id,然後按照id查數據庫表,獲得某id對應的訪問計數值,然後加1,更新數據庫,最後向頁麵顯示訪問計數。

小A:“現在假設一個沒有程序設計經驗的人,要怎樣來思考這個問題的呢?會提出什麽樣的需求呢?”

大B:“你很可能會這樣想:我需要有一個計數器,這個計數器應該有這樣的功能,刷新一次頁麵,訪問量就會加1,另外最好還有一個計數器清0的功能,當然計數器如果有一個可以設為任意值的功能的話,我就可以作弊了。做為一個沒有程序設計經驗的人來說,他完全不會想到對數據庫應該如何操作,對於HTTP變量該如何傳遞,他考慮問題的角度就是我有什麽需求,我的業務邏輯是什麽,軟件應該有什麽功能。”

按照這樣的思路需要有一個計數器類Counter,有一個必須的和兩個可選的方法:

getCount()//取計數器值方法

resetCounter()//計數器清0方法

setCount()//設計數器為相應的值方法

把Counter類完整的定義如下:

publicclassCounter{

publicintgetCount(intid){}

publicvoidresetCounter(intid){}

publicvoidsetCount(intid,intcurrentCount){}

}

解決問題的框架已經有了,來看一下如何使用Counter。在count.cgi裏麵調用Counter來計數,程序片斷如下:

//這裏從HTTP環境裏麵取id值

……

CountermyCounter=newCounter();//獲得計數器

intcurrentCount=myCounter.getCount(id);//從計數器中取計數

//這裏向客戶瀏覽器輸出

……

程序的框架全都寫好了,剩下的就是實現Counter類方法裏麵具體的代碼了,此時才去考慮具體的程序語言實現的細節。

麵向對象的思維方法其實就是我們在現實生活中習慣的思維方式,是從人類考慮問題的角度出發,把人類解決問題的思維方式逐步翻譯成程序能夠理解的思維方式的過程,在這個翻譯的過程中,軟件也就逐步被設計好了。

大B:“在運用麵向對象的思維方法進行軟件設計的過程中,最容易犯的錯誤就是開始分析的時候,就想到了程序代碼實現的細節,因此封裝的類完全是基於程序實現邏輯,而不是基於解決問題的業務邏輯。”