假設在一個學校單位的資訊系統,其中有幾個程式片段:
成績判斷
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的特例.
當然,這個模式享受了使用繼承的好處,但也可能因此帶來其他問題,否則也不會有其他模式的存在了,更何況還有『少用繼承,多用合成』這樣的設計原則,這就在下一章介紹了.