Thinking In Java Part01(抽象)

1、抽象过程
	所有编程语言都提供抽象机制,人们所能解决的问题的复杂性取决与抽象的类型和之类。汇编语言是对底层机器的轻微抽象。命令式语言(Fortran、Basic、C等)都是对汇编语言的抽象。他们所作的主要抽象仍邀请在解决问题时要基于计算机的结构,而不是基于所要解决问题的结构来考虑。
	面向对象方式通过向程序员提供表示问题空间中的元素的工具更进一步,使得我们不会受限于任何特定类型的问题。我们将问题空间中的元素机器在解空间中的表示称为“对象”。这种思想的实质是:程序可以通过添加新类型的对象使自身适用于某个特定问题。因此,当你在阅读描述解决方案的代码的同时,也是在阅读问题的表述。OOP允许根据问题来描述问题,而不是根据允许解决方案的计算机来描述问题。但是每个对象看起来都有点像一台微型计算机——它具有状态,还具有操作,用户可以要求对象执行这些操作。
	Alan Kay曾总结了第一个成功的面向对象语言、同时也是Java所基于的语言之一的SmallTalk的五个基本特性,这些特性表现了一种纯粹的面向对象程序设计方式:
		1.1、万物皆对象:将对象视为奇特的变量,它可以存储数据,除此之外,你还可以要求它在自身上执行操作。理论上讲,你可以抽取待求解问题的任何概念化构建(狗、建筑物、服务等),将其表示为程序中的对象。
		1.2、程序是对象的集合,它们通过发送消息来告知彼此所要做的:要想请求一个都系,就必须对该对象发送一条消息。更具体地说,可以把消息想像为对某个特定对象的方法的调用请求。
		1.3、每个对象都有自己的由其他对象所构成的存储。换句话说,可以通过创建包含现有对象的包的方式来创建新类型的对象。因此,可以在程序中构建复杂的体系,同时将其复杂性隐藏在对象的简单性背后。
		1.4、每个对象都拥有其类型:“每个对象都是某个类(class)的一个实例(instance)”,这里“类”就是“类型”的同义词。每个类最重要的区别于其他类的特性就是“可以发送什么样的消息给它”。
		1.5、某一特定类型的所有对象都可以接受同样的信息:因为“圆形”类型的对象同时也是“几何形”类型的对象,所以一个“圆形”对象必定能够接受发送给“几何形”对象的信息。这意味着可以编写与“几何形”交互并自动处理所有与几何形性质相关的事物的代码。这种可替代性是OOP中最强有力的概念之一。
		Booch对对象提出了一个更加简介的描述:对象具有状态、行为和标识。这以为每一个对象都可以拥有内部数据(它们给出了该对象的状态)和方法(它们产生行为),并且每一个对象都可以唯一地与其他对象区分开来,具体来说 ,就是每一个对象在内存中都有一个唯一的地址(有一点过于受限,因为对象可以存在于不同的机器和地址空间中,它们还可以被存储在硬盘上,在这些情况下,对象的标识就必须由地址之外的某些东西来确定了)。

2、每个对象都有一个接口
	亚里士多德大概是第一个深入研究类型(type)的哲学家。所有的对象都是唯一的,但同时也是具有相同的特性和行为的对象所归属的类的一部分。这种思想被直接应用于第一个面向对象语言Simula-67,它在程序中使用基本关键字class来引入新的类型。
	创建抽象数据类型(类)是面向对象程序设计的基本概念之一。抽象数据类型的运行方式与内置(built-in)类型几乎完全一致:你可以创建某一类型的变量(按照面向对象说法,称其为对象或实例),然后操作这些变量(称其为发送消息或请求,发送消息,对象就知道要做什么)。每个类的成员或元素都具有某种共性:每个账户都有结余金额,每个出纳都可以处理存款请求等。同时,每个成员都有其自身的状态:每个账户都有不同的结余金额,每个出纳都有自己的姓名。因此,出纳、客户、账户、交易等都可以在程序中被表示成唯一的实体。这些实体就是都系,每一个对象都属于定义了特性和行为的某个特定的类。
	所有的面向对象程序设计语言都使用class这个关键字来表示数据类型。因为类描述了具有相同特性(数据元素)和行为(功能)的对象集合,所以一个类实际上就是一个数据类型。
	任何程序都是你所设计的系统的一种仿真。一旦类被建立,就可以随心所欲的创建类的任意个对象,然后操作它们,就像它们是存在于你的待求解问题中的元素一样。
	如何获得有用的对象?必须有某种方式产生对对象的请求,使对象完成各种任务,如完成开关、更亮等。每个对象都只能满足某些请求,这些请求由对象的接口(interface)所定义。	
	接口确定了对某一特定对象所能发出的请求。但是,在程序中必须有满足这些请求的代码,这些代码与隐藏的数据一起构成了实现。在类型中,每一个可能的请求都有一个方法与之相关联,当向对象发送请求时,与之相关联的方法就会被调用。此过程通常被 概括为:向某个对象“发送信息”(产生请求),这个对象便知道此消息的目的,然后执行对应的程序代码。
	UML图中每个类都用一个方框表示,类名在方框的顶部,你所关心的任何数据成员都描述在方框的中间部分,方法(隶属于此对象的、用来接受你发给此对象的消息的函数)在方框的底部。通常,只有类名和公共方法被示于UML设计中。
