物件導向程序設計


物件導向程序設計 (简体)

Free Web Hosting with Website Builder

物件導向程式設計英語Object-oriented programming,縮寫:OOP),指一種程式設計范型,同時也是一種程式開發的方法論。它將物件作為程式的基本單元,將程式和數據封裝其中,以提高軟體的重用性、靈活性和擴展性。[1]

當我們提到物件導向的時候,它不僅指一種程式設計方法。它更多意義上是一種程式開發方式。在這一方面,我們必須了解更多關於物件導向系統分析和物件導向設計(Object Oriented Design,簡稱OOD)方面的知識。

目錄

概述

物件導向程式設計的雛形,早在1960年的Simula語言中即可發現,當時的程式設計領域正面臨著一種危機:在軟硬體環境逐漸複雜的情況下,軟體如何得到良好的維護?物件導向程式設計在某種程度上通過強調可重複性解決了這一問題。20世紀70年代的SmallTalk語言在物件導向方面堪稱經典——以至於30年後的今天依然將這一語言視為物件導向語言的基礎。

物件導向程式設計可以被視作一種在程式中包含各種獨立而又互相調用的單位和物件的思想,這與傳統的思想剛好相反:傳統的物件導向程式設計主張將程式看作一系列函數的集合,或者直接就是一系列對電腦下達的指令。物件導向程式設計中的每一個物件都應該能夠接受數據、處理數據並將數據傳達給其它物件,因此它們都可以被看作一個小型的「機器」,或者說是負有責任的角色。

目前已經被證實的是,物件導向程式設計推廣了程式的靈活性和可維護性,並且在大型項目設計中廣為應用。 此外,支持者聲稱物件導向程式設計要比以往的做法更加便於學習,因為它能夠讓人們更簡單地設計並維護程式,使得程式更加便於分析、設計、理解。反對者在某些領域對此予以否認。.

基本理論

一項由 Deborah J. Armstrong 進行的長達40年之久的計算機著作調查顯示出了一系列物件導向程式設計的基本理論。它們是:

類別

類別(Class)定義了一件事物的抽象特點。通常來說,類別定義了事物的屬性和它可以做到的(它的行為)。舉例來說,「」這個類別會包含狗的一切基礎特徵,例如它的孕育、毛皮顏色和吠叫的能力。類別可以為程式提供模版和結構。一個類別的方法和屬性被稱為「成員」。 我們來看一段虛擬碼


开始
    私有成员:
        孕育
         毛皮颜色
    公有成员:
        吠叫()
结束

在這串代碼中,我們定義了一個類別,這個類別具有一些狗的基本特徵。關於公有成員和私有成員,請參見下面的繼承性一節。

物件

物件(Object)是類別的實例。例如,「」這個類別列舉狗的特點,從而使這個類別定義了世界上所有的狗。而萊絲這個物件則是一條具體的狗,它的屬性也是具體的。狗有皮毛顏色,而萊絲的皮毛顏色是棕白色的。因此,萊絲就是狗這個類別的一個實例。一個具體物件屬性的值被稱作它的「狀態」。(系統給物件分配內存空間,而不會給類別分配內存空間,這很好理解,類別是抽象的系統不可能給抽象的東西分配空間,物件是具體的)

假設我們已經在上面定義了狗這個類別,我們就可以用這個類別來定義物件:

定义莱丝
莱丝.毛皮颜色:=棕白色
莱丝.吠叫()

我們無法讓狗這個類別去吠叫,但是我們可以讓物件「萊絲」去吠叫,正如狗可以吠叫,但沒有具體的狗就無法吠叫。

方法

方法(Method)是一個類別能做的事情,但方法並沒有去做這件事。作為一條狗,萊絲是會吠叫的,因此「吠叫()」就是它的一個方法。與此同時,它可能還會有其它方法,例如「坐下()」,或者「吃()」。 對一個具體物件的方法進行調用並不影響其它物件,正如所有的狗都會叫,但是你讓一條狗叫不代表所有的狗都叫。 如下例:

定义莱丝
定义泰尔
莱丝.吠叫()

則泰爾是不會吠叫的,因為這裡的吠叫只是對物件「萊絲」進行的。

消息傳遞機制

一個物件通過接受消息、處理消息、傳出消息或使用其他類別的方法來實現一定功能,這叫做消息傳遞機制(Message Passing)。

繼承性

繼承性(Inheritance)是指,在某種情況下,一個類別會有「子類別」。子類別比原本的類別(稱為父類別)要更加具體化,例如,「」這個類別可能會有它的子類別「牧羊犬」和「吉娃娃犬」。在這種情況下,「萊絲」可能就是牧羊犬的一個實例。子類別會繼承父類別的屬性和行為,並且也可包含它們自己的。我們假設「狗」這個類別有一個方法叫做「吠叫()」和一個屬性叫做「毛皮顏色」。它的子類別(前例中的牧羊犬和吉娃娃犬)會繼承這些成員。這意味著程式設計師只需要將相同的代碼寫一次。 在虛擬碼中我們可以這樣寫:

