对象导论
1.抽象 所有的编程语言都提供抽象机制。例如汇编对机器进行了轻微的抽象,C语言对汇编进行了抽象。相比较而言,这些语言对于解决问题都有较强的局限性。因为它们会强迫你按照“机器”的角度进行思考。程序员必须根据机器模型和实际问题模型来建立关联。这对于开发来讲是非常不变的。正是因为如此,面向对象的思想应运而生。
在面向对象的世界里,所有的问题都可以看成是对象。程序员不必再受限于待解决的特定类型的问题。我们可以将问题空间中的元素和解空间中的表示称之为对象。这句话读起来非常拗口,不过我们只需要记住,把任何问题都看做对象,更适合描述我们现实中的世界,与我们人类的思维也更为接近。
纯粹的面向对象程序设计方式:
- 万物皆为对象。可以将现实世界,要解决的问题,等一切概念化的构件抽象为对象。
- 程序是对象的集合,它们通过发送消息来告知彼此要做的事情。这句话对于初学者来说可能会有一些歧义,要时刻记住的是,代码定义的是类型,程序中活跃的永远是对象。调用对象中的某个方法相当于向这个对象“发送了消息”,由这个对象根据消息决定要做什么事。
- 每个对象都有自己的由其他对象所构成的存储。通俗一点理解就是对象可以包含其他的对象。正是由于这样的特性我们才可以基于面向对象构建复杂的架构,将复杂性隐藏与对象的简单性之后。
- 每个对象都拥有其类型。这个理解起来很简单,对象是程序中活跃的元素,每个对象都是它类型的一个特殊的实例。比如,人是一种类型,张三是这个类型的一个对象,李四是这个类型中的另一个对象,张三和李四是不同的实体,但是他们同属于“人”这个类型。
- 某一个特定类型的对象可以接受同样的消息。人都可以走,鸟都可以飞。更有深意的理解是,“圆”类型的对象,一定是一个“几何体”类型的对象,所以圆形类型的对象一定能接受发给几何形类型对象的消息。所以编写代码时候尽量编写与“更基本的类型”交互的代码。因为子类型的同样适用于这些代码。这种“可替代性”也就是java中向上转型的思想体现。
总结:对象具有状态(java中用数据成员表示), 行为(java中用方法成员表示), 标识,(每个对象都可以和其他的对象完全区分开来)。
2. 接口与服务。
每个对象都需要对外暴露接口,声明它所能提供的服务。这里的接口和java中的关键字interface不是一个概念,这里的接口相当于对外界的通道,具体来讲就是类中声明的方法。
1 public class Light { 2 3 private int brightness; 4 5 public void on(){ 6 System.out.println("the light is on"); 7 } 8 9 public void off(){ 10 System.out.println("the light is off"); 11 } 12 13 public static void main(String[] args){ 14 Light light = new Light(); 15 light.on(); 16 light.off(); 17 } 18 }
这是一个简单的示例。Light定义了一个灯类型,这个类型的所以对象看起来都应该具有这样的属性,“brightness”,这个类型的所有对象都应该具有这样两个接口, “on”, "off",在main函数中(程序的入口)创建了Light类型的一个对象,对象的名字叫light,
可以向这个对象发送消息,通过调用“on” 和 “off” 方法,让它打开或关闭。这里我调用了系统类打印字符串来模拟打开和关闭。这里没有用到属性,只是为了展示“对象的接口”的含义。
这个示例向我们展示了这样一个理念,在写代码的同时要时刻思考,我创造的类型能够抽象实际中的什么问题,我的类型的对象能向外界提供什么样的服务(通过接口),我应该调用哪些类去提供这样的服务(类的组合或继承),想明白问题就可以迎刃而解。
3.访问控制机制
有些时候,对类里面的成员的访问加以控制是必要的。可以将程序开发人员分为两类,一类是类的创建者,即创建这个类的人,还有一类是客户端程序员,即使用这些类的人。一般来讲,类的创建者只需要暴露给用户那些希望用户可以使用的接口,而隐藏其他需要保护的部分,一是因为这样的机制可以保护程序不被粗心的程序员滥用和破坏,二是允许类的设计者可以改变类的内部实现方式而不会影响到其他使用这个类的程序员。这是使用访问控制机制的根本原因。
java中使用三个关键字,public, private, protected设定边界。可以先记住,public修饰的成员在任何地方都可用,private修饰的成员只能在这个类内部被使用,protected修饰的成员可以在类内部和继承这个类的内部被访问,同时protected具有默认的包访问权限。没有被任何关键字修饰的成员同样具有默认的包访问权限。
4.继承还是组合
代码复用是面向对象设计语言最大的优点之一。最简单的就是创建一个类型的对象,将它放置与另一个类中,称之为“创建一个成员对象”,这样的复用方式具有很大的灵活性。例如,“船”这个类型,需要有“浆”这个类型的对象作为其数据成员,可以创建一个这样的对象将其放入“船”类型中。
继承的适用场景:如果能够以现有的类为基础,通过添加或者修改这个类的接口来创建我们所需的类型。继承类会包含基类的所有成员,无论是public还是private成员,不仅如此它还复制了基类的所有接口。也就是说所有发送给基类的消息同样可以发送给导出类。