談談OCP
看到「好人難為」一文,主角是一位專班學生,看來他似乎很委曲,因此我在意見箱內提議,他可以好好研究一下軟體設計的第一原則:Open-Closed Principle (OCP),或許可以解決他的困擾,這件事涉及到軟體工程的教育與訓練的問題,也就是說,學以致用的問題,因此有必要寫一篇短文以OCP為例,來談談軟體設計原則的運用,這些原則並非軟體發展的食譜(cookbook),而是發展者必須放在心裡的「指引」(guideline),這種指引必須落實成為diciplines,其他如設計樣式(design patterns)也具有指引特性,因此才能廣泛運用,也就是說,可以重覆使用(reuse),學習時最好蒐集一些範例,可能有助於這些設計原則或樣式的運用,有如念法律的人必須研究一些判例一樣,學習軟體發展方法時也不例外。
左邊圖形表示,如果Client想使用另一個Server時,Client必須改變,因為兩者皆是concrete,這樣就不符合OCP原理,再說,你的設計改成如右邊圖形所示,當Client要使用其他Server時只要由AbstractServer提供新的deviation,則Client不必改變,也就是說,Server改變並不影響Client,這就符合OCP的原理。
OCP是物件導向方法的核心,1988年由Bertrand Meyer在他的著作"Object-Oriented Software Construction"一書提出,它是說:「軟體實體必須能夠延伸但不能修改」(Software entities should be open for extension but closed for modification),換言之,必要時可以延伸軟體實體的功能但不必修改它,該軟體實體可以是類別、模組、功能、程式、或組件,完全看你用在何處。Meyer的原意是說,類別實作(或程式)除了須要除錯外,如要改變功能或增加新功能時不得改變父類別(superclass),而由子類別(subclass)來達成,子類別可以利用繼承(inheritance)機制重用父類別的屬性或作業元,但可改變或增減其功能,因此繼承不旦可以重用父類別的實作,同時可以延伸原功能,該子類別的介面可以異於父類別的介面,這是一般具有物件導向的人所熟悉的繼承機制。
到1990年代OCP被重新定義為,新介面可以繼承自「抽象類別」,但非繼承實作部分,原介面不得修改,也就是說,你設計的組件或模組不能改變,當需求改變時,你可以增加新程式以延伸該模組的功能,但不能改變你也許認為十分完美而能作業的原程式,請看下圖(R.C. Martin),
左邊圖形表示,如果Client想使用另一個Server時,Client必須改變,因為兩者皆是concrete,這樣就不符合OCP原理,再說,你的設計改成如右邊圖形所示,當Client要使用其他Server時只要由AbstractServer提供新的deviation,則Client不必改變,也就是說,Server改變並不影響Client,這就符合OCP的原理。
OCP尚具有一種重要的特性,即封裝性(encapsulation),也就是說,使用者不會因某實體的改變而受影響,這種設計觀念你可以在幾乎所有的設計樣式(design patterns)上發現,例如Bridge,Chain of Responsibility,Decorator或Observer等樣式皆符合OCP的定義,譬如Observer樣式,你如加上新的Observer以延伸Subject並不必增加Subject的程式。我們再舉Decorator設計樣式為例,Decortor的「正規」結構讀者可以參閱GoF的Design Patterns一書。我只舉每個人日常生活都會碰到的事件為例,如果你要做蛋糕,你可能以海綿蛋糕為底,如果你要做奶油蛋糕可以在上面塗上奶油,如果你加上水果,則變成水果蛋糕,如果加上巧克力寫「生日快樂」,則搖身一變成為生日蛋糕,你在海綿蛋糕上加上一些「裝飾」並沒有改變海綿蛋糕本身,運用這種觀念,這位專班學生所設計的"tree model",有如海綿蛋糕,他的上司要他增加客戶需求,其實不必改變它引以為傲的tree model。不過,要注意的是,你不能到處使用OCP,如此可能形成時間與人力的浪費,而且可能增加程式複雜度而不易了解,總之,不能所有設計都依照OCP,只要集中在最可能改變設計的部分運用OCP即可,問題在於如何知道何處最可能改變,沒有特別「藥方」,這要靠經驗以及你對於要處理的範疇的知識,不過研究其他範例或有所助益。
(註一)這篇文章本已刪除,不過應劉立頌教授的「鼓動」,才重新裝飾(decorate)張貼,我的原意是,在物件導向軟體設計方法中有極為豐富的原則與樣式提供運用,問題是你必須先了解重要的原則與樣式,並把它們當做指引,引導你如何設計,不知你可同意?
(註二)GoF是指撰寫Design Pattern - Elements of Reusable Object-Oriented Software一書的四位專家,包括:Eric Gamma,Richard Helm,Ralph Johnson,與John Vlissides等。
我覺得這個原則很好?不知道能不能多談一些其他的原則?有時候看工程師寫的程式碼很糟,卻不知道如何說他。如果有一群原則,至少以後我可以說『你這樣的設計沒有符合OCP原則,請重改』。不知道有沒有書有這樣的整理?或是教授們可以簡介一些重要的原則?
回覆刪除謝謝樓上的意見,據個人所知並無專講設計原則的書籍,這些設計原則卻散見於一些軟體工程、物件軟體工程或設計樣式的書籍中,如果對Agile Modeling有興趣,倒有一本專講modeling的書可參考:Scott W. Ambler著"Agile Modeling: Effective Practices for eXtreme Programming and Unified Process, John Wiley & Sons, 2002出版,這本書並不是在講設計原則,但裡面所講的modeling principles與practices或可做為設計時的參考,對此,我曾在本部落格張貼一篇「漫談Agile Modeling」不妨翻出來看看,事實上,我在OCP一文提到,設計原則或設計樣式可當成一種設計指引,所謂指引是用來引導發展者設計時的(正確)方向,善用它,或可提高設計品質。因意見箱空間有限不便多談,如有機會再來談談其他的設計原則或常規(practices)。黃為德
回覆刪除感謝黃教授應讀者要求分享這篇文章!內容真的很棒,又很容易瞭解,並且有許多觀念值得在課堂裡討論。謝謝您送給我一個現成的教材!
回覆刪除就如黃教授所說OCP是一個原則,其實帶有這樣的觀念去設計系統,就能夠帶給系統有多一點的彈性。可是如何拿捏呢?希望大家可以多分享一些心得或者提出一些問題。
上面所提的書,其實我也是蠻喜歡的,其他讀者們可以搜尋一下Scott Ambler 就能夠找到他的網址。裡面的內容很值得看看。
這些書通常都是英文的,讀起來不是很懂。還是希望教授們可以多寫一些。這應該也是這個網站的目的吧. 感謝
回覆刪除謝謝提醒!讀起英文,有時可能有一點辛苦…
回覆刪除其實還有一個網站(雖然不是在廣告)我蠻喜歡的,你可以搜尋一下『點空間』應該可以看到許多好資料,特別是有許多翻成中文的好文章。
至於Ambler的那本書,我喜歡他的modeling精神。這本書有一點是針對eXtreme Programming(XP)人『不喜歡文件』這件事做一些說明。如果是extreme到非常極端,不就是只在寫程式而已?(當然他們與『只寫程式』還有很大的差別就是test-driven)他所提出的論點是:可以沒有文件可是要做modeling。他甚至提到如果準備文件麻煩,數位相機這麼方便,為什麼不把白板或餐巾上所畫的圖照下來,放到文件裡面去呢?
本來agile method的value外,他還有提到一個新的value叫做humility,就是謙卑。他說為了發揮真正的agile develpment,分工合作很重要,其中謙卑學習及彼此尊重可以讓大家一起成長,也可以讓project執行的更順暢。
這本書的序是Ron Jeffries寫的,他是XP代言人之一。他自己承認以往忽略了modeling的重要性,看到Ambler的light-weight modeling精神,值得很欣慰。
如果二樓的匿名先生/小姐對敏捷塑模(agile modeling - AM)有興趣,不妨調出「漫談Agile Modeling」這篇文章參考,我在這篇文章也提到敏捷塑模的五項真義(values),其中前四項來自於Extreme programming,第五項humility是Scott W. Ambler依他的經驗所加上去,就是說,必須謙卑允許別人提供對於你專案工作的意見,這個「別人」,依我的詮釋不只是指人,同時也指由許多專家的經驗所產生的原則與樣式,也就是說,你可以以這些原則或樣式為指引設計你的系統。在文章理,我舉依"use the simplest tools"等常規(practice),設計一則簡單的範例,或可顯示AM的原則與常規的部分功用,當然AM的常規並不只使用最簡單的工具來產生模型一項,其他有機會再來探討。
回覆刪除我個人不很喜歡寫程式,老實說也寫的不好,因此我主張提高發展的抽象層次(level of abstraction)如MDA,要用MDA技術來發展軟體系統,Modeling技術與技巧就十分重要,不過,我奉勸大家,尤其剛進門的學生,不要學我這種懶人做法,還是好好學好一種以上的程式語言。
匿名提到,讀英文書有些吃力,其實重要的不在英文,因科學或工程方面的英文並不難懂,主要是如何了解所講的東西的真義,一般寫書或文章的人,不會在語言上寫的很細,甚至有點抽象,因此只要細心設法了解其真義,語言諒不成問題。
我張貼的文章是「談談OCP」,以上這些「意見」似有點離題,十分抱歉。
我是今年修黃教授 Software Design Method 的專班學生,不過我不是「好人難做」的主角,因好奇的關係,來看看這位專班學生到底發生什麼問題(因為黃教授一直鼓勵我們來看他的文章,我實在按耐不住好奇了...)
回覆刪除1.他的工作是跟物料管理系統的開發相關。公司用的實作框架中包含一個 tree 的 model。
這東西我大概知道他在講啥,剛好我也懂一點 Material Management ,應該就是 BOM 表 (Bill of Material)吧?講 Tree Model 應該講的就是類似 Composite Design Pattern 的結構。
2.有一天,因為使用者的需求變更,他的上司決定把 tree model 改掉以快速的解決顧客的問題。他仔細的看了這個方法,知道一定會對後續的成本計算產生問題,因此請主管不要改 tree model。但是顧客的問題必須要馬上的被解決,所以主管決定還是要改。
通常解物料管理這個問題,最直覺的方法就是這位苦主講的 Tree Model 或所謂的 Composite Design Pattern.
理論上使用者需求變更,應該不需要動到這個解題方法,苦主的客戶到底是遇到了什麼問題,讓苦主的老闆自以為比苦主專業,而提出另一個苦主覺得很爛的方法來,這可能真的要請苦主說清楚。
以我過去的工作經驗,我猜有可能是效能問題。
不過我認為苦主不爽的地方應該是:「沒錯,我的 Tree Model 的確有些問題,但主管提出的 Solution 問題更大。」但這位苦主只能任由外行領導內行。
我可體會苦主的心情,不過我覺得或許苦主可以試著去找出比 Tree Model 更好的 Solution ,然後透過溝通,說服你的主管接受。
苦主問題屬於 ERP 的 Problem Domain ,可以試著看看全球 ERP 的龍頭 SAP 是怎麼處理這個問題的,然後偷學 SAP 的方法,用在苦主的物料管理系統上,中央大學有 SAP 的課,可以找機會去旁聽看看。 SAP 解這個問題不是用苦主的 Tree 的方式,反而是用編碼的方式,不過這說來話長,就不講下去了。
3.有軟體工程概念的他,瞭解這個問題的嚴重性,他深深的知道這個東西一改,以後的程式都會以這個基礎下去開發,到最後成本計算穩死無疑,因此堅決不可以改,兩個人於是吵了起來。
這時候黃教授講的 OCP 就可以派上用場了,苦主原本不覺得這個 Tree Model 會需要改,所以當時設計的時候沒用 OCP ,這很合情合理, Don't over design.
但既然主管認為一定要改,那苦主應該可以趕快 refactor 他的系統,讓其他程式 base on 一個抽象的物料管理方法,而不要直接 base on 他的 Tree Model ,趕快把黃教授圖裡面的那個 AbstractServer 提煉出來,這樣才可以騰出空間來放他主管提議的那個爛方法,如此一來,既可以保留 Tree Model ,也可以容納主管的爛方法。
4.過了三個月,這個問題浮現了,大家忙得雞飛狗跳。但是,沒有人知道他們所遇到的問題是主管所造成的,也沒有人想到他。大家忙著找一個可以立即解決成本計算錯誤的方法。也許,再把 tree model 亂改一通吧。
這時候就證明了主管的爛方法是錯的,那苦主就輕鬆換回苦主自豪的 Tree Model 就好了。
苦主可以充分利用 Strategy Design Pattern ,今天鬥嘴鬥不過主管,那就換主管所提的 Strategy ,過了一陣子,事實證明主管是外行的,換回苦主的 Strategy 就好了,然後找時間再去尋找更好的 ConcreteStrategy 來 implement ,這樣不就皆大歡喜了,既可以證明你的專業,又能夠證明主管的無能。