2012年10月19日

白話 Design Pattern (十二) Template Method Pattern

Template Method Pattern應用了OO最重要的特性之一『繼承』,來達到封裝演算法、程式reuse的目的.對我而言,它算是最容易理解的模式,甚至在沒聽過什麼是Design Pattern前,就已經自然而然的開始使用了.

假設在一個學校單位的資訊系統,其中有幾個程式片段:

成績判斷
if 身分=大學生
  if 成績 >= 60 
    IsPass = true
  else
     IsPass = false
else身分= 研究生
  if 成績 >= 70 
     IsPass = true
 else
     IsPass = true

選課限制
if 身分=大學生
  max學分 = 22
else身分= 研究生
 max學分 = 12

繳費
if 身分=大學生
  學費 = 20000
else身分= 研究生
  學費 = 1000*學分

這種情形應該很常見,看起來也沒什麼不合理.那會有甚麼問題?

一、擴充不易
如果今天學校要招收博士班學生了,那麼相關的片段可能又都要加上身分=博士班學生的判斷,往後招收夜間部、旁聽生...每次都要增加新的判斷式.

二、邏輯分散
同上,也因為程式片段分散多處,增加或修改的時候一定不能有漏,否則可能出現無法預期的狀況...

三、維護不易
假設今天大學生的選課限制要修改,改成大一到大三是22學分,大四則可以25學分,或更複雜的規則.因為各種身分的選課規則都放在一起,一不小心說不定大學生部分改好了,卻動到研究生的規則,而造成其他錯誤.

說到底還是因為以上方法違反了OCP(Open Close Principle),這時候就應該考慮使用適當的Design Pattern來改善.甚至有一種說法,如果系統中同一種判斷(如例子中的『身分』)出現兩次以上,就應該考慮將其重構.(好吧!這是我自己這麼想的)

解決以上的問題,最簡單的做法就是將建立一個學生抽象類別(Abstract Class),然後讓大學生、研究生繼承之,並將以上程式片段改成呼叫學生子物件.


這麼一來,將來要繼續擴充更多種學生,既不需要更動業務規則,也不怕影響原有的其他學生子類別,簡簡單單就符合OCP.

而實際使用中,在這些程式片段之前,會有一個問題-『學生物件如何生成?』這就可以參考前面的簡單工廠或工廠模式.特別提一下,工廠模式本身也是Template Method Pattern的特例.

當然,這個模式享受了使用繼承的好處,但也可能因此帶來其他問題,否則也不會有其他模式的存在了,更何況還有『少用繼承,多用合成』這樣的設計原則,這就在下一章介紹了.