面向对象的程序设计方法

**物件導向程式設計**（英語：Object-oriented programming，縮寫：OOP）是種具有物件概念的程式設計典範，同時也是一種程式開發的抽象方針。它可能包含資料、特性、程式碼與方法。物件則指的是類別（class）的實例。它將物件作為程式的基本單元，將程式和資料封裝其中，以提高軟體的重用性、靈活性和擴充性，物件裡的程式可以存取及經常修改物件相關連的資料。在物件導向程式程式設計裡，電腦程式會被設計成彼此相關的物件。

物件導向程式設計可以看作一種在程式中包含各種獨立而又互相呼叫的物件的思想，這與傳統的思想剛好相反：傳統的程式設計主張將程式看作一系列函式的集合，或者直接就是一系列對電腦下達的指令。物件導向程式設計中的每一個物件都應該能夠接受資料、處理資料並將資料傳達給其它物件，因此它們都可以被看作一個小型的「機器」，即物件。目前已經被證實的是，物件導向程式設計推廣了程式的靈活性和可維護性，並且在大型專案設計中廣為應用。此外，支持者聲稱物件導向程式設計要比以往的做法更加便於學習，因為它能夠讓人們更簡單地設計並維護程式，使得程式更加便於分析、設計、理解。反對者在某些領域對此予以否認。

當我們提到物件導向的時候，它不僅指一種程式設計方法。它更多意義上是一種程式開發方式。在這一方面，我們必須了解更多關於物件導向系統分析和物件導向設計（Object Oriented Design，簡稱 OOD）方面的知識。許多流行的程式語言是物件導向的，它們的風格就是會透由物件來創出實例。

重要的物件導向程式語言包含 Common Lisp、Python、C++、Objective-C、Smalltalk、Delphi、Java、Swift、C#、Perl、Ruby、JavaScript 與 PHP 等。

## 特徵

物件導向程式程式設計的定義是使用「物件」來做設計，但並非所有的程式語言都直接支援「物件導向程式程式設計」相關技術與結構。對於 OOP 的準確定義及其本意存在著不少爭論。通常，OOP 被理解為一種將程式分解為封裝資料及相關操作的模組而進行的程式設計方式。有別於其它程式設計方式，OOP 中的與某資料類型相關的一系列操作都被有機地封裝到該資料類型當中，而非散放於其外，因而 OOP 中的資料類型不僅有著狀態，還有著相關的行為。

OOP 理論，及與之同名的 OOP 實踐相結合創造出了新的一個程式設計架構；OOP 思想被廣泛認為是非常有用的，以致一套新的程式設計範式被創造了出來。（其它的程式設計範式例如函式語言程式設計或程序式程式設計專注於程式執行的過程，而邏輯程式設計專注於引發程式碼執行的斷言）。對面向類比系統的語言（如：SIMULA 67）的研究及對高可靠性系統架構（如：高效能作業系統和 CPU 的架構）的研究最終導致了 OOP 的誕生。其中由 Deborah J. Armstrong 進行的長達 40 年之久的電腦著作調查中，顯示出了一系列物件導向程式設計的基本理論。物件導向程式特徵被條列如下

### 分享非物件導向程式前身語言

物件導向程式設計通常共享高階程式語言的低階功能。可用於建構一個程式的基本工具包括：

* 變數：能儲存一些內建型態的資訊如整數與字元，也有些是資料結構像是字串、串列與雜湊表等包含內建或複合的變數如指標。
* 程式：也稱為函式、方法或常式，是指輸入資料產生輸出結果，現代語言還包含結構化程式設計結構如程式迴圈與條件。

### 類與物件

支援物件導向程式語言通常利用繼承其他類達到代碼重用和可擴展性的特性。而類有兩個主要的概念：

* 類（Class）：定義了一件事物的抽象特點。類的定義包含了數據的形式以及對數據的操作。
* 物件（Object）：是類的實例（Instance）。

其中類別（Class）定義了一件事物的抽象特點。類別的定義包含了資料的形式以及對資料的操作。舉例來說，「犬」這個類別會包含犬的一切基礎特徵，即所有「犬」都共有的特徵或行為，例如它的品種、毛皮顏色和吠叫的能力。類別可以為程式提供模版和結構。一個類別的方法和屬性被稱為「成員」。
我們來看一段虛擬碼：

```
類別**犬**
開始
　　公有成員:
　　　　吠():
　　私有成員:
　　　　毛色:
　　　　品種:
結束
```

在這串代碼中，我們聲明了一個類別，這個類別具有一些犬的基本特徵。關於公有成員和私有成員，請參見下面的繼承性的內容。

