面向对象编程(ObjectOrientedProgramming,OOP,面向对象程序设计)是一种计算机编程架构。OOP的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成。OOP达到了软件工程的三个主要目标:重用性、灵活性和扩展性。为了实现整体运算,每个对象都能够接收信息、处理数据和向其它对象发送信息。OOP主要有以下的概念和组件:
组件
数据和功能一起在运行着的计算机程序中形成的单元,组件在OOP计算机程序中是模块和结构化的基础。
抽象性
程序有能力忽略正在处理中信息的某些方面,即对信息主要方面关注的能力。
封装
也叫做信息封装:确保组件不会以不可预期的方式改变其它组件的内部状态;只有在那些提供了内部状态改变方法的组件中,才可以访问其内部状态。每类组件都提供了一个与其它组件联系的接口,并规定了其它组件进行调用的方法。
多态性
组件的引用和类集会涉及到其它许多不同类型的组件,而且引用组件所产生的结果得依据实际调用的类型。
继承性
允许在现存的组件基础上创建子类组件,这统一并增强了多态性和封装性。典型地来说就是用类来对组件进行分组,而且还可以定义新类为现存的类的扩展,这样就可以将类组织成树形或网状结构,这体现了动作的通用性。
由于抽象性、封装性、重用性以及便于使用等方面的原因,以组件为基础的编程在脚本语言中已经变得特别流行。Python和Ruby是最近才出现的语言,在开发时完全采用了OOP的思想,而流行的Perl脚本语言从版本5开始也慢慢地加入了新的面向对象的功能组件。用组件代替“现实”上的实体成为JavaScript(ECMAScript)得以流行的原因,有论证表明对组件进行适当的组合就可以在英特网上代替HTML和XML的文档对象模型(DOM)。
oop的基本思想
OOP的许多原始思想都来之于Simula语言,并在Smalltalk语言的完善和标准化过程中得到更多的扩展和对以前的思想的重新注解。可以说OO思想和OOPL几乎是同步发展相互促进的。
与函数式程序设计(functional-programming)和逻辑式程序设计(logic-programming)所代表的接近于机器的实际计算模型所不同的是,OOP几乎没有引入精确的数学描叙,而是倾向于建立一个对象模型,它能够近似的反映应用领域内的实体之间的关系,其本质是更接近于一种人类认知事物所采用的哲学观的计算模型。由此,导致了一个自然的话题,那就是OOP到底是什么?[D&T1988][B.S1991].。
在OOP中,对象作为计算主体,拥有自己的名称,状态以及接受外界消息的接口。在对象模型中,产生新对象,旧对象销毁,发送消息,响应消息就构成OOP计算模型的根本。
对象的产生有两种基本方式。
一种是以原型(prototype)对象为基础产生新的对象。
一种是以类(class)为基础产生新对象。
原型的概念已经在认知心理学中被用来解释概念学习的递增特性,原型模型本身就是企图通过提供一个有代表性的对象为基础来产生各种新的对象,并由此继续产生更符合实际应用的对象。而原型-委托也是OOP中的对象抽象,代码共享机制中的一种。一个类提供了一个或者多个对象的通用性描叙。
从形式化的观点看,类与类型有关,因此一个类相当于是从该类中产生的实例的集合。而这样的观点也会带来一些矛盾,比较典型的就是在继承体系下,子集(子类)对象和父集(父类)对象之间的行为相融性可能很难达到,这也就是OOP中常被引用的---子类型(subtype)不等于子类(subclass)[Budd2002]。而在一种所有皆对象的世界观背景下,在类模型基础上还诞生出了一种拥有元类(metaclass)的新对象模型。即类本身也是一种其他类的对象。
以上三种根本不同的观点各自定义了三种基于类(class-based),基于原型(prototype-based)和基于元类(metaclass-based)的对象模型。而这三种对象模型也就导致了许多不同的程序设计语言(如果我们暂时把静态与动态的差别放在一边)。是的,我们经常接触的C++,Java都是使用基于类的对象模型,但除此之外还有很多我们所没有接触的OOPL采用了完全不一样的对象模型,他们是在用另外一种观点诠释OOP的内涵。
什么是oop的基本思想呢?
把组件的实现和接口分开,并且让组件具有多态性。不过,两者还是有根本的不同。oop强调在程序构造中语言要素的语法。你必须得继承,使用类,使用对象,对象传递消息。gp不关心你继承或是不继承,它的开端是分析产品的分类,有些什么种类,他们的行为如何。
就是说,两件东西相等意味着什么?怎样正确地定义相等操作?不单单是相等操作那么简单,你往深处分析就会发现“相等”这个一般观念意味着两个对象部分,或者至少基本部分是相等的,据此我们就可以有一个通用的相等操作。
再说对象的种类
假设存在一个顺序序列和一组对于顺序序列的操作。那么这些操作的语义是什么?从复杂度权衡的角度看,我们应该向用户提供什么样的顺序序列?该种序列上存在那些操作?那种排序是我们需要的?只有对这些组件的概念型分类搞清楚了,我们才能提到实现的问题:使用模板、继承还是宏?使用什么语言和技术?gp的基本观点是把抽象的软件组件和它们的行为用标准的分类学分类,出发点就是要建造真实的、高效的和不取决于语言的算法和数据结构。
当然最终的载体还是语言,没有语言没法编程。stl使用c++,你也可以用ada来实现,用其他的语言来实现也行,结果会有所不同,但基本的东西是一样的。到处都要用到二分查找和排序,而这就是人们正在做的。对于容器的语义,不同的语言会带来轻微的不同。但是基本的区别很清楚是gp所依存的语义,以及语义分解。
例如,我们决定需要一个组件swap,然后指出这个组件在不同的语言中如果工作。显然重点是语义以及语义分类。而oop所强调的(我认为是过分强调的)是清楚的定义类之间的层次关系。oop告诉了你如何建立层次关系,却没有告诉你这些关系的实质。
(这段不太好理解,有一些术语可能要过一段时间才会有合适的中文翻译——译者)
面向对象的编程方法OOP是九十年代才流行的一种软件编程方法。它强调对象的“抽象”、“封装”、“继承”、“多态”。我们讲程序设计是由“数据结构”+“算法”组成的。从宏观的角度讲,OOP下的对象是以编程为中心的,是面向程序的对象。我们今天要讲的OOD是面向信息的对象,是以用户信息为中心的。
进一步阅读:解读面向对象的程序设计(二)
【编辑推荐】