物件導向程式編程的定義是使用「物件」來做設計,但並非所有的程式語言都直接支援「物件導向程式編程」相關技術與結構。对于OOP的准确定义及其本意存在着不少争论。通常,OOP被理解为一种将程序分解为封装数据及相关操作的模块而进行的编程方式。有别于其它编程方式,OOP中的与某数据类型相关的一系列操作都被有机地封装到该数据类型当中,而非散放于其外,因而OOP中的数据类型不仅有着状态,还有着相关的行为。
面向对象的构建要素由三个部分组成,实例、类和元数据,元数据会存储构建所需要的一切信息。从关系上看,类与实例为一对多关系,类和元数据为一对一关系,实例会指向类,类会指向元数据,这种关系最终构成了所有面向对象的基类(object)。
OOP理论,及与之同名的OOP实践相结合创造出了新的一个编程架构;OOP思想被广泛认为是非常有用的,以致一套新的编程范型被创造了出来。(其它的编程范型例如函数式编程或过程式编程专注于程序运行的过程,而逻辑编程专注于引发程序代码执行的断言)。对面向模拟系统的语言(如:SIMULA 67)的研究及对高可靠性系统架构(如:高性能操作系统和CPU的架构)的研究最终导致了OOP的诞生。其中由Deborah J. Armstrong进行的长达40年之久的计算机著作调查中,显示出了一系列面向对象程序设计的基本理论。物件導向程式特徵被條列如下[3][4][5][6]
分享非物件導向程式前身語言
编辑
物件導向程式設計通常共享高階編程語言的低階功能。可用於建構一個程序的基本工具包括:
變數:能儲存一些內建型態的資訊如整數與字元,也有些是資料結構像是字串、串列與雜湊表等包含內建或複合的變數如指標。
程序:也稱為函式、方法或例程,是指輸入資料產生輸出結果,現代語言還包含結構化編程結構如程式迴圈與條件。
類與对象
编辑
支持面向对象編程語言通常利用繼承其他類達到代碼重用和可擴展性的特性。而類有兩個主要的概念:
類(Class):定義了一件事物的抽象特點。類的定義包含了數據的形式以及對數據的操作。
对象(Object):是類的實例(Instance)。
其中类(Class)定义了一件事物的抽象特点。类的定义包含了数据的形式以及对数据的操作。举例来说,“犬”这个类会包含犬的一切基础特征,即所有“犬”都共有的特征或行为,例如它的品种、毛皮颜色和吠叫的能力。类可以为程序提供模版和结构。一个类的方法和属性被称为“成员”。
我们来看一段伪代码:
类犬
开始
公有成员:
吠():
毛色:
私有成员:
品种:
结束
在这串代码中,我们声明了一个类,这个类具有一些犬的基本特征。关于公有成员和私有成员,请参见下面的继承性的内容。
对象(Object)是类的实例。物件有時會對應到現實世界中的事物,舉例來說,一個圖形程式可能有圓形、矩形與畫面等物件,一個線上購物系統可能有購物車、顧客與產品等類別[7]。有時对象會表示更抽象的實體,比如一個被開啟的檔案或是一個提供美國慣用量測轉換的服務。每個对象就是一個特定類別的實例(例如,名稱是“李华”的物件可能是類別雇員的一個實例)。程序在面向对象編程當中被視為方法,變數被視為成員或屬性。例如,“犬”这个类列举犬的特点,从而使这个类定义了世界上所有的犬。而大黄这个对象则是一条具体的犬,它的属性也是具体的。犬有毛色,而大黄的毛色是黄色的。因此,大黄就是犬这个类的一个实例。一个具体对象属性的值被称作它的“状态”。(系统给对象分配内存空间,而不会给类分配内存空间。这很好理解,类是抽象的,系统不可能给抽象的东西分配空间,而对象则是具体的。)
假设我们已经在上面定义了犬这个类,我们就可以用这个类来定义对象:
定义大黄是犬
大黄.毛色 : 黄
大黄.吠()
我们无法让犬这个类去吠,但是我们可以让对象“大黄”去吠,正如狗可以吠,但没有具体的狗就无法吠。
类和对象就好比是“实型”和“1.23”,“实型”是一种数据的类型,而“1.23”是一个真正的“实数”(即对象)。所有的“实数”都具有“实型”所描诉的特征,如“实数的大小”,系统则分配内存给“实数”存储具体的数值。
動態配置與訊息傳遞機制
编辑
定義上動態配置是指方法會隨著實例動態的改變。而訊息傳遞機制(Message Passing)是指一個物件通過接受訊息、處理訊息、傳出訊息或使用其他類別的方法來實作一定功能。如:大黄可以通过吠引起人的注意,从而导致一系列的事发生。
封裝性
编辑
具備封裝性(Encapsulation)的物件導向程式設計隱藏了某一方法的具體執行步驟,取而代之的是通過訊息傳遞機制傳送訊息給它。封裝是通過限制只有特定類別的物件可以存取這一特定類別的成員,而它們通常利用介面實作訊息的傳入傳出。举个例子,接口能确保幼犬这一特征只能被赋予犬这一类。通常來說,成員會依它們的存取權限被分為3種:公有成員、私有成員以及保護成員。有些語言更進一步:Java可以限制同一包內不同類別的存取;C#和VB.NET保留了為類別的成員聚集準備的關鍵字:internal(C#)和Friend(VB.NET);Eiffel語言則可以讓使用者指定哪個類別可以存取所有成員。
因此,举例来说,“犬”这个类有“吠()”的方法,这一方法定义了犬具体该通过什么方法吠。但是,大黄的朋友并不知道它到底是如何吠的。
从实例来看:
/* 一个面向过程的程序会这样写: */
定义大黄
大黄.定音(442)
大黄.吸气()
大黄.吐气()
/* 而当狗的吠叫被封装到类中,任何人都可以简单地使用: */
定义大黄是犬
大黄.吠()
继承
编辑
继承性(Inheritance)是指,在某种情况下,一个类会有“子类”。子类比原本的类(称为父类)要更加具体化。例如,“犬”这个类可能会有它的子类“中华田园犬”和“牧羊犬”。在这种情况下,“大黄”可能就是中华田园犬的一个实例。子类会继承父类的属性(英语:Attribute (computing))和行为,并且也可包含它们自己的。我们假设“犬”这个类有一个方法(行为)叫做“吠()”和一个属性叫做“毛色”。它的子类(前例中的中华田园犬和牧羊犬)会继承这些成员。这意味着程序员只需要将相同的代码写一次。
在伪代码中我们可以这样写:
类 中华田园犬 : 继承 犬
开始
# 中华田园犬继承了犬类的所有方法
结束
# 创建对象
定义 大黄 是 中华田园犬
# 调用方法
大黄.吠()
/*
注释:注意这里调用的是犬类的吠()方法。
*/
回到前面的例子,“中华田园犬”这个类可以继承“毛色”这个属性,并指定其为黄色。而“牧羊犬”则可以继承“吠()”这个方法,并指定它的音调。子类也可以加入新的成员,例如,“牧羊犬”这个类可以加入一个方法叫做“放牧()”。设若用“中华田园犬”这个类定义了一个实例“大黄”,那么大黄就不会放牧,因为这个方法是属于牧羊犬的,而非中华田园犬。事实上,我们可以把继承理解为“是”或“属于”。大黄“是”中华田园犬,中华田园犬“属于”犬类。因此,大黄既得到了中华田园犬的属性,又继承了犬的属性。
我们来看伪代码:
类 牧羊犬 : 继承 犬
开始
公有成员:
放牧()
结束
类 中华田园犬 : 继承 犬
开始
# 中华田园犬类中没有放牧()方法
结束
# 创建对象
定义 大黄 是 中华田园犬
# 调用方法
大黄.放牧()
/*
注释:错误:放牧()是牧羊犬的成员方法,中华田园犬没有这个方法。
*/
当一个类从多个父类继承时,我们称之为“多重继承”。如一只狗既是中华田园犬又是牧羊犬。多重继承并不总是被支持的,因为它很难理解,又很难被好好使用。
多型
编辑
多型(Polymorphism)是指由继承而产生的相关的不同的类,其对象对同一消息会做出不同的响应[8]。例如,狗和鸡都有“叫()”这一方法,但是调用狗的“叫()”,狗会吠叫;调用鸡的“叫()”,鸡则会啼叫。
我们将它体现在伪代码上:
类 犬
开始
公有成员:
叫()
开始
吠()
结束
结束
类 鸡
开始
公有成员:
叫()
开始
啼()
结束
结束
# 创建对象
定义 大黄 是 犬
定义 红帽 是 鸡
# 调用方法
大黄.叫()
红帽.叫()
这样,虽然同样是做出叫这一种行为,但大黄和红帽具体做出的表现方式将大不相同。多态性的概念可以用在运算符重载上,可以根据需求查看相关界面。
抽象性
编辑
抽象(Abstraction)是简化复杂的现实问题的途径,它可以为具体问题找到最恰当的类定义,并且可以在最恰当的继承级别解释问题。举例说明,大黄在大多数时候都被当作一条狗,但是如果想要让它做中华田园犬做的事,你完全可以调用中华田园犬的方法。如果狗这个类还有动物的父类,那么你完全可以视大黄为动物。