物件（Object）是類別的實例。物件有時會對應到現實世界中的事物，舉例來說，一個圖形程式可能有圓形、矩形與畫面等物件，一個線上購物系統可能有購物車、顧客與產品等類別。。有時物件會表示更抽象的實體，比如一個被開啟的檔案或是一個提供美國慣用量測轉換的服務。每個物件就是一個特定類別的實例（例如，名稱是「李華」的物件可能是類別雇員的一個實例）。程式在物件導向程式設計當中被視為方法，變數被視為成員或屬性。例如，「犬」這個類別列舉犬的特點，從而使這個類別定義了世界上所有的犬。而大黃這個物件則是一條具體的犬，它的屬性也是具體的。犬有毛色，而大黃的毛色是黃色的。因此，大黃就是犬這個類別的一個實例。一個具體物件屬性的值被稱作它的「狀態」。（系統給物件分配記憶體空間，而不會給類別分配記憶體空間。這很好理解，類別是抽象的，系統不可能給抽象的東西分配空間，而物件則是具體的。）

假設我們已經在上面定義了犬這個類別，我們就可以用這個類別來定義物件：

```
定義**大黃**是**犬**
大黃.毛色 : 黃
大黃.吠()
```

我們無法讓犬這個類別去吠，但是我們可以讓物件「大黃」去吠，正如狗可以吠，但沒有具體的狗就無法吠。

類別和物件就好比是「實型」和「1.23」，「實型」是一種資料的類別型，而「1.23」是一個真正的「實數」（即物件）。所有的「實數」都具有「實型」所描訴的特徵，如「實數的大小」，系統則分配記憶體給「實數」儲存具體的數值。

### 動態組態與訊息傳遞機制

定義上動態組態是指方法會隨著實例動態的改變。而訊息傳遞機制（Message Passing）是指一個物件通過接受訊息、處理訊息、傳出訊息或使用其他類別的方法來實作一定功能。如：**大黃**可以通過**吠**引起**人**的注意，從而導致一系列的事發生。

### 封裝性

具備封裝性（Encapsulation）的物件導向程式設計隱藏了某一方法的具體執行步驟，取而代之的是通過訊息傳遞機制傳送訊息給它。封裝是通過限制只有特定類別的物件可以存取這一特定類別的成員，而它們通常利用介面實作訊息的傳入傳出。舉個例子，介面能確保幼犬這一特徵只能被賦予犬這一類別。通常來說，成員會依它們的存取權限被分為 3 種：公有成員、私有成員以及保護成員。有些語言更進一步：Java 可以限制同一包內不同類別的存取；C# 和 VB.NET 保留了為類別的成員聚集準備的關鍵字：internal（C#）和 Friend（VB.NET）；Eiffel 語言則可以讓使用者指定哪個類別可以存取所有成員。

因此，舉例來說，「犬」這個類別有「吠 ()」的方法，這一方法定義了犬具體該通過什麼方法吠。但是，大黃的朋友並不知道它到底是如何吠的。

從實例來看：

```
/* 一個程序導向的程式會這樣寫： */
定義**大黃**
大黃.定音(442)
大黃.吸氣()
大黃.吐氣()

/* 而當狗的吠叫被封裝到類別中，任何人都可以簡單地使用： */
定義**大黃**是**犬**
大黃.吠()
```

### 繼承

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

在虛擬碼中我們可以這樣寫：

```
類別**中華田園犬** : 繼承**犬**

定義**大黃**是**中華田園犬**
大黃.吠()    /* 注釋：注意這裡呼叫的是狗這個類別的吠叫方法。*/
```

回到前面的例子，「中華田園犬」這個類別可以繼承「毛色」這個屬性，並指定其為黃色。而「牧羊犬」則可以繼承「吠 ()」這個方法，並指定它的音調。子類別也可以加入新的成員，例如，「牧羊犬」這個類別可以加入一個方法叫做「放牧 ()」。設若用「中華田園犬」這個類別定義了一個實例「大黃」，那麼大黃就不會放牧，因為這個方法是屬於牧羊犬的，而非中華田園犬。事實上，我們可以把繼承理解為「是」或「屬於」。大黃「是」中華田園犬，中華田園犬「屬於」犬類別。因此，大黃既得到了中華田園犬的屬性，又繼承了犬的屬性。
我們來看虛擬碼：

```
類別**牧羊犬** : 繼承**犬**
開始
　　公有成員:
　　　　放牧()
結束
類別**中華田園犬** : 繼承**犬**

定義**大黃**是**中華田園犬**
大黃.放牧()    /* 注釋：錯誤：放牧是牧羊犬的成員方法。 */
```

當一個類別從多個父類別繼承時，我們稱之為「多重繼承」。如一隻狗既是中華田園犬又是牧羊犬。多重繼承並不總是被支援的，因為它很難理解，又很難被好好使用。

### 多型