3、每个对象都提供服务
	当正在试图开发或理解一个程序设计时,最后的方法之一就是将对象想像为“服务提供者”,程序本身将向用户提供服务,它将通过调用其他对象提供的服务来实现这一目的。你的目标就是去创建能够提供理想的服务来解决问题的一系列对象。
	在创建对象前,问自己“如果我可以将问题从表象中抽取出来,那么什么样的对象可以解决我的问题?”如果正在创建一个簿记系统,那么可以知道系统应该具有某些包括了预定义的簿记输入屏幕的对象,一个执行簿记计算的对象集合,以及一个处理在不同的打印机上打印支票和开发票的对象。也许上述对象某些已经存在,但是对于并不存在的对象,它们看起来像什么?它们能够提供哪些服务?它们需要哪些对象才能履行它们的义务?最终,我们会知道这个对象的构成。这是将问题分解为对象集合的一种合理方式。
	将对象看作是服务提供者还有助于提供对象的内聚性。人们设计对象经常面临一个问题为将过多的功能都塞在一个对象中。例如将一个对象设计为了解所有的格式和打印技术。我们可以拆分成多个,比如一个对象可以是所有可能的支票排版的目录,它可以被用来查询有关如何打印一张支票的信息,另一个对象可以是一个通用的打印接口,它知道有关所有不同类型的打印机的信息(但是不包含任何有关簿记的内容,它更应该是一个需要购买而不是自己编写的对象);第三个对象通过调用另外两个都系的服务来完成打印任务。在良好的面向对象设计中,每个对象都可以很好地完成一项任务,但是它并不试图做更多的事。
	将对象作为服务提供者不仅在设计中非常有用,而且当其他人试图理解你的代码或重用时,如果他们看出了这个对象所能提供的服务的价值,会使调整对象以适应其设计的过程变得简单得多
4、被隐藏的具体实现
	程序开发人员角色一般分为类创建者(创建新数据类型的程序员)和客户端程序员(那些在其应用中使用数据类型的类消费者)
	隐藏的部分一般都是对象内部脆弱的部分,很容易被粗心或不知内情的程序员毁坏,隐藏将实现隐藏起来可以减少程序bug。
	在任何相互关系中,具有关系所涉及的各方都遵守的边界非常重要。如果希望别人不要直接操作你的类中的某些成员,需要加上访问控制,不然所有的东西都将赤裸暴露。
	访问控制的第一个存在原因:让客户端程序员无法触及他们不应该触及的部分——这些部分对数据类型的内部操作来说是必须的,但并不是用户解决特定问题所需的接口的一部分。这对客户端程序员来说其实是一项服务,因为他们可以很容易看出哪些东西对他们来说很重要,而哪些东西可以忽略。
	访问控制的第二个存在原因:允许库设计者可以改变类内部的工作方式而不用担心会影响到客户端程序员。开发了一个简单的应用,事后发现要改写。如果接口和实现可以清晰地分离,那么可以轻而易举地完成 。
	Java用三个关键字在类的内部设定边界:public、private、protected。这些访问指定词(access specifier)觉得了紧跟其后被定义的东西可以被谁使用。public表示 紧跟其后的元素 对任何人可用。而private表示除类型创建者和类型的内部方法之外的任何人都不能访问的元素。private就像你与客户端程序员之间的一堵墙,如果有人视图访问private成员,就会在编译时得到错误信息。protected关键字与private作用相当,差别仅在于继承的类可以访问protected,而不能访问private。
	还有一个默认的访问权限,当没有使用前面的任何访问指定词,这种权限通常被称为包访问权限,类可以访问在同一个包(库构件)中的其他类的成员,包外,这些成员如同指定private
