对象导论

1、抽象过程

面向对象这种思想的实质是:程序可以通过添加新类型的对象使自身适用于某个特定问题。因此,当你阅读描述解决方案的代码的同时,也是在阅读问题的表述,这是一种更灵活更强有力的语言抽象。如果要拿现实世界的对象做类比,那么说它们具有特性和行为似乎不错。

ALan Kay总结的五个基本特性,这些特性表现了一种纯粹的面向对象程序设计方式:

  • 万物皆对象

  • 程序是对象的集合

  • 每个对象都有自己的由其他对象所构成的存储

  • 每个对象都拥有其类型

  • 某一特定类型的所有对象都可以接受同样的消息(可替代性)

Booch对对象的描述:对象具有状态、行为和标识。这意味着每一个对象都可以拥有内部数据(状态)和方法(行为),并且每一个对象在内存中都有一个唯一的地址(标识)。

2、每个对象都有一个接口

  • 创建抽象数据类型(类)是面向对象程序设计的基本概念之一。

  • 类描述了具有相同特性(数据元素)和行为(功能)的对象集合,因此一个类实际上就是一个数据类型。

  • 每个对象都只能满足某些请求,这些请求由对象的接口所定义,决定接口的便是类型。

3、每个对象都提供服务

  • 开发或理解一个程序设计,最好的办法之一就是将对象想像为“服务提供者”。

  • 并不存在的对象需考虑的问题:看起来像什么样子?能够提供哪些服务?需要哪些对象才能履行他们的义务?

  • 将对象看作是服务的提供者一个附带的好处:有助于提高对象的内聚性。高内聚是软件设计的基本质量要求之一。在良好的面向对象设计中,每个对象都可以很好的完成一项任务,但是它并不试图做更多的事。

4、被隐藏的具体实现

  • 开发人员按角色分为类创建者(创建新数据类型的程序员)和客户端程序员(在其应用中使用数据类型的程序员)。客户端程序员的目标是收集各种用来实现快速应用开发的类。类创建者的目标是构建类,这种类只向客户端程序员暴露必要的部分,而隐藏其他部分。

  • 访问控制存在原因:第一,让客户端程序员无法触及到他们不应该触及的部分——这些部分对于数据类型的内部操作来说是必需的,但并不是用户解决特定问题所需接口的一部分。第二,允许库设计者可以改变内部的工作方式而不用担心会影响到客户端程序员。

  • Java有四种访问权限,其中三种有访问权限修饰符,分别是private、public和protected,还有一种不带任何修饰符。具体访问权限见下图:

172700_xxPd_570654.jpg

5、复用具体实现

  • 代码复用是面向对象程序设计语言所提供的最了不起的优点之一。

  • 最简单地复用某个类的方式就是直接使用该类的对象,此外也可以将那个类的一个对象置于某个新的类中。使用现有的类合成新的类,这种概念称为组合,如果组合是动态发生的,通常称为聚合。

  • 组合带来了极大的灵活性。新类的成员对象通常都被声明为private,使得使用新类的客户端程序员不能访问它们。

  • 在建立新类时,应该首先考虑组合,因为它更加简单灵活。一旦有了一些经验之后,便能够看出必须使用继承的场合。

6、继承

  • 继承使用基类型和导出类型的概念表示了类型之间的相似性。可以创建一个基类型来表示系统中某些对象的核心概念,从基类型中导出其它类型,来表示此核心可以被实现的各种不同方式。

  • 当继承现有类型时,也就创造了新的类型。新的类型不仅包括现有类型的所有成员(private成员不可访问),而且更重要的是它复制了基类的接口。也就是说所有可以发送给基类对象的消息也可以发送给导出类对象,也就意味着导出类与基类具有相同的类型。通过继承而产生的类型等价性是理解面向对象程序设计方法内涵的重要门槛。

  • 两种方法使基类与导出类产生差异:第一,直接在导出类中添加新方法(应该仔细考虑是否存在基类也需要这些额外方法的可能性);第二,改变现有基类方法的行为(覆盖)。

  • 继承只覆盖基类的方法,意味着导出类和基类是完全相同的类型。可以用一个导出类对象来完全替代一个基类对象,这通常被称为替代原则。这时基类与导出类之间的关系为is-a(是一个)关系。

  • 有时必须在导出类中添加新的接口元素,扩展接口。这个新的类型仍然可以替代基类,但是这种替代并不完美,因为基类无法访问新添加的方法。这时基类与导出类之间的关系为is-like-a(像是一个)关系。

