Polymorphism中文一般稱為「多型」,早期也有人翻譯成「同名異式」。我比較喜歡「多型」,「多型」讓人覺得物件能夠以「多種面貌」出現,同名異式則太強調「不同的函式」。其實,「型別的不同」是「因」,而「函式的不同」是「果」。當一個物件具有不同的型別,就有可能會引發多型機制。
一個物件為何會有不同型別?這是因為繼承而來,物件可以扮演所有祖先類別的角色。例如當某物件的類別是Sub,當此物件被「轉型」成超類別Super之後,此物件就具有兩種不同的類別:「實際類別」是Sub,「形式類別」是Super。如果,在這個情況下呼叫此物件的方法m,會執行到Super定義的方法m?還是Sub定義(修改)的方法m?
答案是實際類別的方法,也就是Sub定義的方法m。因此,所謂的多型就是:不管形式類別是什麼,一定會執行到實際類別的方法。
你可能會覺得疑惑,為何當初要將物件轉型為祖先類別,導致「形式類別」(宣告類別)和「實際類別」(定義類別)不一樣?這個問題留待下一回再回答。
如果你的程式大量使用switch/case語法,很有可能是你的設計不良,沒有好好地使用多型。建議你最好「重構」(Refactoring)程式。
類別的方法,可以分成虛擬(Virtual)與非虛擬兩種。只有虛擬方法才能搭配多型機制使用。如果是非虛擬方法,則會執行到形式類別(而非實際類別)的方法,因為多型沒有發揮作用。
應用框架
為了方便軟體的開發,許多軟體廠商都會提供應用框架(Application Framework),現今流行的框架相當多,例如:.NET Framework、Borland VCL、Java Class Library。有了框架,我們終於可以享受到OO的好處,重複利用別人寫好的程式碼,不用一切自己重頭寫。
框架廠商先寫好大部分的程式,編程員只需要「利用繼承來做修改」,就能套用整個框架,為了讓你修改的部分能夠確實被執行到(而不是執行到框架本身的方法),所以這些允許修改的方法都是定義成虛擬的。
因為編程員「利用繼承來做修改」,所以產生次類別和重新定義的方法。框架比這個次類別更早被定義,當然不認識這個次類別,所以框架內都是以此次類別的祖先類別為「形式上」的處理對象(處理介面)。當此次類別物件被傳入框架中,就會被自動轉型成祖先類別,因此產生「形式類別」和「實際類別」的差異。正因為這樣的類別差異,加上次類別有重新定義方法,所以多型機制出現了。
單一繼承架構中,良好的框架設計(例如Java Swing)會將程式碼不需要被修改的部分,設計成類別。至於需要被繼承修改的部分,設計成介面(介面的方法全都是虛擬的),以及實踐這些介面的類別。框架內的類別盡量只使用到這些介面。
框架設計近年來比較不同的是,階層有變深的趨勢(例如AIR和WPF的框架);也就是說,繼承樹的葉節點到根節點之間的距離變大。這樣的好處是程式碼重複利用度增加(所以框架檔案體積變小),以及介面重複利用度增加(學習速度可以加快)。
OO是生產力的最終解答?
與物件導向程式設計關係緊密的是前一個階段「設計」,和下一個階段「測試」。「設計模式」(Design Pattern)將許多好的設計整理出來,讓我們設計功力大增。如果既有的設計不太好,你可以利用「重構」(Refactoring)的技巧來重新整理程式。現在講求TDD(Test-Driven Development,測試驅動開發),對OO來說,「單元測試」(Unit Test)正是以類別為最小單元。
千萬別忘了UML!設計OO系統時,UML可以整理你的想法,方便大家溝通,甚至當MDA(Model Driven Architecture,模式驅動結構)成熟之後,號稱可以用UML把架構設計圖畫出來,用OCL(Object Constraint Language,物件化語言)描述規範,然後就可以產生程式碼。
OO太美好了!OO是軟體開發的極致靈丹!……。繼續作夢吧!儘管OO主宰現今的主流語言、對開發效率似乎有一些提升,但我可沒看過什麼人用了OO之後就若有神助。更不用說OO還有學習門檻、各種OO框架/設計模式的學習曲線、過度工程化的問題。
最近,我覺得真正可以達到更高生產力的關鍵在於更高階的抽象,也就是DSL(Domain Specific Language,特定領域語言)。關於DSL,我將另闢專文介紹。
至於OO,在我有了新歡DSL之後,早就被我打入冷宮了。
蔡學鏞-專職作家
清華大學資訊工程碩士,曾任華碩集團軟體工程師、元智大學資訊系講師、美商歐萊禮出版社技術編輯、臺灣微軟特約專欄作家。
熱門新聞
2025-01-26
2025-01-25
2025-01-26
2025-01-27
2024-04-24
2025-01-24