面向对象程序设计笔记

下面是我看侯捷翻译的《Thinking in Java》第一章的一些面向对象程序设计笔记。书上还提及了其他Java的优势,我没有全部写下来。

事实上我已经学了面向对象程序设计半年了,但是我对面向对象程序设计的思想还是很模糊。


在机器模型(位于方案空间)与实际解决的问题模型(位于问题空间)之间,程序员必须建立起一种
联系。

建立起抽象数据类型,是面向对象设计中的基本观念。


所谓“纯粹”的面向对象程序设计方法是什么样的
(1) 所有东西都是对象,可将对象想象为一种新型变量,它保存着数据。但可对那个对象发出请求,要求它对自己执行一些操作。理论上讲,可从要解决的问题身上提取出所有概念性组件,再在程序中把它表示成一个对象。
(2) 每个程序都是一大堆对象的组合,通过消息的传递,一个对象可告诉另一个对象该做什么,为了向对象发出请求,需向那个对象发送一条消息。更具体地讲可将消息想象为一个调用请求,它调用的是从属于目标对象的一个子例程或函数。
(3) 每个对象都有自己的存储空间,可容纳其他对象。换句话说,通过封装一个现有的对象,还可生成一个新对象。因此,即使一个非常复杂的程序,在我们面前也显得异常简单:一切都是对象!甚至可以说一个程序本身就是一个对象。
(4) 每个对象都有一种类型。根据语法,每个对象都是某个类的一个实例,其中类(Class)是类型(Type)的同义词,一个类最重要的特征就是:“能将什么消息发给它?”
(5) 同一类所有对象都能接收相同的消息。这实际是别有含义的一种说法,大家不久便能理解。由于类型为圆(Circle)的一个对象也属于类型为形状(Shape)的一个对象,所以一个圆完全能接收形状消息。这意味着可让程序代码统一指挥形状令其自动控制所有符合形状描述的对象,其中自然包括圆。这一特性称为对象的可替换性,是
OOP 最重要的概念之一。(这一点是我之前一直忽略的。)


类(class)实际上是描述了[具有相同属性和方法]的一组实例,所以类也是数据类型的一种。例如,可以建立一个定义包含当前档位等实例变量的自行车类。这个类也定义和提供了实例方法(变档、刹车)的实现。


对象(object),台湾译作物件,是面向对象(Object Oriented) 中的术语,既表示客观世界问题空间(Namespace)中的某个具体的事物,又表示软件系统解空间中的基本元素。(Wikipedia)

[属于同一类]的众多对象除了在程序运行期间具有不同状态,其他都相同。他们有相同的属性和方法,但是状态有可能是不同的。例如:银行的出纳员都有名字性别,但是他们的名字和性别有可能不同。

事实上,我要解决如何在“问题空间”(问题实际存在的地方)的元素与“方案空间”(对实际问题进行建模的地方,如计算机)的元素之间建立理想的“一对一”对应或映射关系。


要想重复使用一个类,最简单的办法便是直接使用那个类的对象。但同时也能将那个类的一个对象置入一个新类。我们把这叫作“创建一个成员对象”新类可由任意数量及类型的其他对象构成。无论如何,只要新类达到自己的设计要求即可,这其实就是“复合”(Composition)的概念。在现有类的基础上“复合”出一个新类。“复合”就像一种包含的关系,例如:每辆车都包含一个发动机。


继承:复用接口

通过继承可以达到站在已有类的基础上修改或添加一些属性或方法。而当原始类(称为:基类(base class)或超类(super class)或父类(parent class))发生变动时,修改的克隆类(称作继承类(inherited class)或子类(child class/sub class))也会发生变动。

从现有的一个类型中继承时,便相当于创建了一个新类型,这个新类型不仅包含了现有类型的所有成员(尽管 private 成员被隐藏起来 ,且不能访问  )但更重要的是 ,它复制了基类的接口。

尽管“继承”有时会暗示(特别是在 Java 中,它用来指示继承关系的关键字就是 extends 即“扩展”的意思)我们打算为接口增添新的函数。但也并非一定如此,为了将新类区分开, 另一种做法是改变原来基类函数的行为。我们把这一处理过程称为对那个函数的“重载”(Overriding)。“重载”只需为派生类中的函数创建一个新定义即可。 尽管函数接口没变,但它对我的新类型要做一些不同的事情。


对象的创建

