对象具有状态、行为和标识。每个对象都可以拥有内部数据(它们给出了该对象的状态)和方法(它们产生的行为),并且每个对象在内存中都有一个唯一的地址(标识)。
抽象过程就是在问题空间元素和解空间的对象之间创建一对一的映射。
1 对象是服务提供者
程序本身将向用户提供服务,它将通过调用其他对象提供的服务来实现这一目的。
通过某种方式产生对对象的请求,使对象完成各种服务。比如让灯泡发光,灯泡提供发光、熄灭两种服务。每个对象都只能满足某些请求,这些请求也称为对象的接口。
图 灯泡提供的服务
接口确定了对某一特定对象所能发出的请求。
当向对象发送请求时,与之关联的方法就会被调用,这个过程概括为:向某个对象“发送消息”(产生请求),这个对象便知道此消息的目的,然后执行对应的程序代码。
1.1 将问题分解为对象集合
我们需要开发一个简单的学生成绩录入系统。需要能录入学生的成绩、能查询某一学生的成绩等。
服务提供者 | 问题 |
学生 | 获取学生成绩信息(分数+姓名) |
成绩存储器 | 存储学生成绩信息 |
查询学生成绩 |
表 学生成绩录入系统问题与服务分析
图 学生成绩录入系统UML图
每个对象都很好地完成一项任务,但它并不试图做更多的事。在设计一个类的时候,一个类只负责一个功能领域中的相应职责。
2 代码的复用
一旦类被创建并被测试完,那么它就应该代表一个有用的代码单元,就应该可以被其他类复用。
2.1 组合
最简单复用某个类的方式是直接使用该类的一个对象,也可以将这个对象置于某个新类的成员对象中。新的类可以由任意数量、任意类型的其他对象以任意可以实现新类中想要的功能的方式所组成,这种概念被称为组合。
组合经常被视为“has-a”关系。就像人拥有鼻子一样。
在建立新类时,应该首先考虑组合,它更加灵活,会让设计变得更加清晰。
2.2 继承
在现实世界中,存在着许多的继承关系,比如人类属于动物,人类继承了动物的许多特性,比如移动move, 吃东西 eat等。在计算机这个解空间中,我们先创建好动物这个类型Animal,在创建人类People这个类型的时候,因为Animal的所有状态与行为人类都有,这时我们可以直接继承Animal。
图 人类与动物的继承关系
2.2.1 “is-a”与 “is-like-a”
“is-a”: 如果导出类只覆盖基类的方法,而不添加新的服务,这意味着导出类和基类是完全相同的类型,因为它们具有完全相同的接口。可以用导出类对象来完全替代一个基类对象。这通常被称之为替代原则。
“is-like-a”: 会在导出类中添加新的方法。比如在人类People这个导出类中,我们会添加新的接口:think()思考。我们就说,People is like a Animal。人像是一种动物。
假如我们有个系统模拟原始社会的,在原始社会中,所有动物都会行走与吃东西,但唯独不会思考。在这系统中,万物平等,都是可以互相替代的(因为行为是一样的),有一天,人类开始进化,学会了思考,于是人类开始变得独一无二,这时,人类将不能被其他动物给代替了。
2.2.2 多态
当向对象发送消息时,被调用的代码直到运行时才能确定。编译器确保被调用方法的存在,并对调用参数和返回值执行类型检查。但是并不知道将被执行的确切代码。
图 人与鱼的动态行为
3 被隐藏的具体实现
将开发人员按角色划分为类创建者(构建类)和客户端程序员(使用类)。创建类时只暴露给客户端程序员必需的部分,而隐藏其他部分。这么做有以下的好处:
1)创建者可以任意修改被隐藏的部分,而不用担心对其他任何人造成影响。
2)通常隐藏的部分是对象内部脆弱的部分,容易被客户端程序员毁坏。
public | 对任何人都是可用的。 |
private | 除类型创建者和类型的内部方法之外的的任何人都不能访问。 |
protected | 继承类可以访问 |
默认的访问权限 | 包访问权限,可以被同一个包中其他类访问。而不能被包外的访问。 |
表 Java控制访问权限的四种类似