物件導向程式設計(英語:Object-oriented programming,縮寫:OOP)是種具有物件概念的程式設計典範,同時也是一種程式開發的抽象方針。它可能包含資料、特性、程式碼與方法。物件則指的是類別(class)的實例。它將物件作為程式的基本單元,將程式和資料封裝其中,以提高軟體的重用性、靈活性和擴充性,物件裡的程式可以訪問及經常修改物件相關連的資料。在物件導向程式程式設計裡,電腦程式會被設計成彼此相關的物件[1][2]。
「物件導向程式設計」的各地常用名稱 | |
---|---|
中國大陸 | 面向對象程序設計 |
臺灣 | 物件導向程式設計 |
港澳 | 物件導向程式設計 |
物件導向程式設計可以看作一種在程式中包含各種獨立而又互相呼叫的物件的思想,這與傳統的思想剛好相反:傳統的程式設計主張將程式看作一系列函式的集合,或者直接就是一系列對電腦下達的指令。物件導向程式設計中的每一個物件都應該能夠接受資料、處理資料並將資料傳達給其它物件,因此它們都可以被看作一個小型的「機器」,即物件。目前已經被證實的是,物件導向程式設計推廣了程式的靈活性和可維護性,並且在大型專案設計中廣為應用。此外,支持者聲稱物件導向程式設計要比以往的做法更加便於學習,因為它能夠讓人們更簡單地設計並維護程式,使得程式更加便於分析、設計、理解。反對者在某些領域對此予以否認。
當我們提到物件導向的時候,它不僅指一種程式設計方法。它更多意義上是一種程式開發方式。在這一方面,我們必須了解更多關於物件導向系統分析和物件導向設計(Object Oriented Design,簡稱OOD)方面的知識。許多流行的程式語言是物件導向的,它們的風格就是會透由物件來創出實例。
重要的物件導向程式語言包含Common Lisp、Python、C++、Objective-C、Smalltalk、Delphi、Java、Swift、C#、Perl、Ruby、JavaScript 與 PHP等。
特徵
物件導向程式程式設計的定義是使用「物件」來做設計,但並非所有的程式語言都直接支援「物件導向程式程式設計」相關技術與結構。對於OOP的準確定義及其本意存在著不少爭論。通常,OOP被理解為一種將程式分解為封裝資料及相關操作的模組而進行的程式設計方式。有別於其它程式設計方式,OOP中的與某資料類型相關的一系列操作都被有機地封裝到該資料類型當中,而非散放於其外,因而OOP中的資料類型不僅有著狀態,還有著相關的行為。
物件導向的構建要素由三個部分組成,實例、類別和元資料,元資料會儲存構建所需要的一切資訊。從關係上看,類別與實例為一對多關係,類別和元資料為一對一關係,實例會指向類別,類別會指向元資料,這種關係最終構成了所有物件導向的基礎類別(object)。
OOP理論,及與之同名的OOP實踐相結合創造出了新的一個程式設計架構;OOP思想被廣泛認為是非常有用的,以致一套新的程式設計範式被創造了出來。(其它的程式設計範式例如函數式程式設計或程序式程式設計專注於程式執行的過程,而邏輯程式設計專注於引發程式碼執行的斷言)。對面向類比系統的語言(如:SIMULA 67)的研究及對高可靠性系統架構(如:高效能作業系統和CPU的架構)的研究最終導致了OOP的誕生。其中由Deborah J. Armstrong進行的長達40年之久的電腦著作調查中,顯示出了一系列物件導向程式設計的基本理論。物件導向程式特徵被條列如下[3][4][5][6]
物件導向程式設計通常共享高階程式語言的低階功能。可用於建構一個程式的基本工具包括:
支援物件導向程式語言通常利用繼承其他類達到代碼重用和可延伸性的特性。而類有兩個主要的概念:
其中類別(Class)定義了一件事物的抽象特點。類別的定義包含了資料的形式以及對資料的操作。舉例來說,「犬」這個類別會包含犬的一切基礎特徵,即所有「犬」都共有的特徵或行為,例如它的品種、毛皮顏色和吠叫的能力。類別可以為程式提供模版和結構。一個類別的方法和屬性被稱為「成員」。 我們來看一段虛擬碼:
類別犬 開始 公有成員: 吠(): 毛色: 私有成員: 品種: 結束
在這串代碼中,我們聲明了一個類別,這個類別具有一些犬的基本特徵。關於公有成員和私有成員,請參見下面的繼承性的內容。
物件(Object)是類別的實例。物件有時會對應到現實世界中的事物,舉例來說,一個圖形程式可能有圓形、矩形與畫面等物件,一個線上購物系統可能有購物車、顧客與產品等類別。[7]。有時物件會表示更抽象的實體,比如一個被開啟的檔案或是一個提供美國慣用量測轉換的服務。每個物件就是一個特定類別的實例(例如,名稱是「李華」的物件可能是類別雇員的一個實例)。程式在物件導向程式設計當中被視為方法,變數被視為成員或屬性。例如,「犬」這個類別列舉犬的特點,從而使這個類別定義了世界上所有的犬。而大黃這個物件則是一條具體的犬,它的屬性也是具體的。犬有毛色,而大黃的毛色是黃色的。因此,大黃就是犬這個類別的一個實例。一個具體物件屬性的值被稱作它的「狀態」。(系統給物件分配主記憶體空間,而不會給類別分配主記憶體空間。這很好理解,類別是抽象的,系統不可能給抽象的東西分配空間,而物件則是具體的。)
假設我們已經在上面定義了犬這個類別,我們就可以用這個類別來定義物件:
定義大黃是犬 大黃.毛色 : 黃 大黃.吠()
我們無法讓犬這個類別去吠,但是我們可以讓物件「大黃」去吠,正如狗可以吠,但沒有具體的狗就無法吠。
類別和物件就好比是「實型」和「1.23」,「實型」是一種資料的類別型,而「1.23」是一個真正的「實數」(即物件)。所有的「實數」都具有「實型」所描訴的特徵,如「實數的大小」,系統則分配主記憶體給「實數」儲存具體的數值。
定義上動態組態是指方法會隨著實例動態的改變。而訊息傳遞機制(Message Passing)是指一個物件通過接受訊息、處理訊息、傳出訊息或使用其他類別的方法來實作一定功能。如:大黃可以通過吠引起人的注意,從而導致一系列的事發生。
具備封裝性(Encapsulation)的物件導向程式設計隱藏了某一方法的具體執行步驟,取而代之的是通過訊息傳遞機制傳送訊息給它。封裝是通過限制只有特定類別的物件可以存取這一特定類別的成員,而它們通常利用介面實作訊息的傳入傳出。舉個例子,介面能確保幼犬這一特徵只能被賦予犬這一類別。通常來說,成員會依它們的存取權限被分為3種:公有成員、私有成員以及保護成員。有些語言更進一步:Java可以限制同一包內不同類別的存取;C#和VB.NET保留了為類別的成員聚集準備的關鍵字:internal(C#)和Friend(VB.NET);Eiffel語言則可以讓使用者指定哪個類別可以存取所有成員。
因此,舉例來說,「犬」這個類別有「吠()」的方法,這一方法定義了犬具體該通過什麼方法吠。但是,大黃的朋友並不知道它到底是如何吠的。
從實例來看:
/* 一個程序導向的程式會這樣寫: */ 定義大黃 大黃.定音(442) 大黃.吸氣() 大黃.吐氣() /* 而當狗的吠叫被封裝到類別中,任何人都可以簡單地使用: */ 定義大黃是犬 大黃.吠()
繼承性(Inheritance)是指,在某種情況下,一個類別會有「子類別」。子類別比原本的類別(稱為父類別)要更加具體化。例如,「犬」這個類別可能會有它的子類別「中華田園犬」和「牧羊犬」。在這種情況下,「大黃」可能就是中華田園犬的一個實例。子類別會繼承父類別的屬性和行為,並且也可包含它們自己的。我們假設「犬」這個類別有一個方法(行為)叫做「吠()」和一個屬性叫做「毛色」。它的子類別(前例中的中華田園犬和牧羊犬)會繼承這些成員。這意味著程式設計師只需要將相同的代碼寫一次。
在虛擬碼中我們可以這樣寫:
類別 中華田園犬 : 繼承 犬 開始 # 中華田園犬繼承了犬類別的所有方法 結束 # 建立物件 定義 大黃 是 中華田園犬 # 呼叫方法 大黃.吠() /* 注釋:注意這裡呼叫的是犬類別的吠()方法。 */
回到前面的例子,「中華田園犬」這個類別可以繼承「毛色」這個屬性,並指定其為黃色。而「牧羊犬」則可以繼承「吠()」這個方法,並指定它的音調。子類別也可以加入新的成員,例如,「牧羊犬」這個類別可以加入一個方法叫做「放牧()」。設若用「中華田園犬」這個類別定義了一個實例「大黃」,那麼大黃就不會放牧,因為這個方法是屬於牧羊犬的,而非中華田園犬。事實上,我們可以把繼承理解為「是」或「屬於」。大黃「是」中華田園犬,中華田園犬「屬於」犬類別。因此,大黃既得到了中華田園犬的屬性,又繼承了犬的屬性。 我們來看虛擬碼:
類別 牧羊犬 : 繼承 犬 開始 公有成員: 放牧() 結束 類別 中華田園犬 : 繼承 犬 開始 # 中華田園犬類別中沒有放牧()方法 結束 # 建立物件 定義 大黃 是 中華田園犬 # 呼叫方法 大黃.放牧() /* 注釋:錯誤:放牧()是牧羊犬的成員方法,中華田園犬沒有這個方法。 */
當一個類別從多個父類別繼承時,我們稱之為「多重繼承」。如一隻狗既是中華田園犬又是牧羊犬。多重繼承並不總是被支援的,因為它很難理解,又很難被好好使用。
多型(Polymorphism)是指由繼承而產生的相關的不同的類別,其物件對同一訊息會做出不同的回應[8]。例如,狗和雞都有「叫()」這一方法,但是呼叫狗的「叫()」,狗會吠叫;呼叫雞的「叫()」,雞則會啼叫。 我們將它體現在虛擬碼上:
類別 犬 開始 公有成員: 叫() 開始 吠() 結束 結束 類別 雞 開始 公有成員: 叫() 開始 啼() 結束 結束 # 建立物件 定義 大黃 是 犬 定義 紅帽 是 雞 # 呼叫方法 大黃.叫() 紅帽.叫()
這樣,雖然同樣是做出叫這一種行為,但大黃和紅帽具體做出的表現方式將大不相同。多型性的概念可以用在運算子多載上,可以根據需求檢視相關介面。
抽象(Abstraction)是簡化複雜的現實問題的途徑,它可以為具體問題找到最恰當的類別定義,並且可以在最恰當的繼承級別解釋問題。舉例說明,大黃在大多數時候都被當作一條狗,但是如果想要讓它做中華田園犬做的事,你完全可以呼叫中華田園犬的方法。如果狗這個類別還有動物的父類別,那麼你完全可以視大黃為動物。
歷史
物件導向程式設計的雛形,早在1960年代的Simula語言中即可發現,當時的程式設計領域正面臨著一種危機:在軟硬體環境逐漸複雜的情況下,軟體如何得到良好的維護?物件導向程式設計在某種程度上通過強調可重複性解決了這一問題。20世紀70年代的Smalltalk語言在物件導向方面堪稱經典——以至於30年後的今天依然將這一語言視為物件導向語言的基礎。
電腦科學中物件和實例概念的最早萌芽可以追溯到麻省理工學院的PDP-1系統。這一系統大概是最早的基於容量架構(capability based architecture)的實際系統。另外1963年Ivan Sutherland的Sketchpad應用中也蘊含了同樣的思想。物件作為程式設計實體最早是於1960年代由Simula 67語言引入思維。Simula這一語言是奧利-約翰·達爾和克利斯登·奈加特在奧斯陸的挪威計算中心為類比環境而設計的。(據說,他們是為了類比船隻而設計的這種語言,並且對不同船隻間屬性的相互影響感興趣。他們將不同的船隻歸納為不同的類別,而每一個物件,基於它的類別,可以定義它自己的屬性和行為。)這種辦法是分析式程式的最早概念體現。在分析式程式中,我們將真實世界的物件對映到抽象的物件,這叫做「類比」。Simula不僅引入了「類別」的概念,還應用了實例這一思想——這可能是這些概念的最早應用。
20世紀70年代全錄PARC研究所發明的Smalltalk語言將物件導向程式設計的概念定義為,在基礎運算中,對物件和訊息的廣泛應用。Smalltalk的建立者深受Simula 67的主要思想影響,但Smalltalk中的物件是完全動態的——它們可以被建立、修改並銷毀,這與Simula中的靜態物件有所區別。此外,Smalltalk還引入了繼承性的思想,它因此一舉超越了不可建立實例的程式設計模型和不具備繼承性的Simula。此外,Simula 67的思想亦被應用在許多不同的語言,如Lisp、Pascal。
物件導向程式設計在80年代成為了一種主導思想,這主要應歸功於C++——C語言的擴充版。在圖形化使用者介面(GUI)日漸崛起的情況下,物件導向程式設計很好地適應了潮流。GUI和物件導向程式設計的緊密關聯在Mac OS X中可見一斑。Mac OS X是由Objective-C語言寫成的,這一語言是一個仿Smalltalk的C語言擴充版。物件導向程式設計的思想也使事件處理式的程式設計更加廣泛被應用(雖然這一概念並非僅存在於物件導向程式設計)。一種說法是,GUI的引入極大地推動了物件導向程式設計的發展。
蘇黎世聯邦理工學院的尼克勞斯·維爾特和他的同事們對抽象資料和模組化程式設計進行了研究。Modula-2將這些都包括了進去,而Oberon則包括了一種特殊的物件導向方法——不同於Smalltalk與C++。
物件導向的特性也被加入了當時較為流行的語言:Ada、BASIC、Lisp、Fortran、Pascal以及種種。由於這些語言最初並沒有物件導向的設計,故而這種糅合常常會導致相容性和維護性的問題。與之相反的是,「純正的」物件導向語言卻缺乏一些程式設計師們賴以生存的特性。在這一大環境下,開發新的語言成為了當務之急。作為先行者,Eiffel成功地解決了這些問題,並成為了當時較受歡迎的語言。
在過去的幾年中,Java語言成為了廣為應用的語言,除了它與C和C++語法上的近似性。Java的可移植性是它的成功中不可磨滅的一步,因為這一特性,已吸引了龐大的程式設計師群的投入。
在最近的電腦語言發展中,一些既支援物件導向程式設計,又支援程序導向程式設計的語言悄然浮出水面。它們中的佼佼者有Python、Ruby等等。
正如程序導向程式設計使得結構化程式設計的技術得以提升,現代的物件導向程式設計方法使得對設計模式的用途、契約式設計和建模語言(如UML)技術也得到了一定提升。
物件導向程式語言
支援部分或絕大部分物件導向特性的語言即可稱為基於物件的或物件導向的語言。Simula (1967)被視為第一個具有物件導向特性的語言。早期,完全物件導向的語言主要包括Smalltalk等語言,目前較為流行的語言中有Java、C#、Eiffel等。隨著軟體工業的發展,比較早的程序導向的語言在近些年的發展中也紛紛吸收了許多物件導向的概念,比如C→C++,C→Objective-C,BASIC→Visual Basic→Visual Basic .NET,Pascal→Object Pascal,Ada→Ada95。「純粹」的物件導向語言, 因為所有的東西都是由物件所組成,例如:Eiffel, Emerald,[9] JADE, Obix, Ruby, Scala, Smalltalk, Self.
近年來,物件導向的程式設計越來越流行於手稿語言中。Python和Ruby是建立在OOP原理的指令碼語言,Perl和PHP亦分別在Perl 5和PHP 4時加入物件導向特性。
參見
- 一次且僅一次(once and only once,OAOO)
- Distributed Component Object Model
- UML
參考文獻
延伸閱讀
外部連結
Wikiwand in your browser!
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.