7、伴随多态的可互换对象

  • 在处理类型的层次结构时,经常想把一个对象不当作它所属的特定类型来对待,而是将其当作其基类型的对象来对待,这样就可以编写出不依赖于特定类型的代码。

  • 通过导出新的子类型而轻松扩展设计的能力是对改动进行封装的基本方式之一。

  • 把将导出类看作是它的基类的过程称为向上转型。一个面向对象程序肯定会在某处包含向上转型,因为这正是将自己从必须知道确切类型中解放出来的关键。

8、单根继承结构

  • Java中所有的类最终都继承自单一的基类,这个终极基类的名字就是Object。

  • 在单根继承结构中的所有对象都具有一个共用接口,所以它们归根到底都是相同的基本类型。

  • 单根继承结构保证所有对象都具备某些功能,在每个对象上都能执行某些基本操作,因此所有对象都可以在堆上很容易创建,而参数传递也得到极大的简化。

  • 单根继承结构使垃圾回收机器的实现变得容易很多,而垃圾回收器是java相对c++重要的改进之一。由于所有对象都具有其类型信息,因此不会因无法确定对象类型而陷入僵局。这对于系统级操作(如异常处理)尤为重要,并且给编程带来了更大的灵活性。

9、容器(集合)

  • Java类库中具有满足不同需求的各种类型容器,例如List(用于存储序列),Map(关联数组,建立对象之间的关联),Set(每种对象类型只持有一个),以及诸如队列、树、堆栈等更多的构件。

  • 容器选择依据:第一,不同的容器提供了不同类型的接口和外部行为。第二,不同的容器对于某些操作具有不同的效率。

  • 使用容器只需在其中置入对象引用,可是将它们取回时,再度用到转型,但这次不是像继承结构的上层转型为一个更泛化的类型,而是向下转型为更具体的类型。向上转型是安全的,但向下转型不一定安全。

  • 参数化类型解决了向下转型的问题,在Java中它被称为泛型。一对尖括号,中间包含类型信息。

10、对象的创建和生命周期

  • 每个对象为了生存都需要资源,尤其是内存。

  • 在被称为堆的内存池中动态地创建对象。动态方式有一个一般性的逻辑假设:对象趋向于变得复杂,查找和释放存储空间的开销不会对对象的创建造成重大的冲击。

  • Java完全采用动态内存分配方式。每当想要创建新对象时,就要使用new关键字来构建此对象的动态实例。

  • Java提供被称为“垃圾回收器”的机制,被设计用来处理内存释放的问题,它可以自动发现对象何时不再被使用,并继而销毁它。这一点和所有对象都是继承自单根基类Object以及只能以一种方式创建对象(在堆上创建)这两个特性结合起来,使得用java编程的过程较之用C++编程要简单得多。

11、异常处理:处理错误

  • Java内置了异常处理,而且强制你必须使用它,它是唯一可以接受的错误报告方式。如果没有编写正确的处理异常的代码,编译时就会报错。

  • 异常提供了一种从错误状况进行可靠恢复的途径。

12、并发编程

  • 同一时刻处理多个任务的思想,实现方法:中断和并发编程。

  • 中断对于处理时间性强的任务是必须的。

  • 对于大量其他问题,我们只是想把问题切分成多个可独立运行的部分(任务),从而提高程序响应能力。在程序中,这些彼此独立的部分称之为线程,上述概念被称为“并发”。

  • 并发有一个隐患:共享资源。如果有多个并行任务都要访问同一项资源,那么就会出问题。因此,整个过程是:某个任务锁定某项资源,完成其任务,然后释放资源锁,使其他任务也可以使用这项资源。

13、Java与Internet

  • Java对于解决传统的单机程序设计问题非常有用,但同样重要的是,它解决了在万维网(WWW)上的程序设计问题。

  • 客户端编程

       插件(plug-in)

       插件对于客户端编程的价值在于:它允许专家级的程序员不需经过浏览器厂商的许可,就可以开发某种语言扩展,并将它们添加到浏览器中。

       脚本语言(scripting language)

       Java

       备选方案(Flex,它允许你创建基于Flash的应用)

       .net和C#

       Internet与Intranet(企业内部网或局域网)

  • 服务端编程

       Perl、Python、C++或其他某种语言编写的CGI程序而实现。

       基于java的Web服务器,它让你用Java编写被称为servlet的程序来实现服务端编程(servlet及其衍生物JSP)。

转载于:https://my.oschina.net/90liusq/blog/301554