Java 采用的对象创建是在一个内存池中动态创建对象,该内存池亦叫“堆”或者“内存堆”若采用这种方式,除非真正运行,否则根本不知道到底需要多少个对象,也不知道它们的存在时间有多长,以及准确的类型是什么,这些参数都在程序正式运行时才决定的。若需一个新对象,只需在需要它的时候在内存堆里简单地创建它即可,由于存储空间的管理是运行期间动态进行的所以在内存堆里分配存储空间的时间比在堆栈里创建的时间长得多(在堆栈里创建存储空间一般只需要一个简单的指令,将堆栈指针向下或向下移动即可)。由于动态创建方法使对象本来就倾向于复杂,所以查找存储空间以及释放它所需的额外开销不会为对象的创建造成明显的影响。除此以外,更大的灵活性对于常规编程问题的解决是至关重要的。

而且,和c++不同,Java采用了一种名为“垃圾收集器”的机制,可自动探测出一个不再使用的对象并自动将其清除显然,我们用这种“垃圾收集器”会方便许多,因为它免去了我们必须进行跟踪和必须写一系列相关代码的苦恼。更重要的是,用垃圾收集器可有效防止出现内存漏洞,许多C++项目在它面前都会显得“相形见拙”。


容器库

在C++中它们是以标准模板库STL 的形式提供的Object,Pascal 用自己的可视组件库VCL 提供容器,Smalltalk 提供了一套非常完整的容器。而Java 也用自己的标准库提供了容器。在某些库中,一个常规容器便可满足人们的大多数要求。


分析和设计

时刻提醒自己注意以下几个问题
(1) 对象是什么?(怎样将自己的项目分割成一系列单独的组件?)
(2) 它们的接口是什么?(每个对象需要接收什么消息?)


这里写了设计分五步

阶段 0:拟出一个计划

第一步决定在后面的过程中要采取哪些步骤,把一个大的目标分成几个小任务来完成。

关于任务描述:“高度浓缩”!!举个例子来说,在一个飞行管制系统中,最开始可以将它的基本用途定义成“由控制塔程序跟踪飞机”。但假如把你的系统拿到一个非常小的机场中使用,又会出现什么情况?在那里可能没有控制塔,只有一个人负责控制,甚至连一个人都没有。因此一个程序模型要想成功应该尽可能地少反映一些特定的细节。比如上面那个例子,你可以这样来描述问题“飞机到达,下人下货,机场服务,上人上货,然后起飞。”


阶段 1:要制作什么

要特别注意将重点放在这一阶段的核心问题上,不要纠缠于其他细枝末节。这个核心问题便是决定系统要具备哪些功能。
对于这个问题最有价值的工具就是一个名为“使用场景”的集合。通过“使用场景”,我们可知道系统需要提供的一些关键性功能从而知道自己该使用的一些基本类。具体说来,你需要对下面这一系列问题做到心中有数。
1.谁来使用这个系统
2.那些人能对系统进行哪些操作
3.他们具体怎么操作
4.如果有人在操作一项功能,另一个人想操作同样的功能,怎么办?或者同一个人想操作不同的功能怎么办?(以揭示出系统的变性)
5.对系统进行操作时 可能出现什么问题以揭示出违例


阶段 2:如何构建

描述好对象及其接口,用以下三点简单概括

(1) 类的名字:这个名字应当抓住该类的本质,使人一看便懂。
(2) 类的职责:说明可用这个类做什么。可以简单地罗列出它的成员函数的名字,概括出该类的功用(因为在一个好的设计中,函数名也应该能说明一切)
(3) 类的合作:它和其他类如何打交道。

可以考虑使用UML图表式记录法。


开发你的类时,请遵循以下准则:
(1) 让特定的问题来产生一个类,然后在其他问题的方案中,让类不断得以扩充和成熟。
(2) 请记住,发现你需要的类(及其接口)是系统设计时最主要的工作。只有真正得到了那些类,你的项目以后才会变得轻松。
(3) 最开始不必强求知道一切东西——在学习中进步
(4) 尽早开始编程:让一些东西工作起来,证明你的设计是否可行。不要担心最后得到的是一系列“拿不出手”的代码——条理清晰的类会帮你区分不同的问题,并可有效控制混乱局面。
(5) 尽量简单!小而清楚的对象及功能单纯的工具要明显优于大而复杂的接口。


阶段 3:构建核心

系统构建的一部分工作是把它放到一个现实的环境中进行测试,然后参考自己的要求和系统规范进行进行分析。请测试你的系统是否能满足使用场景的要求。假如系统的核心是稳定可靠的,就可以继续开发过程,在它的基础上放心地添加其他功能。

阶段4 迭代使用场景

核心框架运行起来之后,在它上面添加的每项功能都应该只是一个独立的小项目。我们经过一次“迭代”(Iteration)便完成了一系列特性的添加。每一次“迭代”都应当是一个
比较短的开发周期。每一次迭代结束后,我们都得到了一个集成的经过测试的系统,而且又新添了不少功能。


阶段 5:校订

事实上整个开发周期还没有结束,现在进入的是传统意义上称为“维护”的一个阶段。



你可能感兴趣的:(Java)