面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构    ['ɔ:rɪəntɪd]      [ˈprəʊgræmɪŋ]

 

  1:OOP优缺点

 

  2: OOP五大基本特征

    (1) 所有东西都是对象。可将对象想象成一种新型变量;它保存着数据,但 可要求它对自身进行操作。理论上讲,可从要解决的问题身上提出所有概念性的 组件,然后在程序中将其表达为一个对象。

    (2) 程序是一大堆对象的组合;通过消息传递,各对象知道自己该做些什么。 为了向对象发出请求,需向那个对象“发送一条消息”。更具体地讲,可将消息 想象为一个调用请求,它调用的是从属于目标对象的一个子例程或函数。

    (3) 每个对象都有自己的存储空间,可容纳其他对象。或者说,通过封装现 有对象,可制作出新型对象。所以,尽管对象的概念非常简单,但在程序中却可 达到任意高的复杂程度。

    (4) 每个对象都有一种类型。根据语法,每个对象都是某个“类”的一个“实 例”。其中,“类”(Class)是“类型”(Type)的同义词。一个类重要的特征 就是“能将什么消息发给它?”。

    (5) 同一类所有对象都能接收相同的消息。这实际是别有含义的一种说法, 大家不久便能理解。由于类型为“圆”(Circle)的一个对象也属于类型为“形状” (Shape)的一个对象,所以一个圆完全能接收形状消息。这意味着可让程序代 码统一指挥“形状”,令其自动控制所有符合“形状”描述的对象,其中自然包 括“圆”。这一特性称为对象的“可替换性”,是 OOP 重要的概念之一。 

 

  3:事实上,当我们进行面向对象的程序设计时,面临 的最大一项挑战性就是:如何在“问题空间”(问题实际存在的地方)的元素与 “方案空间”(对实际问题进行建模的地方,如计算机)的元素之间建立理想的 “一对一”对应或映射关系。 

    如何利用对象完成真正有用的工作呢?必须有一种办法能向对象发出请求, 令其做一些实际的事情,比如完成一次交易、在屏幕上画一些东西或者打开一个 开关等等。每个对象仅能接受特定的请求。我们向对象发出的请求是通过它的“接 口”(Interface)定义的,对象的“类型”或“类”则规定了它的接口形式。“类 型”与“接口”的等价或对应关系是面向对象程序设计的基础。 

Light lt = new Light();

lt.on();
在这个例子中,类型/类的名称是 Light,可向 Light 对象发出的请求包
括打开(on)、关闭(off)、变得更明亮(brighten)或者变得更暗淡(dim)。通 过简单地声明一个名字(lt),我们为 Light 对象创建了一个“句柄”。然后用 new 关键字新建类型为 Light 的一个对象。再用等号将其赋给句柄。为了向对象发送 一条消息,我们列出句柄名(lt),再用一个句点符号(.)把它同消息名称(on) 连接起来。

“接口”(Interface)规定了可对一个特定的对象发出哪些请求。

 

 

  4:访问权限

  “public”(公共)意味着后续的定义任何人均可使用。

  “private”(私有)意味着除您自己、类型的创建者以及那个类型的内部 函数成员,其他任何人都不能访问后续的定义信息。private 在您与客户程序员之 间竖起了一堵墙。若有人试图访问私有成员,就会得到一个编译期错误。

  “friendly”(友好的)涉及“包装”或“封装”(Package)的概念——即 Java 用 来构建库的方法。若某样东西是“友好的”,意味着它只能在这个包装的范围内 使用(所以这一访问级别有时也叫作“包装访问”)。

  “protected”(受保护的)与 “private”相似,只是一个继承的类可访问受保护的成员,但不能访问私有成员。 继承的问题不久就要谈到。  

 

  5:方案的重复使用

  为重复使用一个类,简单的办法是仅直接使用那个类的对象。但同时也能 将那个类的一个对象置入一个新类。我们把这叫作“创建一个成员对象”。

  新类 可由任意数量和类型的其他对象构成。无论如何,只要新类达到了设计要求即可。 这个概念叫作“组织”——在现有类的基础上组织一个新类。有时,我们也将组 织称作“包含”关系,比如“一辆车包含了一个变速箱”。 

  新类的“成员对象”通常设为“私有” (Private),使用这个类的客户程序员不能访问它们。这样一来,我们可在不干 扰客户代码的前提下,从容地修改那些成员。也可以在“运行期”更改成员,这 进一步增大了灵活性。后面要讲到的“继承”并不具备这种灵活性,因为编译器 必须对通过继承创建的类加以限制。 

  新加入这一领域的程序员,或许早已先入为主地认为“继承应当随处可见”。 沿这种思路产生的设计将是非常笨拙的,会大大增加程序的复杂程度。相反,新 建类的时候,首先应考虑“组织”对象;这样做显得更加简单和灵活。利用对象 的组织,我们的设计可保持清爽。一旦需要用到继承,就会明显意识到这一点。 

  

  6:上溯造型

void doStuff(Shape s) {

  s.erase();

   // ...

   s.draw();

}
那么对 doStuff()的调用会自动良好地工作,无论对象的具体类型是什么。 这实际是一个非常有用的编程技巧。请考虑下面这行代码:

doStuff(c);

此时,一个 Circle(圆)句柄传递给一个本来期待 Shape(形状)句柄的函 数。由于圆是一种几何形状,所以 doStuff()能正确地进行处理。也就是说,凡是 doStuff()能发给一个 Shape 的消息,Circle 也能接收。所以这样做是安全的,不 会造成错误

我们将这种把衍生类型当作它的基本类型处理的过程叫作“Upcasting”(上 溯造型)。其中,“cast”(造型)是指根据一个现成的模型创建;而“Up”(向上) 表明继承的方向是从“上面”来的——即基础类位于顶部,而衍生类在下方展开。 所以,根据基础类进行造型就是一个从上面继承的过程,即“Upcasting”。 

 

  7:动态绑定

将一条消息发给对象时,如果并不知道对方的具体类型是什么,但采取的行 动同样是正确的,这种情况就叫作“多形性”(Polymorphism)。对面向对象的程 序设计语言来说,它们用以实现多形性的方法叫作“动态绑定”。编译器和运行 期系统会负责对所有细节的控制;我们只需知道会发生什么事情,而且更重要的 是,如何利用它帮助自己设计程序。

有些语言要求我们用一个特殊的关键字来允许动态绑定。在 C++中,这个关 键字是 virtual。在 Java 中,我们则完全不必记住添加一个关键字,因为函数的 动态绑定是自动进行的。所以在将一条消息发给对象时,我们完全可以肯定对象 会采取正确的行动,即使其中涉及上溯造型之类的处理。  

 

  8:抽象类、抽象函数

设计程序时,我们经常都希望基础类只为自己的衍生类提供一个接口。也就 是说,我们不想其他任何人实际创建基础类的一个对象,只对上溯造型成它,以 便使用它们的接口。为达到这个目的,需要把那个类变成“抽象”的——使用 abstract 关键字。若有人试图创建抽象类的一个对象,编译器就会阻止他们。这 种工具可有效强制实行一种特殊的设计。 亦可用 abstract 关键字描述一个尚未实现的方法——作为一个“根”使用, 指出:“这是适用于从这个类继承的所有类型的一个接口函数,但目前尚没有对 它进行任何形式的实现。”抽象方法也许只能在一个抽象类里创建。继承了一个 类后,那个方法就必须实现,否则继承的类也会变成“抽象”类。通过创建一个 抽象方法,我们可以将一个方法置入接口中,不必再为那个方法提供可能毫无意 义的主体代码。 interface(接口)关键字将抽象类的概念更延伸了一步,它完全禁止了所有 的函数定义。“接口”是一种相当有效和常用的工具。另外如果自己愿意,亦可 将多个接口都合并到一起(不能从多个普通 class 或 abstract class 中继承)。 

 

  9:单根结构

所有类终都应从单独一个基础类继承,这个终级基础类的名字很简单, 就是一个“Object”。

 

  10:下溯造型(Downcasting)

假如下溯造型成错误的东西,会得到我们称为 “违例”(Exception)的一种运行期错误。

 

  11:垃圾收集器

代价就是运行期的开销。

 

  12:多线程

有些时候,中断对那些实时性很强的任务来说是很有必要的。但还存在其他 许多问题,它们只要求将问题划分进入独立运行的程序片断中,使整个程序能更 迅速地响应用户的请求。在一个程序中,这些独立运行的片断叫作“线程” (Thread),利用它编程的概念就叫作“多线程处理”。多线程处理一个常见的例 子就是用户界面。利用线程,用户可按下一个按钮,然后程序会立即作出响应, 而不是让用户等待程序完成了当前任务以后才开始响应。 

根据前面的论述,大家可能感觉线程处理非常简单。但必须注意一个问题: 共享资源!如果有多个线程同时运行,而且它们试图访问相同的资源,就会遇到 一个问题。举个例子来说,两个进程不能将信息同时发送给一台打印机。为解决 这个问题,对那些可共享的资源来说(比如打印机),它们在使用期间必须进入 锁定状态。所以一个线程可将资源锁定,在完成了它的任务后,再解开(释放) 这个锁,使其他线程可以接着使用同样的资源。 

。Java 也提供了有限的资源锁定方案。它能锁定任何对象占用的内存(内 存实际是多种共享资源的一种),所以同一时间只能有一个线程使用特定的内存 空间。为达到这个目的,需要使用 synchronized 关键字。其他类型的资源必须由 程序员明确锁定,这通常要求程序员创建一个对象,用它代表一把锁,所有线程 在访问那个资源时都必须检查这把锁。