牧羊犬:继承

定义莱丝牧羊犬
莱丝.吠叫()    /* 注意这里调用的是狗这个类的吠叫属性。 */

回到前面的例子,「牧羊犬」這個類別可以繼承「毛皮顏色」這個屬性,並指定其為棕白色。而「吉娃娃犬」則可以繼承「吠叫()」這個方法,並指定它的音調高於平常。子類別也可以加入新的成員,例如,「吉娃娃犬」這個類別可以加入一個方法叫做「顫抖()」。設若用「牧羊犬」這個類別定義了一個實例「萊絲」,那麼萊絲就不會顫抖,因為這個方法是屬於吉娃娃犬的,而非牧羊犬。事實上,我們可以把繼承理解為「是」。例如,萊絲「是」牧羊犬,牧羊犬「是」狗。因此,萊絲既繼承了牧羊犬的屬性,又繼承了狗的屬性。 我們來看虛擬碼:

吉娃娃犬:继承
开始
   公有成员:
      颤抖()
结束
类牧羊犬:继承

定义莱丝牧羊犬
莱丝.颤抖()    /* 错误:颤抖是吉娃娃犬的成员方法。 */

當一個類別從多個父類別繼承時,我們稱之為「多重繼承」。多重繼承並不總是被支持的,因為它很難理解,又很難被好好使用。

封裝性

具備封裝性(Encapsulation)的物件導向程式設計隱藏了某一方法的具體執行步驟,取而代之的是通過消息傳遞機制傳送消息給它。因此,舉例來說,「狗」這個類別有「吠叫()」的方法,這一方法定義了狗具體該通過什麼方法吠叫。但是,萊絲的朋友蒂米並不需要知道它到底如何吠叫。 從實例來看:

/* 一个面向过程的程序会这样写: */
定义莱丝
莱丝.设置音调(5)
莱丝.吸气()
莱丝.吐气()

/* 而当狗的吠叫被封装到类中,任何人都可以简单地使用: */
定义莱丝
莱丝.吠叫()

封裝是通過限制只有特定類別的實例可以訪問這一特定類別的成員,而它們通常利用介面實現消息的傳入傳出。舉個例子,介面能確保幼犬這一特徵只能被賦予狗這一類別。通常來說,成員會依它們的訪問許可權被分為3種:公有成員、私有成員以及保護成員。有些語言更進一步:Java可以限制同一包內不同類別的訪問;C#VB.NET保留了為類別的成員聚集準備的關鍵字:internal(C#)和Friend(VB.NET);Eiffel語言則可以讓用戶指定哪個類別可以訪問所有成員。

多型性

多型性(Polymorphism)指方法在不同的類別中調用可以實現的不同結果。因此,2個甚至更多的類別可以對同一消息作出不同的反應。舉例來說,狗和雞都有「叫()」這一方法,但是調用狗的「叫()」,狗會吠叫;調用雞的「叫()」,雞則會啼叫。 我們將它體現在虛擬碼上:


开始
   公有成员:
       叫()
       开始
          吠叫()
       结束
结束

类
开始
   公有成员:
       叫()
       开始
          啼叫()
       结束
结束

定义莱丝
定义鲁斯特
莱丝.叫()
鲁斯特.叫()

這樣,同樣是叫,萊絲和魯斯特做出的反應將大不相同。多型性的概念可以用在運算符重載上,本文不再贅述。

抽象性

抽象(Abstraction)是簡化複雜的現實問題的途徑,它可以為具體問題找到最恰當的類別定義,並且可以在最恰當的繼承級別解釋問題。舉例說明,萊絲在大多數時候都被當作一條狗,但是如果想要讓它做牧羊犬做的事,你完全可以調用牧羊犬的方法。如果狗這個類別還有動物的父類別,那麼你完全可以視萊絲為一個動物。

OOP名詞釋意

編程範型 對於OOP的準確定義及其本意存在著不少爭論。

通常,OOP被理解為一種將程式分解為封裝數據及相關操作的模塊而進行的編程方式。有別于其它編程方式,OOP中的與某數據類別型相關的一系列操作都被有機地封裝到該數據類別型當中,而非散放于其外,因而OOP中的數據類別型不僅有著狀態,還有著相關的行為。OOP理論,及與之同名的OOP實踐相結合創造出了新的一個編程架構;OOP思想被廣泛認為是非常有用的,以致一套新的編程範型被創造了出來。(其它的編程範型例如函數式編程或過程式編程專註于程式運行的過程,而邏輯編程專註于引發程式代碼執行的斷言)

對面向模擬系統的語言(如:SIMULA 67)的研究及對高可靠性系統架構(如:高性能作業系統和CPU的架構)的研究最終導致了OOP的誕生。

一些專家認為Object-Orientation中的Object的本意來自於其在語法領域的意義,即應將其理解為「賓語」或「操作物件」,而非一般的「物件」或「物件」。我們所見到的軟體的運行請求通常都是Subject-Oriented的,即「面向主語的」或「面向操作者的」,然而這樣將使得對操作者物件的設計變得困難而複雜。有鑒於此,部分研究人員開始了對「面向操作物件」的思考。這又一次產生了新的編程範型,這是前邊提到的「面向操作者」的思考模式的一項革新。