多型（Polymorphism）是指由繼承而產生的相關的不同的類別，其物件對同一訊息會做出不同的回應。例如，狗和雞都有「叫 ()」這一方法，但是呼叫狗的「叫 ()」，狗會吠叫；呼叫雞的「叫 ()」，雞則會啼叫。
我們將它體現在虛擬碼上：

```
類別**犬**
開始
　　公有成員:
　　　　叫()
　　　　開始
　　　　　　吠()
　　　　結束
結束

類別**雞**
開始
　　公有成員:
　　　　叫()
　　　　開始
　　　　　　啼()
　　　　結束
結束

定義**大黃**是**狗**
定義**紅帽**是**雞**
大黃.叫()
紅帽.叫()
```

這樣，雖然同樣是做出**叫**這一種行為，但大黃和紅帽具體做出的表現方式將大不相同。多型性的概念可以用在運算子多載上，可以根據需求檢視相關介面。

### 抽象性

抽象（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, JADE, Obix, Ruby, Scala, Smalltalk, Self.

### 指令碼中的 OOP

近年來，物件導向的程式設計越來越流行於手稿語言中。Python 和 Ruby 是建立在 OOP 原理的指令碼語言，Perl 和 PHP 亦分別在 Perl 5 和 PHP 4 時加入物件導向特性。

## 參見

* 一次且僅一次（once and only once，OAOO）
* Distributed Component Object Model
* UML

## 參考文獻

## 延伸閱讀

* Abadi, Martin; Luca Cardelli. A Theory of Objects. Springer Verlag. 1998. ISBN 0-387-94775-2.
* Abelson, Harold; Gerald Jay Sussman. Structure and Interpretation of Computer Programs. MIT Press. 1997 [2016-03-06]. ISBN0-262-01153-0. （原始內容存檔於 2017-12-26）.
* Armstrong, Deborah J. The Quarks of Object-Oriented Development. Communications of the ACM. February 2006, **49** (2): 123–128 [8 August 2006]. ISSN 0001-0782. doi:10.1145/1113034.1113040. （原始內容存檔於 2020-01-22）.
* Booch, Grady. Object-Oriented Analysis and Design with Applications. Addison-Wesley. 1997. ISBN 0-8053-5340-2.
* Eeles, Peter; Oliver Sims. Building Business Objects. John Wiley & Sons. 1998. ISBN 0-471-19176-0.
* Gamma, Erich; Richard Helm, Ralph Johnson, John Vlissides. Design Patterns: Elements of Reusable Object Oriented Software. Addison-Wesley. 1995. ISBN 0-201-63361-2.
* Harmon, Paul; William Morrissey. The Object Technology Casebook - Lessons from Award-Winning Business Applications. John Wiley & Sons. 1996. ISBN 0-471-14717-6.
* Jacobson, Ivar. Object-Oriented Software Engineering: A Use Case-Driven Approach. Addison-Wesley. 1992. ISBN 0-201-54435-0.
* Kay, Alan. The Early History of Smalltalk. [2016-03-06]. （原始內容存檔於 2005-04-04）.
* Meyer, Bertrand. Object-Oriented Software Construction. Prentice Hall. 1997. ISBN 0-13-629155-4.
* Pecinovsky, Rudolf. OOP - Learn Object Oriented Thinking & Programming. Bruckner Publishing. 2013 [2016-03-06]. ISBN978-80-904661-8-0. （原始內容存檔於 2021-05-14）.
* Rumbaugh, James; Michael Blaha; William Premerlani; Frederick Eddy; William Lorensen. Object-Oriented Modeling and Design. Prentice Hall. 1991. ISBN 0-13-629841-9.
* Schach, Stephen. Object-Oriented and Classical Software Engineering, Seventh Edition. McGraw-Hill. 2006. ISBN 0-07-319126-4.
* Schreiner, Axel-Tobias. Object oriented programming with ANSI-C. Hanser. 1993. ISBN 3-446-17426-5. hdl:1850/8544.
* Taylor, David A. Object-Oriented Information Systems - Planning and Implementation. John Wiley & Sons. 1992. ISBN 0-471-54364-0.
* Weisfeld, Matt. The Object-Oriented Thought Process, Third Edition. Addison-Wesley. 2009. ISBN 0-672-33016-4.
* West, David. Object Thinking (Developer Reference). Microsoft Press. 2004. ISBN 0735619654.

## 外部連結

* 開放式目錄計劃中和 Object-oriented programming 相關的內容
* Introduction to Object Oriented Programming Concepts (OOP) and More （頁面存檔備份，存於網際網路檔案館） by L.W.C. Nirosh
* Discussion about the flaws of OOD （頁面存檔備份，存於網際網路檔案館）
* OOP Concepts (Java Tutorials) （頁面存檔備份，存於網際網路檔案館）