23 April 2006

最近漸漸發現自己常犯一個錯誤:設計錯 domain。呃... 我不大會描述,直接拿實例來講好了。比方說出租車業好了,出租的車有普通的四人座轎車,也有七人座休旅車、再上去甚至還有大型遊覽車...等。根據實際生活的經驗,這些都是車。然後,我們可以依車種或承載人數來 model 各種不同的 class,下面是繼承關係: Car -> SUV -> Bus,然後不同的 class 有自己的計價公式 -rentCost()。

看起來很合理,物件的分類也很直覺... 但是等到車種一多時,就開始越來越吃力,繼承關係也不再像一開始看起來這麼簡單,緊接著企畫案突然出現這樣的需求:七人座以下 SUV 比照一般轎車算錢,九人座以上的則等同視為遊覽車... 哇!原本的繼承關係破功了,這下可難改啦,只好在 rentCost() 裡寫一些特別的 "if",硬生生的解決這個問題....

到底是啥出了問題?是需求變化的太快嗎?還是該怪罪 Java 單一繼承太蠢?就我最近體會到的,是設計錯 domain。我們回過頭來想,出租車業裡的真正的 domain 是啥?其實應該是 "租賃"。如果以租賃為出發點來重新思考這個問題,可能會出現像 RentCar (出租的車),LongTermRentCar (長期出租的車),HighCostRentCar (租費昂貴的車).... 之類的 class (我不是出租車業的 domain 專家,這些是我亂舉的例子)。如果再繼續推敲下去,就會出現 Rentable,LongTerm,Expensive... 這些 "interface"。有沒有發現新的字眼中已經沒有車子了?這表示這個 model 才是真正的反應 "租賃" 這個 domain、可以適切地解決租賃上會遇到的問題。

這個例子可能不是很貼切,不過應該夠說明 model 錯 domain 的意思和現象。我常常很容易地就依一般地生活經驗設計物件,看到車子就開始依車種 model,看到人就開始依姓名和性別 model,看到按鈕就依各式各樣的按鈕 model...。

要避免這個現象自然是要累蹟越多的 domain knowledge,這個大家都知道.. 可是時間不但有限、環境也常常變換啊!目前對這個毛病的解法是:

  • 先忽視顯而易見的 entity
  • 鑽研互動 "行為",及欲達成的 "目的"
  • modeling 時從行為和目的下手。
  • 最後再回來看哪些是必要存的資料,修正 model 及設計 db

當然這些考量都是針對需要 rich domain 的專案... 如果只是純資料處理當然就不用搞這些了。


回響

可以用 Tag <I>、<B>,程式碼請用 <PRE>