依照「面向操作物件」的原則,在程式語句中的動詞應該被劃分到操作物件的類別型之中,而與該動詞請求相關的邏輯關係也就因此將在操作物件中處理。以下是採用「面向操作物件」的方式翻譯「面向操作者」的一些例子:

  • 面向操作者:銷售系統保存交易記錄。
  • 面向操作物件:交易記錄在接受到銷售系統的一條請求消息後將自身保存。
  • 面向操作者:銷售系統列印收據。
  • 面向操作物件:收據在接收到銷售系統的一條請求消息後將自身列印。

物件導向的語言

支持部分或絕大部分物件導向特性的語言即可稱為基於物件的或物件導向的語言。

早期,完全物件導向的語言主要包括Smalltalk等語言,目前較為流行的語言中有JavaC#、Eiffel等。隨著軟體工業的發展,比較早的程式導向的語言在近些年的發展中也紛紛吸收了許多物件導向的概念,比如C->C++BASIC->Visual Basic->Visual Basic .NETPascal->Object PascalAda->Ada95。

歷史

物件和實例的最早概念出自麻省理工大學的PDP-1系統。這一系統大概是capability based architecture的最早示例67中被引入程式設計中。Simula這一語言是Ole-Johan Dahl和Kristen Nygaard在奧斯陸計算機中心為模擬環境而設計的。(據說,他們是為了模擬船隻而設計的這種語言,並且對不同船隻間屬性的相互影響感興趣。他們將不同的船隻歸納為不同的類別,而每一個物件,基於它的類別,可以定義它自己的屬性和行為。)這種辦法是分析式程式的最早概念體現。在分析式程式中,我們將真實世界的物件映射到抽象的物件,這叫做「模擬」。Simula不僅引入了「類別」的概念,還應用了實例這一思想——這可能是這些概念的最早應用。

20世紀70年代施樂PARC研究所發明的Smalltalk語言將物件導向程式設計的概念定義為,在基礎運算中,對物件消息的廣泛應用。Smalltalk的創建者深受Simula 67的主要思想影響,但Smalltalk中的物件是完全動態的——它們可以被創建、修改並銷毀,這與Simula中的靜態物件有所區別。此外,Smalltalk還引入了繼承性的思想,它因此一舉超越了不可創建實例的程式設計模型和不具備繼承性的Simula。

此外,Simula 67的思想亦被應用在許多不同的語言,如LispPascal

物件導向程式設計在80年代成為了一種主導思想,這主要應歸功於C++——C語言的擴充版。在圖形用戶界面(GUI)日漸崛起的情況下,物件導向程式設計很好地適應了潮流。GUI和物件導向程式設計的緊密關聯在Mac OS X中可見一斑。Mac OS X是由物件導向C語言寫成的,這一語言是一個仿Smalltalk的C語言擴充版。物件導向程式設計的思想也使事件處理式的程式設計更加廣泛被應用(雖然這一概念並非僅存在於物件導向程式設計)。一種說法是,GUI的引入極大地推動了物件導向程式設計的發展。

ETH Zürich(英文),Niklaus Wirth 和他的同事們對抽象數據和模塊化程式設計進行了調查。Modula-2將這些都包括了進去,而Oberon則包括了一種特殊的物件導向方法——不同於SmalltalkC++

物件導向的特性也被加入了當時較為流行的語言:AdaBASICLispFortranPascal以及種種。由於這些語言最初並沒有物件導向的設計,故而這種糅合常常會導致兼容性和維護性的問題。與之相反的是,「純正的」物件導向語言卻缺乏一些程式設計師們賴以生存的特性。在這一大環境下,開發新的語言成為了當務之急。作為先行者,Eiffel成功地解決了這些問題,並成為了當時較受歡迎的語言。

在過去的幾年中,Java語言成為了廣為應用的語言,除了它與CC++語法上的近似性。Java的可移植性是它的成功中不可磨滅的一步,因為這一特性,已吸引了龐大的程式設計師群的投入。

近日,一些既支持物件導向程式設計,又支持物件導向程式設計的語言悄然浮出水面。它們中的佼佼者有PythonRuby等等.

正如物件導向程式設計使得結構化程式設計的技術得以提升,現代的物件導向程式設計方法使得對設計模式的用途、契約式設計和建模語言(如UML)技術也得到了一定提升。

腳本中的OOP

近年來,物件導向程式設計越發流行於腳本語言PythonRuby是建立在OOP原理的腳本語言,PerlPHP亦分別在Perl 5和PHP 4時加入物件導向特性。

參考文獻

  1. ^ 《Object Oriented Programming》[1],中科永聯高級技術培訓中心。

相關內容

外部連結







Why are we here?
All text is available under the terms of the GNU Free Documentation License
This page is cache of Wikipedia. History