物件導向程式設計(OOP - Object Oriented Programming)的發展
已有二十幾年﹐許多 OOP 的擁護者也試圖說服大家﹐OOP 是一套適用各處﹑
利多於弊的模型﹑方法。然而現實的情況是否真如他們所宣稱的完美呢?有
人提出了十八項 OOP 的迷思﹐讓大家反相思考。
這十八項迷思分別如下:
OOP 已被證實可適用於任何場合
OOP 能更逼真地模擬真實世界
OOP 讓程式設計工作更加視覺化
OOP 讓程式設計更容易﹑更快
OOP 免除了 "case" 或 "switch" 指令的複雜性
OOP 減少須要修改的地方
繼承(Inheritance)增進重覆利用性
大部份的東西都能在層次分類中適得其所
只有 OOP 能自動收集垃圾(garbage collection)
只有 OOP 能建立元件
OOP 已防止了 Y2K 問題
內容實作的改變顯然通常比介面重要
程式化/關聯性語言將變數型別和大小和程式碼綁得較緊密
程式化/關聯性語言不能 "factor"
這篇的作者認為﹐事實上物件導向支持者不斷地嘗試展現
(範例http://www.geocities.com/tablizer/challeng.htm)OO 的優越性﹐
但都失敗了。『他們引起很大的騷動﹐卻無法實現美夢。』
關於以上諸多迷思﹐作者或多或少都進行了有力的反駁﹐例如有太多實
例證明採用 OOP 的軟體專案﹐如果沒有良好的規劃管理﹐OOP 並無法帶來
什麼好處﹐而有些用非 OOP 的 COBOL 語言來規劃專案﹐也能良好地達到
『重覆使用』﹑『彈性高』的特色。
物件導向程式設計是不是萬靈丹?這是一個複雜而且爭議性極高的問
題。無論如何﹐電腦﹑軟體﹑程式設計方法﹐都是幫助人類解決問題的工
具﹐如果因為個人喜好﹐甚至信仰﹐而忽略了用『解決問題』這個最大前
提來進行思考﹐恐怕難免有失偏頗﹐應從技術﹑理論﹑實作等三方面來理
性討論。歡迎讀者發表您的意見。
只有物件導向資料庫能儲存大量﹑多媒體的資料
OODBMS 整體而言快於 RDBMS
C 是最佳的程式化語言
分享 ASP,ASP.NET,VB,C#,程式開發,網站設計,部落格,微網誌,網路行銷,facebook 行銷,噗浪行銷,社群行銷,電腦硬體軟體,網路賺錢等資訊內容。『噗落格』裡的文章大多是從各網站摘錄(轉貼)下來的,僅提供研究及筆記之用途,如有侵權請留言告知!一開始不打算賺錢,一個不可能中的可能
2009年4月21日 星期二
想起OOP
無意間翻到PTT的OOAD板,看到了一些關於OOP的爭論。
起頭是討論GOD OBJECT,自然就談起了Constructor來。於是乎,一方認為Constructor只能用做建立物件初始之用,避免未來需要用到的時候又要改寫物件。另一方則認為放一些functional的code在裡面無傷大雅,畢竟需求並不到那種程度。
個人以為,OOP的目的與精神,可以化簡為一個單字:Reuse,不論是繼承、多型…都是由這個中心理念推衍出來。由這樣的觀點來看,Constructor的確不需要做多餘的事。
讓我們談的更深入一點:就一個專職於個人電腦應用軟體設計的工程師來說,一個接著一個的專案中,其實很多code都是重複再重複的。常寫程式的人一定遇過這種情況:做專案B的時候,會從專案A裡面複製一段程式碼來,改個變數名稱就可以用了。寫久之後,甚至會遇到一個專案有超過50%的code是剪剪貼貼而來,OOP正是為了解決這種事情而產生的概念。
當然,沒有任何事情是只有好沒有壞的。OOP的缺點就是包袱太重:設如你的物件可以看成是甲乙丙丁四種功能(四樣東西、四個部份…whatever)組成的,而專案A、B、C都會用到。不論你怎麼重組,設計,每個專案都不太可能用到甲乙丙丁四項的完整功能,而是這個用一部份,那個拿一點點;但你卻得為了這些部份的功能,收下一個相對來說很肥大的物件。不過這對一般應用程式來說不是問題,畢竟個人電腦進化夠快。
簡言之:為資源十分有限的系統設計程式(80%以上特製的程式都屬於這種),請別用OOP,你的生活不會因為OOP而美好。為資源充足的系統寫程式,OOP才能發揮他應有的好處,為你爭取喝杯咖啡,陪陪妻兒的時間。
起頭是討論GOD OBJECT,自然就談起了Constructor來。於是乎,一方認為Constructor只能用做建立物件初始之用,避免未來需要用到的時候又要改寫物件。另一方則認為放一些functional的code在裡面無傷大雅,畢竟需求並不到那種程度。
個人以為,OOP的目的與精神,可以化簡為一個單字:Reuse,不論是繼承、多型…都是由這個中心理念推衍出來。由這樣的觀點來看,Constructor的確不需要做多餘的事。
讓我們談的更深入一點:就一個專職於個人電腦應用軟體設計的工程師來說,一個接著一個的專案中,其實很多code都是重複再重複的。常寫程式的人一定遇過這種情況:做專案B的時候,會從專案A裡面複製一段程式碼來,改個變數名稱就可以用了。寫久之後,甚至會遇到一個專案有超過50%的code是剪剪貼貼而來,OOP正是為了解決這種事情而產生的概念。
當然,沒有任何事情是只有好沒有壞的。OOP的缺點就是包袱太重:設如你的物件可以看成是甲乙丙丁四種功能(四樣東西、四個部份…whatever)組成的,而專案A、B、C都會用到。不論你怎麼重組,設計,每個專案都不太可能用到甲乙丙丁四項的完整功能,而是這個用一部份,那個拿一點點;但你卻得為了這些部份的功能,收下一個相對來說很肥大的物件。不過這對一般應用程式來說不是問題,畢竟個人電腦進化夠快。
簡言之:為資源十分有限的系統設計程式(80%以上特製的程式都屬於這種),請別用OOP,你的生活不會因為OOP而美好。為資源充足的系統寫程式,OOP才能發揮他應有的好處,為你爭取喝杯咖啡,陪陪妻兒的時間。
關於OOP 物件導向 (About OOP)
這篇文章的目的是粗略的介紹物件導向程式設計(object-oriented programming) - OOP。
關於這個主題你必要知道的一件事就是「九層之台,起於累土。千里之行,始於足下(Best way to begin a long journey is to make a first step)」-中國諺語。 把它想作我們要無痛的跨出第一步。
我假設你已在 Pascal, C 或某些『通常』程式語言寫過程式同時你覺得有某些事情遺漏。這個『某些事情』就是高層次的抽象。OOP不只是把它想成程式設計的技術。當然,如果程式語言直接支援OOP是最好的--這樣可以讓你能夠以語言本身的語法思考。但既使是非OO的語言,以物件的方式思考也是可以的。
我要引用C++之父Bjarne Stroustrup的話: 小的程式(1000行)可以使用任何東西或任何方式來撰寫。如果你不是那麼簡單,最終你可以讓程式跑。但是,大型程式就不一樣了。如果你不是使用好的『程式設計技術』(尤其是OOP),在你修改舊有的錯誤時新的錯誤隨之產生。
源由是:程式的每一部份相依於許多其他的部分,而這些相依關係是如此的複雜及非直覺性的,既使一個程式設計師撰寫一支程式也沒辦法掌握追尋這些相依關係。當你改變一部份,你沒辦法很容易的看到對於程式其他部分的影響。當然;使用良好的程序性語言(procedural programming),能夠模組化程式及擴充可重複使用程式碼,但如果你是這樣做的話,你已是開始以物件導向思考了。此時你唯一忽略的是以較好的方式組織這些你所寫的程序及方法,並且把這些程序及方法與其操作的資料結構連結在一起。
讓我們回顧在學校所學的,並且溫習資料型別(data type)的定義:「資料型別是成對的(Pair),第一個元素是這個型別所容許的所有值的集合,第二個元素是我們可以執行於這些值的所有操作。」資料型別是具有值及操作的二元性(duality)。
如果你知道甚麼是資料型別,你便知道甚麼是OOP的基礎概念:類別(class)。
事實上,類別不只是以程式語言的方式定義一個資料型別。
把下面的概念在你心中組合起來:一個類別是程式是語言所支援介於函數/程序與資料結構詳盡的(explicit)練結。現在有一個邏輯問題產生了:「但是,我可以在程序的參數放入任何東西--包括我想要的資料結構--而且這是我把資料結構連結到操作的方式。這有甚麼不同?」差異就是上面所說的『詳盡的(explicit)』。在OOP;屬於類別的程序有許多不同特定(special)方式,同時經由這些特定的方式你可以在『單獨(stand-alone)』的程序做一些不可思議的事情。這些『成員(member)』的程序就叫做方法(method)。
所以,為什麼我需要把資料操作連結進來?主要有下列4個優點:
第一個優點:乾淨的名稱(clear names)
如果你有一個類別Triangle(三角形)及方法Paint(這個方法可以呼叫用以繪至三角形),你也可以有一個類別Square(正方形)也有一個方法Paint(這個方法繪製正方形)。既使有相同的名稱,這些方法還是不同的。所以,節省名稱並且避免衝突。模組(modules)(在Pasical中的單元(units))可以做為這個用途的使用,同時有些語言提供區隔的機制以克服邏輯名稱(例如C++命名空間Vnamespaces)或Modular-2廣泛的實作模組)。但是模組在任務中往往太『沈重(heavy)』,尤其是如果(在Pascal中)受限於原始碼的實際儲存體--檔案。舉例來說在Modula-2的模組可以包含次模組。這些次模組明確地定義哪些他們可以看以及從外界可以被看到,但這些看起來像是嘗試以鐵鎚打一隻蒼蠅。此外如果你有一個變數t是屬於Triangle類別以及一個變數s是屬於Square類別,你以t.paint繪製三角形而以s.paint繪製正方形--你想還有比這更簡單的嗎?
因此我來到物件(object)這個名詞。簡單易懂,物件是某個類別的變數。另一個物件的名稱是實例(instance)。類別是型別(type)的定義,物件是類別的一個特定實例(specimen)。例如,當我們說t有型別(類別)Triangle,另一種說法是:t是Triangle的物件(實例)。所以t與s都是物件。
第二個優點:封裝(encapsulation)
每一個類別可以隱藏他的某一部份。如果你有一些輔助的部分程式碼;這些程式碼只是供類別本身的方法呼叫,你可以讓他成為私有方法(private method)--在類別外部無法看到。
如果你是撰寫大型程式,你使用模組並且隱藏這類程式碼在實作段(implementation section)(在C++中是cpp檔)。無論如何;你是在大量的模組下及每一個模組使用其他每一個而使自己冒相當的風險,而且這些模組相互關連(interconnected)不會是你所喜歡的......
隱藏程式碼稱為封裝。有些語言例如C++及新版的Java甚至可以讓類別中還有類別,而這些『被包含』的類別是其包含類別私有類別;這些是沒有OOP則沒辦法辦到的。
直到現在;應用許多自我訓練(self-discipline);你只可以經由使用傳統的『好的程式設計』技術自保。現在有一些東西沒有OOP根本是不可能達成的。
第三個優點:繼承(inheritance)
最重要的優點就是:繼承是擴充或改變既有『父』類別的方式,並且讓『子類別』仍然連結其父類別。這是程式碼再使用的關鍵。
如果你已有一個類別只是與你所需的有些微的差異,為什麼你不使用這個既有的類別,而只是增加差異的部分?當然,使用複製貼上程式碼,你也可以快速的『再使用』程式碼。但是這種複製貼上的方式你產生了兩個程式碼複本(copies)其中你只知道他們應該做相同的事情--亦即你必須同時維護這兩個複本。想像一個特殊情況就是你有10個複本!我必須提醒你:那並非不尋常;許多類別程式庫(像Delphi的VCL)有好幾打的繼承階層包含幾百個類別。如果那是以複製貼上程式碼的方式那是多麼複雜,而我們還尚未說到效率的問題呢。
無論如何,當你使用繼承,如果你改變父類別的任何東西,你可以自動的改變到子類別(及子類別的子類別等等)。從另一方面而言,在多數的語言,你可以產生一個新的子類別而無須重新編譯父類別,甚至無須父類別的原始碼--只需要介面就可以(類別及方法的宣告而沒有定義)。因此,沒有重複編譯相同的程式碼,同時所有的事情都是比較快速且簡單的。
但是使用繼承,你可以增加新的方法及欄位;或者修改現有的方法。我們將在後面更詳細的討論繼承。
第四個優點:多型(polymorphism)
與繼承緊密相關的概念就是多型。多型的觀念對於OOP的新手可能比較難領會,所以如果你一時無法全然瞭解也不要太緊張。當你從一個類別繼承,你(在實體層(physical level))增加/修改方法或者增加欄位,這就是多型。
但是在邏輯層(logical level)你是產生了類別的一個次種類(sub-kind)。
現在,小姐先生,一個多型的更進一步的想法(meta-though):子類別就是父類別(child is parent)。這表示:你可以在父類別可以使用的地方使用子類別(既使你或許也可以在其他的地方使用子類別),這很簡單因為子類別包含所有父類別所包含的(既使子類別或許包含多一些)。請記得反向則否。父類別不是子類別(parent is not child)--子類別總是包含一些東西是父類別所沒有的,因此我們不能以父類別替代子類別。
現在,多型的本質:既使我們以子類別替代父類別,他仍然是子類別。如果其中有一個類別是屬於子類別及父類別,哪一個版本將會被建立是依據你在執行期所使用的類別。如果我們使用子類別,那麼子類別的方法將被呼叫。例如;不管我們宣告的是父類別的變數,在執行期我們可以在此以子類別取代,而子類別將仍然是以子類別的行為工作。
此外,可能的子類別/父類別替代是在OOP中使用指標的原因。
因此,不同類別的物件可以以相同的手法使用,但依據他們實際的類別而有不同的行為。相對的,我們可能沒有決定特定物件的實際類別,但在執行期,正確類別的方法將被呼叫--而不是編譯期所宣告的類別。
結論
讓Bjarne Stroustrup再次幫助我們:程式語言有兩個觀點:
首先是告訴機器要做甚麼的技術部分。
其次概念工具;你可以用於思考如何解決問題。
我所寫的理論,不只是包含於每一個主要的物件導向語言,也是代表抽象思考傑出的工具。你不想壓抑你在流程圖的創造性,你將進一步偏離及以物件切割問題;而這個物件是由問題所行成。你將物件分門別類成為類別,並將類別組織成邏輯的樹狀(tree-like)的結構--類別層級架構(hierarchies)。
關於這個主題你必要知道的一件事就是「九層之台,起於累土。千里之行,始於足下(Best way to begin a long journey is to make a first step)」-中國諺語。 把它想作我們要無痛的跨出第一步。
我假設你已在 Pascal, C 或某些『通常』程式語言寫過程式同時你覺得有某些事情遺漏。這個『某些事情』就是高層次的抽象。OOP不只是把它想成程式設計的技術。當然,如果程式語言直接支援OOP是最好的--這樣可以讓你能夠以語言本身的語法思考。但既使是非OO的語言,以物件的方式思考也是可以的。
我要引用C++之父Bjarne Stroustrup的話: 小的程式(1000行)可以使用任何東西或任何方式來撰寫。如果你不是那麼簡單,最終你可以讓程式跑。但是,大型程式就不一樣了。如果你不是使用好的『程式設計技術』(尤其是OOP),在你修改舊有的錯誤時新的錯誤隨之產生。
源由是:程式的每一部份相依於許多其他的部分,而這些相依關係是如此的複雜及非直覺性的,既使一個程式設計師撰寫一支程式也沒辦法掌握追尋這些相依關係。當你改變一部份,你沒辦法很容易的看到對於程式其他部分的影響。當然;使用良好的程序性語言(procedural programming),能夠模組化程式及擴充可重複使用程式碼,但如果你是這樣做的話,你已是開始以物件導向思考了。此時你唯一忽略的是以較好的方式組織這些你所寫的程序及方法,並且把這些程序及方法與其操作的資料結構連結在一起。
讓我們回顧在學校所學的,並且溫習資料型別(data type)的定義:「資料型別是成對的(Pair),第一個元素是這個型別所容許的所有值的集合,第二個元素是我們可以執行於這些值的所有操作。」資料型別是具有值及操作的二元性(duality)。
如果你知道甚麼是資料型別,你便知道甚麼是OOP的基礎概念:類別(class)。
事實上,類別不只是以程式語言的方式定義一個資料型別。
把下面的概念在你心中組合起來:一個類別是程式是語言所支援介於函數/程序與資料結構詳盡的(explicit)練結。現在有一個邏輯問題產生了:「但是,我可以在程序的參數放入任何東西--包括我想要的資料結構--而且這是我把資料結構連結到操作的方式。這有甚麼不同?」差異就是上面所說的『詳盡的(explicit)』。在OOP;屬於類別的程序有許多不同特定(special)方式,同時經由這些特定的方式你可以在『單獨(stand-alone)』的程序做一些不可思議的事情。這些『成員(member)』的程序就叫做方法(method)。
所以,為什麼我需要把資料操作連結進來?主要有下列4個優點:
第一個優點:乾淨的名稱(clear names)
如果你有一個類別Triangle(三角形)及方法Paint(這個方法可以呼叫用以繪至三角形),你也可以有一個類別Square(正方形)也有一個方法Paint(這個方法繪製正方形)。既使有相同的名稱,這些方法還是不同的。所以,節省名稱並且避免衝突。模組(modules)(在Pasical中的單元(units))可以做為這個用途的使用,同時有些語言提供區隔的機制以克服邏輯名稱(例如C++命名空間Vnamespaces)或Modular-2廣泛的實作模組)。但是模組在任務中往往太『沈重(heavy)』,尤其是如果(在Pascal中)受限於原始碼的實際儲存體--檔案。舉例來說在Modula-2的模組可以包含次模組。這些次模組明確地定義哪些他們可以看以及從外界可以被看到,但這些看起來像是嘗試以鐵鎚打一隻蒼蠅。此外如果你有一個變數t是屬於Triangle類別以及一個變數s是屬於Square類別,你以t.paint繪製三角形而以s.paint繪製正方形--你想還有比這更簡單的嗎?
因此我來到物件(object)這個名詞。簡單易懂,物件是某個類別的變數。另一個物件的名稱是實例(instance)。類別是型別(type)的定義,物件是類別的一個特定實例(specimen)。例如,當我們說t有型別(類別)Triangle,另一種說法是:t是Triangle的物件(實例)。所以t與s都是物件。
第二個優點:封裝(encapsulation)
每一個類別可以隱藏他的某一部份。如果你有一些輔助的部分程式碼;這些程式碼只是供類別本身的方法呼叫,你可以讓他成為私有方法(private method)--在類別外部無法看到。
如果你是撰寫大型程式,你使用模組並且隱藏這類程式碼在實作段(implementation section)(在C++中是cpp檔)。無論如何;你是在大量的模組下及每一個模組使用其他每一個而使自己冒相當的風險,而且這些模組相互關連(interconnected)不會是你所喜歡的......
隱藏程式碼稱為封裝。有些語言例如C++及新版的Java甚至可以讓類別中還有類別,而這些『被包含』的類別是其包含類別私有類別;這些是沒有OOP則沒辦法辦到的。
直到現在;應用許多自我訓練(self-discipline);你只可以經由使用傳統的『好的程式設計』技術自保。現在有一些東西沒有OOP根本是不可能達成的。
第三個優點:繼承(inheritance)
最重要的優點就是:繼承是擴充或改變既有『父』類別的方式,並且讓『子類別』仍然連結其父類別。這是程式碼再使用的關鍵。
如果你已有一個類別只是與你所需的有些微的差異,為什麼你不使用這個既有的類別,而只是增加差異的部分?當然,使用複製貼上程式碼,你也可以快速的『再使用』程式碼。但是這種複製貼上的方式你產生了兩個程式碼複本(copies)其中你只知道他們應該做相同的事情--亦即你必須同時維護這兩個複本。想像一個特殊情況就是你有10個複本!我必須提醒你:那並非不尋常;許多類別程式庫(像Delphi的VCL)有好幾打的繼承階層包含幾百個類別。如果那是以複製貼上程式碼的方式那是多麼複雜,而我們還尚未說到效率的問題呢。
無論如何,當你使用繼承,如果你改變父類別的任何東西,你可以自動的改變到子類別(及子類別的子類別等等)。從另一方面而言,在多數的語言,你可以產生一個新的子類別而無須重新編譯父類別,甚至無須父類別的原始碼--只需要介面就可以(類別及方法的宣告而沒有定義)。因此,沒有重複編譯相同的程式碼,同時所有的事情都是比較快速且簡單的。
但是使用繼承,你可以增加新的方法及欄位;或者修改現有的方法。我們將在後面更詳細的討論繼承。
第四個優點:多型(polymorphism)
與繼承緊密相關的概念就是多型。多型的觀念對於OOP的新手可能比較難領會,所以如果你一時無法全然瞭解也不要太緊張。當你從一個類別繼承,你(在實體層(physical level))增加/修改方法或者增加欄位,這就是多型。
但是在邏輯層(logical level)你是產生了類別的一個次種類(sub-kind)。
現在,小姐先生,一個多型的更進一步的想法(meta-though):子類別就是父類別(child is parent)。這表示:你可以在父類別可以使用的地方使用子類別(既使你或許也可以在其他的地方使用子類別),這很簡單因為子類別包含所有父類別所包含的(既使子類別或許包含多一些)。請記得反向則否。父類別不是子類別(parent is not child)--子類別總是包含一些東西是父類別所沒有的,因此我們不能以父類別替代子類別。
現在,多型的本質:既使我們以子類別替代父類別,他仍然是子類別。如果其中有一個類別是屬於子類別及父類別,哪一個版本將會被建立是依據你在執行期所使用的類別。如果我們使用子類別,那麼子類別的方法將被呼叫。例如;不管我們宣告的是父類別的變數,在執行期我們可以在此以子類別取代,而子類別將仍然是以子類別的行為工作。
此外,可能的子類別/父類別替代是在OOP中使用指標的原因。
因此,不同類別的物件可以以相同的手法使用,但依據他們實際的類別而有不同的行為。相對的,我們可能沒有決定特定物件的實際類別,但在執行期,正確類別的方法將被呼叫--而不是編譯期所宣告的類別。
結論
讓Bjarne Stroustrup再次幫助我們:程式語言有兩個觀點:
首先是告訴機器要做甚麼的技術部分。
其次概念工具;你可以用於思考如何解決問題。
我所寫的理論,不只是包含於每一個主要的物件導向語言,也是代表抽象思考傑出的工具。你不想壓抑你在流程圖的創造性,你將進一步偏離及以物件切割問題;而這個物件是由問題所行成。你將物件分門別類成為類別,並將類別組織成邏輯的樹狀(tree-like)的結構--類別層級架構(hierarchies)。
話說從頭 - 為什麼要使用物件導向設計 (OOD)
會想要談論這個題目其實是有緣故的。
自從.Net Go2 OO這個部落格成立以來,我們發表了幾篇關於物件導向基礎的文章,關心的眼光都停留在介面這個重量級的角色上,其中包含了介面使用的時機以及為何要使用介面的正確觀念;另一方面我們也發表了幾篇較為進階的文章,初步的介紹了Design Patterns中較為簡單的幾個樣式,其中也包含了一篇如何應用Pattern來實做的案例。
但是我們逐漸聽到了類似下面的問題:「究竟為什麼要使用物件導向設計,在現實面究竟有什麼好處存在?在現實上這麼辛苦麻煩的設計架構究竟有沒有價值?」
我不禁回想起這些年來學習程式設計以及物件導向設計的過程,這中間我不斷的聽到這樣的標準答案,所謂物件導向就是封裝(Encapsulation)、繼承(Inheritance)、多型(Polymorphism)。我也在許多書本上學習了這些詞彙的解釋,也懂得了如何利用這些特性來撰寫程式(OOP),但是即便如此,我還是沒辦法很輕易的回答上面的問題,我也很少聽到或者看到一個可以讓我由衷讚嘆「對啦,就是這樣!」的說法。
接著我開始接觸物件導向設計(OOD),解釋物件導向的說法開始變的更加虛無飄渺了,每個人都用「汽車與卡車都是車子」的故事來為我解釋物件導向。可是就算我知道汽車跟卡車其實有親戚關係,我還是沒辦法自圓其說為什麼我要使用物件導向設計。難道就因為大家都說它好所以它就好嗎?
然而隨著接觸的層面越來越廣,對於物件導向設計我逐漸有了另外一種看法。
我們時常提及的封裝、繼承、多型或者物件的分析本質都是物件導向設計的特色,又或者說物件導向設計是由這些特質所組合而成的。但是這並不足以構成物件導向成為主流的原因。
一個男人的如果長的很帥可以是他的特色,但是如果長的帥沒辦法為他帶來好處,那我們就不能說長的帥是他的優點。
那麼封裝、繼承、多型這些特色究竟可以為我們帶來什麼好處?
這裡不打算解釋什麼是封裝、繼承、多型,有許多書本都講解的非常的清楚明白,要麻煩不瞭解的朋友們去查閱這些書籍。
換個角度
首先,封裝讓程式碼易於理解。我們可以從一個類別的名稱以及他的行為去理解與記憶它和系統之間的關係與責任,這樣的特性可以縮短日後我們重新檢視程式碼時所要花費的時間,沒有人會說這不是好處吧?
再來,繼承讓程式碼可以重複使用。就拿剛剛提到的車子、汽車與卡車的例子來說吧。我們把大部分重複的程式碼寫在車子的類別裡,以後的十種汽車跟八種卡車都可以直接享用車子中已經定義好的程式碼與功能。我們因此縮短了浪費在重複性工作上的時間。
最後,多型讓程式易於擴充與維護。針對共通的介面來撰寫程式時,可以使得物件之間的關係被鬆綁,讓軟體在日後進行擴充或者個別物件修改時不需要更動到既有的程式碼。當軟體龐大到一定程度之後,擴充與修改對程式設計師而言往往是非常痛苦的一件事情,我對於善用介面可以達到的效果非常推崇,可以說相當程度的提供了軟體品質的穩定。
撇開所有美輪美奐的說詞,回來面對現實,我們就是為了能夠讓程式碼重複利用,讓系統易於擴充與維護所以才要使用物件導向。這一切最直接的效果就反應在縮短軟體開發的時間以及增進軟體的品質穩定度上,讓我們能夠專注在真正重要的工作上面。美麗或者基本教義派的崇拜都不是物件導向之所以存在的原因。
站在實作的角度來看,物件導向的存在就是為了增進程式設計師工作的效率以及軟體的品質,以這樣的觀點而言,使用物件導向設計是再實際也不過了,千萬別說使用物件導向是天真而不肯面對現實。
水能載舟亦能覆舟
不過問題來了,既然物件導向這麼優秀,為什麼還會有這麼多人不願意把她娶進門,仍然嫌東嫌西的呢?
其實上帝是公平的,這世界上本來就不存在十全十美的事物,物件導向既然擁有這麼抽象而複雜的特性,也就造成了它在撰寫上一開始就必須克服的時間成本。為了能夠做到封裝,所以我們必須多花一些時間在分析物件的責任歸屬,為了做到繼承,所以我們必須多花一些時間在分析物件之間共有的責任與資料,為了日後擴充方便,我們必須多花一些時間創造出合適的抽象介面來讓物件實做。
這些都是伴隨著物件導向設計而來的工作。我們不能否認,使用結構式的程式設計不必付出這些時間成本;當然,自然也享受不到繼承與介面的優點。
持平而論,物件導向的出現是為了讓程式設計師能夠用更短的時間開發出更優良的軟體,如果在某些現實條件下的評估結果是,不使用複雜的物件導向設計勝於使用的話,又為何不選擇簡單一點架構呢?明明不會有擴充或者變動的可能性,硬要放個抽象介面在那邊礙眼,這是最不智的行為。
吃路邊攤的時候穿晚禮服,就算你長的再美,也只會讓人家覺得你有毛病而已,不是嗎?
結論
在現實生活中開發任何軟體專案時,我們通常希望在專案的進度、品質以及成本之間取得平衡,極端的要求在最短的時間內花掉最少的成本來取得最高的品質是不可能實現的夢想。
物件導向設計是軟體開發歷史演進下的產物,集結了許多前輩的智慧與經驗而成,即便是如此,也不可能達到上述夢想中的境界。我們當然可以追求最完美的物件導向設計架構,但是必然將犧牲開發的進度以及成本。相對的,一昧追求時效捨棄良好的軟體設計也不可能得到合理的品質。
許多時候並非物件導向設計無用,只是在有條件的選擇下被捨棄罷了。
自從.Net Go2 OO這個部落格成立以來,我們發表了幾篇關於物件導向基礎的文章,關心的眼光都停留在介面這個重量級的角色上,其中包含了介面使用的時機以及為何要使用介面的正確觀念;另一方面我們也發表了幾篇較為進階的文章,初步的介紹了Design Patterns中較為簡單的幾個樣式,其中也包含了一篇如何應用Pattern來實做的案例。
但是我們逐漸聽到了類似下面的問題:「究竟為什麼要使用物件導向設計,在現實面究竟有什麼好處存在?在現實上這麼辛苦麻煩的設計架構究竟有沒有價值?」
我不禁回想起這些年來學習程式設計以及物件導向設計的過程,這中間我不斷的聽到這樣的標準答案,所謂物件導向就是封裝(Encapsulation)、繼承(Inheritance)、多型(Polymorphism)。我也在許多書本上學習了這些詞彙的解釋,也懂得了如何利用這些特性來撰寫程式(OOP),但是即便如此,我還是沒辦法很輕易的回答上面的問題,我也很少聽到或者看到一個可以讓我由衷讚嘆「對啦,就是這樣!」的說法。
接著我開始接觸物件導向設計(OOD),解釋物件導向的說法開始變的更加虛無飄渺了,每個人都用「汽車與卡車都是車子」的故事來為我解釋物件導向。可是就算我知道汽車跟卡車其實有親戚關係,我還是沒辦法自圓其說為什麼我要使用物件導向設計。難道就因為大家都說它好所以它就好嗎?
然而隨著接觸的層面越來越廣,對於物件導向設計我逐漸有了另外一種看法。
我們時常提及的封裝、繼承、多型或者物件的分析本質都是物件導向設計的特色,又或者說物件導向設計是由這些特質所組合而成的。但是這並不足以構成物件導向成為主流的原因。
一個男人的如果長的很帥可以是他的特色,但是如果長的帥沒辦法為他帶來好處,那我們就不能說長的帥是他的優點。
那麼封裝、繼承、多型這些特色究竟可以為我們帶來什麼好處?
這裡不打算解釋什麼是封裝、繼承、多型,有許多書本都講解的非常的清楚明白,要麻煩不瞭解的朋友們去查閱這些書籍。
換個角度
首先,封裝讓程式碼易於理解。我們可以從一個類別的名稱以及他的行為去理解與記憶它和系統之間的關係與責任,這樣的特性可以縮短日後我們重新檢視程式碼時所要花費的時間,沒有人會說這不是好處吧?
再來,繼承讓程式碼可以重複使用。就拿剛剛提到的車子、汽車與卡車的例子來說吧。我們把大部分重複的程式碼寫在車子的類別裡,以後的十種汽車跟八種卡車都可以直接享用車子中已經定義好的程式碼與功能。我們因此縮短了浪費在重複性工作上的時間。
最後,多型讓程式易於擴充與維護。針對共通的介面來撰寫程式時,可以使得物件之間的關係被鬆綁,讓軟體在日後進行擴充或者個別物件修改時不需要更動到既有的程式碼。當軟體龐大到一定程度之後,擴充與修改對程式設計師而言往往是非常痛苦的一件事情,我對於善用介面可以達到的效果非常推崇,可以說相當程度的提供了軟體品質的穩定。
撇開所有美輪美奐的說詞,回來面對現實,我們就是為了能夠讓程式碼重複利用,讓系統易於擴充與維護所以才要使用物件導向。這一切最直接的效果就反應在縮短軟體開發的時間以及增進軟體的品質穩定度上,讓我們能夠專注在真正重要的工作上面。美麗或者基本教義派的崇拜都不是物件導向之所以存在的原因。
站在實作的角度來看,物件導向的存在就是為了增進程式設計師工作的效率以及軟體的品質,以這樣的觀點而言,使用物件導向設計是再實際也不過了,千萬別說使用物件導向是天真而不肯面對現實。
水能載舟亦能覆舟
不過問題來了,既然物件導向這麼優秀,為什麼還會有這麼多人不願意把她娶進門,仍然嫌東嫌西的呢?
其實上帝是公平的,這世界上本來就不存在十全十美的事物,物件導向既然擁有這麼抽象而複雜的特性,也就造成了它在撰寫上一開始就必須克服的時間成本。為了能夠做到封裝,所以我們必須多花一些時間在分析物件的責任歸屬,為了做到繼承,所以我們必須多花一些時間在分析物件之間共有的責任與資料,為了日後擴充方便,我們必須多花一些時間創造出合適的抽象介面來讓物件實做。
這些都是伴隨著物件導向設計而來的工作。我們不能否認,使用結構式的程式設計不必付出這些時間成本;當然,自然也享受不到繼承與介面的優點。
持平而論,物件導向的出現是為了讓程式設計師能夠用更短的時間開發出更優良的軟體,如果在某些現實條件下的評估結果是,不使用複雜的物件導向設計勝於使用的話,又為何不選擇簡單一點架構呢?明明不會有擴充或者變動的可能性,硬要放個抽象介面在那邊礙眼,這是最不智的行為。
吃路邊攤的時候穿晚禮服,就算你長的再美,也只會讓人家覺得你有毛病而已,不是嗎?
結論
在現實生活中開發任何軟體專案時,我們通常希望在專案的進度、品質以及成本之間取得平衡,極端的要求在最短的時間內花掉最少的成本來取得最高的品質是不可能實現的夢想。
物件導向設計是軟體開發歷史演進下的產物,集結了許多前輩的智慧與經驗而成,即便是如此,也不可能達到上述夢想中的境界。我們當然可以追求最完美的物件導向設計架構,但是必然將犧牲開發的進度以及成本。相對的,一昧追求時效捨棄良好的軟體設計也不可能得到合理的品質。
許多時候並非物件導向設計無用,只是在有條件的選擇下被捨棄罷了。
系統設計的起點:如何將需求轉為物件導向的設計
筆者在近日因某些關係與一位已退休的東海大學物理系劉教授聚餐聊天,在談話的過程中我似乎與教授生活在不同的世界一般,可想而知物理是一切科學之本,而教授的思路與談吐都環繞著他們數十年來所追求的真理與中心思想,我想這便是一種思考原則吧!
相對的,若我們將焦點縮小到物件導向設計,它的中心思想筆者由自己的經驗與書籍上可歸納出就是『將真實世界的物體抽象化』,不過這種說法我想對於一般的讀者來說會充滿了疑惑且難以想像,就好像我與劉教授一樣,無法進入他的思考境界一般,因為充滿哲理的說法,是需要很多知識與智慧的結合才能夠體會的。
這篇文章的目的就是為了協助初學物件導向設計的讀者用最簡單的方式將真實世界的需求轉換為類別設計,以筆者的經驗與心得來引導讀者去分析及找出學習的盲點。
筆者在學習物件導向程式設計(C++)過程中,翻過了很多的書籍,跳過每本書的前一至三章說明程式設計的基本功夫不說,大部分書上的內容結構都離不開物件導向程式設計的通則『繼承』、『封裝』及『多形』等,也會給予很多的範例讓讀者練習,不過,當讀者要接觸真實的專案設計時,不一定能立刻將問題及需求轉換為物件導向的設計方法。
其實這是很正常的,因為書上都會盡量以範例來闡述物件導向,缺少了系統分析與設計的部分,因此,大部分的初學者會碰到這樣的瓶頸,筆者也不例外,不過當時並沒有前輩們的指導,協助我如何去思考及實作,所以,只能從實務中去體會學習如何以物件還思考問題了。
為什麼會碰到這個瓶頸呢?我想在於書本上的範例過於強調以一個案例敘述來解釋物件導向程式設計(OOP)的概念,忽略了引述案例所應包含的前因果,讓讀者可以『初步』的去體會或瞭解一些物件導向設計(OOD)的概念,如此極有可能造成剛學會OOP的人,在轉換到OOD時有學習的斷層存在,甚至與資深的程式設計師或分析師討論問題時,也有可能發生溝通上的困難,這個論點我在『物件導向OO技術基礎講座』一書中作者也同樣的點出此問題。
初學物件導向程式設計的人員,不必過於將真實世界的所有事情都要以OO的觀點來看待他,因為此時你所學習到的只是如何去實踐OO系統開發的工具而已,你可能會一直停留在物件導向的reuse或extend等執著當中,所以你會遇到為什麼使用OO會這麼的礙手礙腳的問題,此時別灰心,因為只是你缺少了一些思考的觀點、原則及方法等經驗吧!
需求與類別的關係
在系統開發時的工作要點之一就是系統分析,所謂分析是去找出問題及需求,在物件導向分析中我們經常將分析區分為:
找尋及界定問題的『需求分析』。
找尋問題描述的『物件分析』,經過這兩個步驟之後你就可以初步的找出需求中的物件了。
在需求分析階段,此時是專案開發時最重要也最複雜的階段,是必需經過很綿密的思考及溝通才能產生較為完整的需求,這也必須依賴豐富的經驗與專業素養,甚至良好的公關能力才能順利的完成,所以,當你還是初學者的時候,若身旁有資深的人員帶領那是最好也不過了,若沒有當然還是必須先稍微做一下功課後才去執行此項工作,一方面可以在最短時間內取得客戶對你的信任,另一方面也容易打開彼此之間的關係。關於這方面的問題,我想不需要論述得太多,而筆者這篇文章主要還是把重點放在需求與物件的主題中,所以不再多加闡述。
一般需求分析時,都會先列出系統的參與者(角色),及針對這些參與者的問題需求寫成描述,這階段對於瀑布式需求分析(Waterfall)或物件導向需求分析等方法來說其實大同小異,就如同『USE CASE』使用案例來說,其實它主要是利用「文字敘述」來描述需求的內容,之後訂定的UML才將Use Case Diagram作為輔助表達參與者與系統之間關係的一種圖形,但在諸多文獻中仍可明確得知,Use Cases的重心仍然在文字敘述,單就這點而言,需求分析的工作並不會因為物件導向的開發而有所不同。
總結來說,在系統分析方法上的主要差異性在還是於『物件分析』階段的思考模式。
瀑布式需求分析階段
物件導向需求分析階段
需求描述
文字描述需求
文字描述需求(USE CASE)
圖形工具
傳統流程圖
Use Case Diagram
System Sequence Diagram
其他
需求轉化為物件之分析
在物件分析階段,主要就是在需求描述的問題的範圍內找出類別來,有時會稱作「問題領域物件」,物件經一般化後便產生類別來,此時你就已經有了系統分析的初步結果了。然而問題往往是初學者對於如何需求敘述中找出類別、方法及屬性也會感到力不從心,因為這才是將系統需求轉化為物件導向系統分析的關鍵所在,不過資深的前輩們也都知道這樣的轉化過程,其實是需要很多的經驗所累積的,而這對初學者而言卻是最難跨出的一步。
因此在本篇文章中,我們先將以簡單的方法來介紹並結合筆者們常用的思考方式來幫助初學者,以期能夠縮短學習的曲線,至於更詳細的內容我們將在往後文章中來作闡述。
筆者們常用的方法中,就如『Applying UML And Patterns』一書中所提的需求分析與物件導向分析與設計的方法中一般,大約可分為四個步驟:
定義使用案例-描述詳細的需求的情境(Use Case)。
定義領域模型-將現實世界的物體抽象或一般化,並找出屬性及關聯。
定義互動圖-將物件與物件之間的訊息傳遞的行為找出來(Sequence Diagram)。
定義設計類別圖-找出物件內的屬性及方法(Class Diagram)。
不過上述的步驟方法大都是已經有該專案的Know how且有OOAD的經驗者之思考及實作的方法,因為他們已經可以憑著經驗,而能夠很直覺得定義出需求中所需的物件、屬性及方法,更進一步的能夠分析出物件與物件之間的關係,不過,筆者整理出下列的方法,可以協助初學者較容易找出上述幾個步驟中可以產出的一些分析文件及圖形:
a、 由需求中找出類別
從每個需求敘述中找出『名詞』來,每個名詞都是類別的候選者,再篩選出該類別可能含有行為及屬性,若該名詞不具備行為(方法)及屬性,則可能是某類別的屬性之一,此方法可對應著上述的『定義領域模型』的步驟。
b、 找出類別的方法
找出需求敘述中的動詞(is、was、have),這將會是方法的候選者,且透過需求敘述你可以再將這些動詞與上一步驟所找出的名詞結合,繪製出所謂的『互動圖』及『類別圖』。
c、 找出類別的屬性
類別候選者所消除的名詞可能就是某些類別的屬性,這也是『定義領域模型』的一種另類思考的方法。
d、 驗證你的需求
重新驗證需求中的每個敘述,並檢討可能遺漏的必要功能。
結論
關於需求轉為物件導向系統分析的方法諸多繁瑣,而且真的需要經驗的累積,筆者所闡述的是盡量讓初學者得到一些啟發,至於對錯可能都會因人而異,且這個主題充滿了很多的哲理,要描述這些哲理不是一篇短文能夠涵蓋的,因此筆者先以這篇文章作個開場白,因為或多或少在未來的文章裡,大都會提到與本文相關的一些議題,因為這篇文章是物件導向設計與分析的核心,所以,一些關鍵的議題將會在未來為各位說明,敬請期待囉~
相對的,若我們將焦點縮小到物件導向設計,它的中心思想筆者由自己的經驗與書籍上可歸納出就是『將真實世界的物體抽象化』,不過這種說法我想對於一般的讀者來說會充滿了疑惑且難以想像,就好像我與劉教授一樣,無法進入他的思考境界一般,因為充滿哲理的說法,是需要很多知識與智慧的結合才能夠體會的。
這篇文章的目的就是為了協助初學物件導向設計的讀者用最簡單的方式將真實世界的需求轉換為類別設計,以筆者的經驗與心得來引導讀者去分析及找出學習的盲點。
筆者在學習物件導向程式設計(C++)過程中,翻過了很多的書籍,跳過每本書的前一至三章說明程式設計的基本功夫不說,大部分書上的內容結構都離不開物件導向程式設計的通則『繼承』、『封裝』及『多形』等,也會給予很多的範例讓讀者練習,不過,當讀者要接觸真實的專案設計時,不一定能立刻將問題及需求轉換為物件導向的設計方法。
其實這是很正常的,因為書上都會盡量以範例來闡述物件導向,缺少了系統分析與設計的部分,因此,大部分的初學者會碰到這樣的瓶頸,筆者也不例外,不過當時並沒有前輩們的指導,協助我如何去思考及實作,所以,只能從實務中去體會學習如何以物件還思考問題了。
為什麼會碰到這個瓶頸呢?我想在於書本上的範例過於強調以一個案例敘述來解釋物件導向程式設計(OOP)的概念,忽略了引述案例所應包含的前因果,讓讀者可以『初步』的去體會或瞭解一些物件導向設計(OOD)的概念,如此極有可能造成剛學會OOP的人,在轉換到OOD時有學習的斷層存在,甚至與資深的程式設計師或分析師討論問題時,也有可能發生溝通上的困難,這個論點我在『物件導向OO技術基礎講座』一書中作者也同樣的點出此問題。
初學物件導向程式設計的人員,不必過於將真實世界的所有事情都要以OO的觀點來看待他,因為此時你所學習到的只是如何去實踐OO系統開發的工具而已,你可能會一直停留在物件導向的reuse或extend等執著當中,所以你會遇到為什麼使用OO會這麼的礙手礙腳的問題,此時別灰心,因為只是你缺少了一些思考的觀點、原則及方法等經驗吧!
需求與類別的關係
在系統開發時的工作要點之一就是系統分析,所謂分析是去找出問題及需求,在物件導向分析中我們經常將分析區分為:
找尋及界定問題的『需求分析』。
找尋問題描述的『物件分析』,經過這兩個步驟之後你就可以初步的找出需求中的物件了。
在需求分析階段,此時是專案開發時最重要也最複雜的階段,是必需經過很綿密的思考及溝通才能產生較為完整的需求,這也必須依賴豐富的經驗與專業素養,甚至良好的公關能力才能順利的完成,所以,當你還是初學者的時候,若身旁有資深的人員帶領那是最好也不過了,若沒有當然還是必須先稍微做一下功課後才去執行此項工作,一方面可以在最短時間內取得客戶對你的信任,另一方面也容易打開彼此之間的關係。關於這方面的問題,我想不需要論述得太多,而筆者這篇文章主要還是把重點放在需求與物件的主題中,所以不再多加闡述。
一般需求分析時,都會先列出系統的參與者(角色),及針對這些參與者的問題需求寫成描述,這階段對於瀑布式需求分析(Waterfall)或物件導向需求分析等方法來說其實大同小異,就如同『USE CASE』使用案例來說,其實它主要是利用「文字敘述」來描述需求的內容,之後訂定的UML才將Use Case Diagram作為輔助表達參與者與系統之間關係的一種圖形,但在諸多文獻中仍可明確得知,Use Cases的重心仍然在文字敘述,單就這點而言,需求分析的工作並不會因為物件導向的開發而有所不同。
總結來說,在系統分析方法上的主要差異性在還是於『物件分析』階段的思考模式。
瀑布式需求分析階段
物件導向需求分析階段
需求描述
文字描述需求
文字描述需求(USE CASE)
圖形工具
傳統流程圖
Use Case Diagram
System Sequence Diagram
其他
需求轉化為物件之分析
在物件分析階段,主要就是在需求描述的問題的範圍內找出類別來,有時會稱作「問題領域物件」,物件經一般化後便產生類別來,此時你就已經有了系統分析的初步結果了。然而問題往往是初學者對於如何需求敘述中找出類別、方法及屬性也會感到力不從心,因為這才是將系統需求轉化為物件導向系統分析的關鍵所在,不過資深的前輩們也都知道這樣的轉化過程,其實是需要很多的經驗所累積的,而這對初學者而言卻是最難跨出的一步。
因此在本篇文章中,我們先將以簡單的方法來介紹並結合筆者們常用的思考方式來幫助初學者,以期能夠縮短學習的曲線,至於更詳細的內容我們將在往後文章中來作闡述。
筆者們常用的方法中,就如『Applying UML And Patterns』一書中所提的需求分析與物件導向分析與設計的方法中一般,大約可分為四個步驟:
定義使用案例-描述詳細的需求的情境(Use Case)。
定義領域模型-將現實世界的物體抽象或一般化,並找出屬性及關聯。
定義互動圖-將物件與物件之間的訊息傳遞的行為找出來(Sequence Diagram)。
定義設計類別圖-找出物件內的屬性及方法(Class Diagram)。
不過上述的步驟方法大都是已經有該專案的Know how且有OOAD的經驗者之思考及實作的方法,因為他們已經可以憑著經驗,而能夠很直覺得定義出需求中所需的物件、屬性及方法,更進一步的能夠分析出物件與物件之間的關係,不過,筆者整理出下列的方法,可以協助初學者較容易找出上述幾個步驟中可以產出的一些分析文件及圖形:
a、 由需求中找出類別
從每個需求敘述中找出『名詞』來,每個名詞都是類別的候選者,再篩選出該類別可能含有行為及屬性,若該名詞不具備行為(方法)及屬性,則可能是某類別的屬性之一,此方法可對應著上述的『定義領域模型』的步驟。
b、 找出類別的方法
找出需求敘述中的動詞(is、was、have),這將會是方法的候選者,且透過需求敘述你可以再將這些動詞與上一步驟所找出的名詞結合,繪製出所謂的『互動圖』及『類別圖』。
c、 找出類別的屬性
類別候選者所消除的名詞可能就是某些類別的屬性,這也是『定義領域模型』的一種另類思考的方法。
d、 驗證你的需求
重新驗證需求中的每個敘述,並檢討可能遺漏的必要功能。
結論
關於需求轉為物件導向系統分析的方法諸多繁瑣,而且真的需要經驗的累積,筆者所闡述的是盡量讓初學者得到一些啟發,至於對錯可能都會因人而異,且這個主題充滿了很多的哲理,要描述這些哲理不是一篇短文能夠涵蓋的,因此筆者先以這篇文章作個開場白,因為或多或少在未來的文章裡,大都會提到與本文相關的一些議題,因為這篇文章是物件導向設計與分析的核心,所以,一些關鍵的議題將會在未來為各位說明,敬請期待囉~
2009年4月14日 星期二
物件導向程式設計
物件導向程式設計(Object Orientated Paradigm,OOP)是Java的核心。
實際上,所有Java程式皆是物件導向:跟C++不一樣…
運用物件式的語言(如C++)並無法保證你用物件化的方式來設計:
尤其 C++ 也保留了對 C 語言的支援,所以拿 C++ 來寫 C 也可以,故初學者容易混用。以程序式的方法寫程式時,自以為是以物件導向的方法來寫程式。
那什麼是以物件導向的方法來寫程式呢?以下是紫色幻想喵 大大的例子
物件導向呀…
就像是…
今天如果你想要開車車
那麼,你只要把"開車"這兩個字寫出來,裡面就包括了…
踩油門、開車門、踩殺車、方向燈等等,車子就會跑了~~~~
但如果是非物件導向的話(也就是我說的程序式寫法,也就是C語言寫法)。
你就要重頭寫…
我看到一台車
我開車門
我坐上去
我踩油門…等
一步一步寫~
so~物件導向就像套裝的東西
你要去旅行,買個旅行組就好了,不用牙刷、毛巾…一個個去買(一個個去買是C語言寫法)。
雖然會比較方便,但…
不見得裡面的東西對你而言都是實用的…
也許旅行組裡面有個淋浴乳,但你從來都是用肥皂洗澡,所以…這個你就用不到啦~
實際上,所有Java程式皆是物件導向:跟C++不一樣…
運用物件式的語言(如C++)並無法保證你用物件化的方式來設計:
尤其 C++ 也保留了對 C 語言的支援,所以拿 C++ 來寫 C 也可以,故初學者容易混用。以程序式的方法寫程式時,自以為是以物件導向的方法來寫程式。
那什麼是以物件導向的方法來寫程式呢?以下是紫色幻想喵 大大的例子
物件導向呀…
就像是…
今天如果你想要開車車
那麼,你只要把"開車"這兩個字寫出來,裡面就包括了…
踩油門、開車門、踩殺車、方向燈等等,車子就會跑了~~~~
但如果是非物件導向的話(也就是我說的程序式寫法,也就是C語言寫法)。
你就要重頭寫…
我看到一台車
我開車門
我坐上去
我踩油門…等
一步一步寫~
so~物件導向就像套裝的東西
你要去旅行,買個旅行組就好了,不用牙刷、毛巾…一個個去買(一個個去買是C語言寫法)。
雖然會比較方便,但…
不見得裡面的東西對你而言都是實用的…
也許旅行組裡面有個淋浴乳,但你從來都是用肥皂洗澡,所以…這個你就用不到啦~
物件導向程式設計與程序導向程式設計之差異與比較
物件導向程式設計OOP (Object-Oriented Programming) 是一種近幾年來程式設計的新觀念,它將程式語言要處理的對象看成是一種物件,傳統程式設計以程序導向 (procedure-oriented) 為主,程式的動作過程就好像是電腦執行程式的流程一樣,但是這樣卻和實際上要解決的問題無法緊密結合。
物件導向的程式設計方法,是站在較人性化的觀點來思考、設計程式的邏輯,例如在傳統的程式設計語言中,我們要開啟一個資料庫檔案,通常是撰寫如下列的程式呼叫:『開啟檔案(資料庫)』,而在物件導向語言當中,則是執行下列的程式呼叫:『資料庫.開啟檔案』。
這只是物件導向的一種特性,此外,它還擴充了一般程式語言的功能,例如在C++ 語言當中,我們可定義許多相同名稱的副程式,它們各自執行不同的功能,而不會互相衝突──因為它們是針對不同的物件運作的,這是物件導向當中的『多形』(polymorphism),其它重要的概念還有『封裝』 (encapsulation) 與『繼承』(inheritance),使得程式撰寫可更容易模組化 (modular),也更易於重複使用 (reuse) 軟體元件。一般說來,SmallTalk與Simula兩種程式語言是OOP的始祖,C++、Java、Javascript、Flash Action Script與C# 則是近來OOP的主流。
在現實面上,程序導向和物件導向算是比較一般化的,其中程序導向語言製作的軟體仍然佔有最大的應用市場,也許程序式的運作模型最能被大家接受,最容易隨性地發揮,與現今 von Neuman 架構機器最能夠匹配,也許物件導向的方法太過嚴謹、太過抽象,在這種狀況下真的很難去說服同學說其它沒有被市場廣泛接受的軟體方法中擁有無限的希望,用心、下些苦工去了解他們是不會讓你後悔的;想說得嚴重一點,沒有了解各種軟體方法的話,也許資訊系就白走一遭了,可是也深深地知道市場早已證明,許多的從業人員不需要知道軟體製作的各種奧祕,只要精通程序式/結構化的軟體方法,在工商業界中已經可以無往不利了,真的看不出 von Neuman 型態的計算機模型會很快地消失,會有所謂物件化的硬體模型嗎? 所以真的也不預期程序式的程式製作方法會像史前的恐龍一樣受迫消失。
那麼物件式模組化、與應用領域緊密結合、由下而上 (bottom up) 的軟體製作方法是不是就永遠限於大規模、大成本、複雜、專業的軟體呢? 這些方法會的人少,資源也少,就好像叫好不叫座的電影一樣,讓所有的影評不知道該執著於理想拼命鼓吹呢? 還是順應大眾的口味,大加討伐一番。
上程式設計課程時常常提醒大家用的是 C 語言而不是 C++,就是不喜歡讓同學在使用支援物件導向的語言 (例如 C++) 以程序式的方法製作軟體時,自以為是製作物件式的軟體,運用物件式的語言並無法保證你用物件化的方式來設計、規劃及製作軟體, (另一方面,運用不支援物件導向的語言寫的軟體仍然可以基於物件導向的方法來設計,只是程式設計者所要遵循的規則無法由編譯器來幫你檢查,而必須由程式設計者自己來實現,) 學習物件導向的軟體設計方法可以讓大家領略軟體製作時工程式的嚴謹過程,了解軟體中物件系統紮實可重用的根基。
使用 VB 設計視窗環境應用程式的軟體工作者很明顯地比使用 C++/MFC 來設計視窗環境應用程式的工程師多太多了,由表象上來分析,使用者多的軟體發展環境資源多、可以諮詢的人也多,要完成計劃的阻礙比較低,當然吸引更多的人來投入。很沮喪地說,我幾乎找不到用 VB 寫不出來的視窗應用程式, (講這句話時有一點像是說沒有用 Assembly 寫不出來的程式一樣),如果為了安慰自己而說某些系統的應用為了配合作業系統還是需要用 C/C++ 的話,那微軟還有 COM/ActiveX 的技術可以讓 VB 的應用程式設計者輕鬆地運用 C/C++ 程式設計者的產品,那為什麼要 C++/MFC??? 不會說是寫系統核心才用得到吧,那你我什麼時候才寫得到系統核心呢?
由設計軟體的方法來比較, VB 是架構在 Basic 這種型態並非非常嚴謹的程序式語言上,先天上就有容易學習的優點,製作時不需要做嚴謹的分析設計圖,撰寫程式碼時不需嚴謹地訂定界面,維護封裝,入門的門檻明顯地比 C++/物件導向的程式製作方法要低得多。由另一個角度來看,大多數人在使用 VB 來設計應用系統時應該都是由界面物件開始設計,也就是應用 VB 表單編輯器來設計人與機器間的界面,然後再應用事件驅動的視窗程式運作模型逐一填入各個界面所引發的程式動作,這是非常功能性的 top-down 程式設計, (因為用到了許多界面物件,又用到了事件驅動的概念,所以許多人覺得 VB 也是物件導向了,這是很大的誤會,大多數程式設計師在設計 VB 的程式時可能對 "快速地完成設計" 要比 "完整的分析目標系統的運作與組成" 要注重得多,物件系統中抽象化的功能物件恐怕更不是考慮的重點,沒有這些基本考量的程式決不會是物件導向的,物件導向的四大特性甚至都還沒有包含 "事件驅動" 呢。) VB 程式的設計方法可以說是由外而內的, (在設計使用者界面的雛型時相信是一個很有用的工具),反觀使用 C++/MFC 來設計物件式系統時,通常不會由使用者界面著手,一般是由應用領域中系統運作來開始分析,所分析設計出來的物件不見得是人機界面的物件,而是運作系統中的物件,例如在進出貨管理系統中,實體貨物都有其相對應的軟體物件,儲存/載運/處理實體貨物的機制中,所有的資料、人員也都是系統中的物件,實體機制中所有的動作都在軟體系統中模擬為物件的互動,這些物件構成了軟體系統的核心機制,其中軟體物件和人員之間的界面也就是人機的界面,通常會抽離出來由使用者的角度進一步地設計合理美觀的互動機制,這種設計方式比較是由內而外的,通常可以先使核心軟體模型完全地符合應用環境來運作,然後再替這個系統架構人機間的視窗圖形化界面。
物件導向的程式設計方法,是站在較人性化的觀點來思考、設計程式的邏輯,例如在傳統的程式設計語言中,我們要開啟一個資料庫檔案,通常是撰寫如下列的程式呼叫:『開啟檔案(資料庫)』,而在物件導向語言當中,則是執行下列的程式呼叫:『資料庫.開啟檔案』。
這只是物件導向的一種特性,此外,它還擴充了一般程式語言的功能,例如在C++ 語言當中,我們可定義許多相同名稱的副程式,它們各自執行不同的功能,而不會互相衝突──因為它們是針對不同的物件運作的,這是物件導向當中的『多形』(polymorphism),其它重要的概念還有『封裝』 (encapsulation) 與『繼承』(inheritance),使得程式撰寫可更容易模組化 (modular),也更易於重複使用 (reuse) 軟體元件。一般說來,SmallTalk與Simula兩種程式語言是OOP的始祖,C++、Java、Javascript、Flash Action Script與C# 則是近來OOP的主流。
在現實面上,程序導向和物件導向算是比較一般化的,其中程序導向語言製作的軟體仍然佔有最大的應用市場,也許程序式的運作模型最能被大家接受,最容易隨性地發揮,與現今 von Neuman 架構機器最能夠匹配,也許物件導向的方法太過嚴謹、太過抽象,在這種狀況下真的很難去說服同學說其它沒有被市場廣泛接受的軟體方法中擁有無限的希望,用心、下些苦工去了解他們是不會讓你後悔的;想說得嚴重一點,沒有了解各種軟體方法的話,也許資訊系就白走一遭了,可是也深深地知道市場早已證明,許多的從業人員不需要知道軟體製作的各種奧祕,只要精通程序式/結構化的軟體方法,在工商業界中已經可以無往不利了,真的看不出 von Neuman 型態的計算機模型會很快地消失,會有所謂物件化的硬體模型嗎? 所以真的也不預期程序式的程式製作方法會像史前的恐龍一樣受迫消失。
那麼物件式模組化、與應用領域緊密結合、由下而上 (bottom up) 的軟體製作方法是不是就永遠限於大規模、大成本、複雜、專業的軟體呢? 這些方法會的人少,資源也少,就好像叫好不叫座的電影一樣,讓所有的影評不知道該執著於理想拼命鼓吹呢? 還是順應大眾的口味,大加討伐一番。
上程式設計課程時常常提醒大家用的是 C 語言而不是 C++,就是不喜歡讓同學在使用支援物件導向的語言 (例如 C++) 以程序式的方法製作軟體時,自以為是製作物件式的軟體,運用物件式的語言並無法保證你用物件化的方式來設計、規劃及製作軟體, (另一方面,運用不支援物件導向的語言寫的軟體仍然可以基於物件導向的方法來設計,只是程式設計者所要遵循的規則無法由編譯器來幫你檢查,而必須由程式設計者自己來實現,) 學習物件導向的軟體設計方法可以讓大家領略軟體製作時工程式的嚴謹過程,了解軟體中物件系統紮實可重用的根基。
使用 VB 設計視窗環境應用程式的軟體工作者很明顯地比使用 C++/MFC 來設計視窗環境應用程式的工程師多太多了,由表象上來分析,使用者多的軟體發展環境資源多、可以諮詢的人也多,要完成計劃的阻礙比較低,當然吸引更多的人來投入。很沮喪地說,我幾乎找不到用 VB 寫不出來的視窗應用程式, (講這句話時有一點像是說沒有用 Assembly 寫不出來的程式一樣),如果為了安慰自己而說某些系統的應用為了配合作業系統還是需要用 C/C++ 的話,那微軟還有 COM/ActiveX 的技術可以讓 VB 的應用程式設計者輕鬆地運用 C/C++ 程式設計者的產品,那為什麼要 C++/MFC??? 不會說是寫系統核心才用得到吧,那你我什麼時候才寫得到系統核心呢?
由設計軟體的方法來比較, VB 是架構在 Basic 這種型態並非非常嚴謹的程序式語言上,先天上就有容易學習的優點,製作時不需要做嚴謹的分析設計圖,撰寫程式碼時不需嚴謹地訂定界面,維護封裝,入門的門檻明顯地比 C++/物件導向的程式製作方法要低得多。由另一個角度來看,大多數人在使用 VB 來設計應用系統時應該都是由界面物件開始設計,也就是應用 VB 表單編輯器來設計人與機器間的界面,然後再應用事件驅動的視窗程式運作模型逐一填入各個界面所引發的程式動作,這是非常功能性的 top-down 程式設計, (因為用到了許多界面物件,又用到了事件驅動的概念,所以許多人覺得 VB 也是物件導向了,這是很大的誤會,大多數程式設計師在設計 VB 的程式時可能對 "快速地完成設計" 要比 "完整的分析目標系統的運作與組成" 要注重得多,物件系統中抽象化的功能物件恐怕更不是考慮的重點,沒有這些基本考量的程式決不會是物件導向的,物件導向的四大特性甚至都還沒有包含 "事件驅動" 呢。) VB 程式的設計方法可以說是由外而內的, (在設計使用者界面的雛型時相信是一個很有用的工具),反觀使用 C++/MFC 來設計物件式系統時,通常不會由使用者界面著手,一般是由應用領域中系統運作來開始分析,所分析設計出來的物件不見得是人機界面的物件,而是運作系統中的物件,例如在進出貨管理系統中,實體貨物都有其相對應的軟體物件,儲存/載運/處理實體貨物的機制中,所有的資料、人員也都是系統中的物件,實體機制中所有的動作都在軟體系統中模擬為物件的互動,這些物件構成了軟體系統的核心機制,其中軟體物件和人員之間的界面也就是人機的界面,通常會抽離出來由使用者的角度進一步地設計合理美觀的互動機制,這種設計方式比較是由內而外的,通常可以先使核心軟體模型完全地符合應用環境來運作,然後再替這個系統架構人機間的視窗圖形化界面。
訂閱:
文章 (Atom)