面向对象程序设计

物件導向程式設計（，缩写：）是種具有物件概念的程式設計典範，同时也是一种程式开发的抽象方针。它可能包含資料、特性、程式碼與方法。对象則指的是類別（class）的实例。它将对象作为程序的基本单元，将程序和数据封装其中，以提高软件的重用性、灵活性和扩展性，物件裡的程序可以訪問及經常修改物件相關連的資料。在物件導向程式編程裡，電腦程式會被設計成彼此相關的物件, section 1.6 "Object-Oriented Programming"。

面向对象程序设计可以看作一种在程序中包含各种独立而又互相调用的对象的思想，这与传统的思想刚好相反：传统的程序设计主张将程序看作一系列函数的集合，或者直接就是一系列对电脑下达的指令。面向对象程序设计中的每一个对象都应该能够接受数据、处理数据并将数据传达给其它对象，因此它们都可以被看作一个小型的“机器”，即对象。目前已经被证实的是，面向对象程序设计推广了程序的灵活性和可维护性，并且在大型项目设计中广为应用。此外，支持者声称面向对象程序设计要比以往的做法更加便于学习，因为它能够让人们更简单地设计并维护程序，使得程序更加便于分析、设计、理解。反对者在某些领域对此予以否认。

当我们提到面向对象的时候，它不仅指一种程序设计方法。它更多意义上是一种程序开发方式。在这一方面，我们必须了解更多关于面向对象系统分析和面向对象设计（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年之久的计算机著作调查中，显示出了一系列面向对象程序设计的基本理论。物件導向程式特徵被條列如下Deborah J. Armstrong. The Quarks of Object-Oriented Development. A survey of nearly 40 years of computing literature which identified a number of fundamental concepts found in the large majority of definitions of OOP, in descending order of popularity: Inheritance, Object, Class, Encapsulation, Method, Message Passing, Polymorphism, and Abstraction.John C. Mitchell, Concepts in programming languages, Cambridge University Press, 2003, ISBN 0-521-78098-5, p.278.  Lists: Dynamic dispatch, abstraction, subtype polymorphism, and inheritance.Michael Lee Scott, Programming language pragmatics, Edition 2, Morgan Kaufmann, 2006, ISBN 0-12-633951-1, p. 470.  Lists encapsulation, inheritance, and dynamic dispatch., section 18.1 "What is Object-Oriented Programming?"  Lists: Dynamic dispatch, encapsulation or multi-methods (multiple dispatch), subtype polymorphism, inheritance or delegation, open recursion ("this"/"self")

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

物件導向程式設計通常共享高階編程語言的低階功能。可用於建構一個程序的基本工具包括：
 變數：能儲存一些內建型態的資訊如整數與字元，也有些是資料結構像是字串、串列與雜湊表等包含內建或複合的變數如指標。
程序：也稱為函式、方法或例程，是指輸入資料產生輸出結果，現代語言還包含結構化編程結構如程式迴圈與條件。

類與对象
支持面向对象編程語言通常利用繼承其他類達到代碼重用和可擴展性的特性。而類有兩個主要的概念：

 類（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）是指由继承而产生的相关的不同的类，其对象对同一消息会做出不同的响应谭浩强：《C++面向对象程序设计》，清华大学出版社，2006年1月第一版。ISBN 978-7-302-12315-6。例如，狗和鸡都有“叫()”这一方法，但是调用狗的“叫()”，狗会吠叫；调用鸡的“叫()”，鸡则会啼叫。
我们将它体现在伪代码上：

 -{}-
 类 犬
 开始
     公有成员:
         叫()
         开始
             吠()
         结束
 结束

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

 # 创建对象
 定义 大黄 是 犬
 定义 红帽 是 鸡

 # 调用方法
 大黄.叫()
 红帽.叫()

这样，虽然同样是做出叫这一种行为，但大黄和红帽具体做出的表现方式将大不相同。多态性的概念可以用在运算符重载上，可以根据需求查看相关界面。

 抽象性 
抽象（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

 參考文獻 

延伸閱讀

外部連結

Introduction to Object Oriented Programming Concepts (OOP) and More  by L.W.C. Nirosh
Discussion about the flaws of OOD 
OOP Concepts (Java Tutorials) 

Category:编程范式

Category:软件开发
Category:軟體工程