物件導向的思維方式

azz發表於2007-08-23
物件導向的思維方式[@more@]  我是從學習Java程式設計開始接觸OOP(物件導向程式設計),剛開始使用Java編寫程式的時候感覺很彆扭,因為我早以習慣用C來編寫程式,很欣賞C的簡潔性和高效性,喜歡C簡練而表達能力豐富的風格,特別忍受不了Java執行起來慢吞吞的速度,相對冗長的程式碼,而且一個很簡單的事情,要寫好多類,一個類呼叫一個類,心裡的牴觸情緒很強。

   我對Java的物件導向的特性琢磨良久,自認為有所領悟,也開始有意識的運用OOP風格來寫程式,然而還是經常會覺得不知道應該怎樣提煉類,面對一個具體的問題的時候,會覺得腦子裡千頭萬緒的,不知道怎麼下手,一不小心,又會回到原來的思路上去。

   舉個例子,要發廣告郵件,廣告郵件列表存在資料庫裡面。倘若用C來寫的話,一般會這樣思考,先把郵件內容讀入,然後連線資料庫,迴圈取郵件地址,呼叫本機的qmail的sendmail命令傳送。

   然後考慮用Java來實現,既然是OOP,就不能什麼程式碼都塞到main過程裡面,於是就設計了三個類:


  一個類是負責讀取資料庫,取郵件地址,呼叫qmail的sendmail命令傳送;
  一個類是讀郵件內容,MIME編碼成HTML格式的,再加上郵件頭;
  一個主類負責從命令讀引數,處理命令列引數,呼叫發email的類。

   把一件工作按照功能劃分為3個模組分別處理,每個類完成一件模組任務。

   仔細的分析一下,就會發現這樣的設計完全是從程式設計師實現程式功能的角度來設計的,或者說,設計類的時候,是自低向上的,從機器的角度到現實世界的角度來分析問題的。因此在設計的時候,就已經把程式程式設計實現的細節都考慮進去了,企圖從底層實現程式這樣的出發點來達到滿足現實世界的軟體需求的目標。

   這樣的分析方法其實是不適用於Java這樣物件導向的程式語言,因為,如果改用C語言,封裝兩個C函式,都會比Java實現起來輕鬆的多,邏輯上也清楚的多。

   我覺得物件導向的精髓在於考慮問題的思路是從現實世界的人類思維習慣出發的,只要領會了這一點,就領會了物件導向的思維方法。

   舉一個非常簡單的例子:假使現在需要寫一個網頁計數器,客戶訪問一次頁面,網頁計數器加1,計數器是這樣來訪問的

   如:

   後臺有一個資料庫表,儲存每個id(一個id對應一個被統計訪問次數的頁面)的計數器當前值,請求頁面一次,對應id的計數器的欄位加1(這裡我們忽略併發更新資料庫表,出現的表鎖定的問題)。

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

   現在假設一個沒有程式設計經驗的人,他會怎樣來思考這個問題的呢?他會提出什麼樣的需求呢?他很可能會這樣想:我需要有一個計數器,這個計數器應該有這樣的功能,重新整理一次頁面,訪問量就會加1,另外最好還有一個計數器清0的功能,當然計數器如果有一個可以設為任意值的功能的話,我就可以作弊了。

   做為一個沒有程式設計經驗的人來說,他完全不會想到對資料庫應該如何操作,對於HTTP變數該如何傳遞,他考慮問題的角度就是我有什麼需求,我的業務邏輯是什麼,軟體應該有什麼功能。

   按照這樣的思路(請注意,他的思路其實就是我們平時在生活中習慣的思維方式),我們知道需要有一個計數器類 Counter,有一個必須的和兩個可選的方法:

  getCount() // 取計數器值方法
  resetCounter() // 計數器清0方法
  setCount() // 設計數器為相應的值方法

  把Counter類完整的定義如下:

  public class Counter {
   public int getCount(int id) {}
   public void resetCounter(int id) {}
   public void setCount(int id, int currentCount) {}
  }

   解決問題的框架已經有了,來看一下如何使用Counter。 在count.cgi裡面呼叫Counter來計數,程式片斷如下:

   // 這裡從HTTP環境裡面取id值
   ...
   Counter myCounter = new Counter(); // 獲得計數器
   int currentCount = myCounter.getCount(id); // 從計數器中取計數
   // 這裡向客戶瀏覽器輸出
   ...

   程式的框架全都寫好了,剩下的就是實現Counter類方法裡面具體的程式碼了,此時才去考慮具體的程式語言實現的細節,比如,在getCount()方法裡面訪問資料庫,更新計數值。

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

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

   學習JDBC程式設計的經典錯誤問法是:“我怎樣封裝對資料庫的select操作?”

   物件導向的設計是基於解決業務問題的設計,而不是基於具體程式設計技術的設計。我不會去封裝select語句的,我只封裝解決問題的業務邏輯,對資料庫的讀取是在業務邏輯的編碼實現階段才去考慮的問題。

   回過頭看上面那個發廣告郵件的例子,應該如何應用物件導向的思維方法呢?

   對於一個郵件來說,有郵件頭,郵件體,和郵件地址這三個屬性,傳送郵件,需要一個傳送的方法,另外還需要一個能把所有郵件地址列出來的方法。所以應該如下設計:

  類JunkMail

  屬性:
   head
   body
   address
  方法:
   sendMail() // 傳送郵件
   listAllMail() // 列郵件地址

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10901326/viewspace-965470/,如需轉載,請註明出處,否則將追究法律責任。

相關文章