5、复用具体实现
	最简单的复用就是直接使用该类的一个对象,此外,可以将那个类的一个对象置于某个新的类中。我们称其为“创建一个成员对象”。因为是在使用先有的类合成新的类,所以这种概念被称为组合(composition),如果组合是动态的,被称为聚合(aggregation)。组合被视为"has-a"(拥有),就像我们常说“汽车拥有引擎”。
	新类的成员对象常被声明为private,使得新类的客户端程序员不能访问它们。这也使得你可以在不干扰现有客户端代码的情况下,修改这些成员,也可以在运行时修改这些成员对象,以实现动态修改程序的行为 。有继承不具备的灵活性
6、继承
	对象的观念使得我们可以通过概念将数据和功能封装到一起,因此可以对问题空间的观念给出恰当的表示,而不用受制于必须使用底层机器语言。这些概念用关键字class来表示,它们形成了编程语言中的基本单位。
	我们通过继承可以用现有的类为基础,复制它,然后通过添加和修改这个副本来创建新类。当源类(被称为基类、超类或父类)发出变动时,被修改的“副本“(被称为导出类、继承类或子类)也会反映出这些变动。
	类型不仅仅知识描述了作用于一个对象集合上的约束条件,同时还有与其他类型直接的关系。两个类型可以有相同的特性和行为,但是其中一个类型可能比另一个含有更多的特性,并且可以处理更多的信息(或以不同的方式来处理消息)。继承使用基类型和导出类型的概念表示了这种类型之间的相似性。一个基类型包含其所有导出类型所共享的特性和行为 。可以创建一个基类型来表示系统中某些对象的核心概念。
	以垃圾回收为例,它用来归类散落的垃圾。“垃圾”是基类型,每一件垃圾都有重量、价值等特性,可以被切碎、熔化或分解。在此基础上,可以通过添加额外的特性(例如瓶子有颜色)或行为(例如铁罐可以被磁化)导出更具体的垃圾类型。此外,某些行为可能不同(例如纸的价值取决于类型和状态)。可以通过使用继承来构建一个类型层次结构,以此来表示待求解的某种类型的问题。
	另一个例子是基类是几何形,每一个几何形都具有尺寸、颜色、位置等,同时每一个几何形都可以被绘制、擦除、移动和着色等。在此基础上,可以导出(继承出)具体的几何形状——圆形、正方形、三角形等——每一种都具有额外的特性和行为,例如某些形状可以翻转,例如计算几何形状的面积。类型层次结构同时体现了几何形状之间的相似性和差异性。
	以同样的术语将解决方案转换成问题是大有裨益的,因为不需要在问题描述和解决翻翻描述之间建立许多中间模型。通过使用对象,类型层次结构成为了主要模型,因此,可以直接从真实世界中对系统的描述过渡到代码对系统进行描述。
	当继承现有类型时,也就创造了新的类型。这个新的类型不仅包括现有类型的所有成员(尽管private成员被隐藏,并且不可访问)而且更重要的是它复制了基类的接口。也就是说,所有可以发送给基类对象的消息同时也可以发送给导出类对象。由于通过发送给类的消息的 类型 可知类的类型,所以这也就意味着导出类与基类具有相同的类型。所以“一个圆形就是一个几何形”。通过继承而产生的类型等价性是理解面向对象程序设计方法内涵的重要门槛。
	由于基类和导出类具有相同的基础接口,所以伴随此接口的必定有某些具体实现。也就是说,当对象接收到特定消息时,必须有某些代码去执行。如果知识简单地继承一个类而并不做其他任何事,那么在基类接口中的方法将会直接继承到导出类中。这意味着导出类的对象不仅与基类拥有相同的类型,而且还拥有相同的行为,这样做没什么特别意义。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值