《4java面向对象设计课件》由会员分享,可在线阅读,更多相关《4java面向对象设计课件(21页珍藏版)》请在金锄头文库上搜索。
1、Java面向对象设计思想计算机学院通信软件工程中心张艳梅 14java面向对象设计本章主要内容:l1、一切皆对象一切皆对象。程序由对象构成。对象由更小的对象构成。每个对象有其职责。对象职责通过它的下属对象的职责实现和下属对象互相协作来实现。l2、从实例体会OOP开始使用对象继承的好处接口可是个利器24java面向对象设计1、一切皆对象l对象:是人们要进行研究的任何事物,从最简单的整数到复杂的飞机等均可看作对象,它不仅能表示具体的事物,还能表示抽象的规则、计划和事件。l对象具有状态,一个对象用数值来描述它的状态。l对象具体操作,用来改变对象的状态,操作就是对象的行为。l对象实现了数据和操作的结合
2、,使数据和操作封闭于对象的统一体中。34java面向对象设计1.1 一切皆对象l理论上讲,可从要解决的问题身上提出所有概念性的组件,然后在程序中将其表达为一个对象。l当我们进行面向对象的程序设计时,面临的最大一项挑战性就是,如何把问题描述转化为对象架构。44java面向对象设计1.2 程序由对象构成l程序是一大堆对象的组合。l例:Lightlt=newLight();l通过消息传递,各对象知道自己该做些什么。l例:lt.on();lt.off();lt.brighten();lt.dim();l为了向对象发出请求,需向那个对象“发送一条消息”。更具体地讲,可将消息想象为一个调用请求,它调用的是
3、从属于目标对象的一个子例程或函数。l使用一些预先定义好的类时,我们在程序里采用的代码是非常简单和直观的。54java面向对象设计1.3 对象由更小的对象构成(1)许多人认为代码重用是面向对象程序设计提供的最伟大的一种杠杆。l为重复使用一个类,最简单的办法是直接使用那个类的对象。但同时也能将那个类的一个对象置入一个新类。我们把这叫作“创建一个成员对象”。l新类可由任意数量和类的其他对象构成。这个概念叫作“组合”(也叫“包含”)在现有类的基础上组织一个新类。l所以,尽管对象的概念非常简单,但在程序中却可达到任意高的复杂程度。64java面向对象设计1.3 对象由更小的对象构成(2)l对象的组合具有
4、极大的灵活性。新类的“成员对象”通常设为“私有”(Private),这样我们可在不干扰客户代码的前提下,从容地修改那些成员。也可以在“运行期”更改成员,这进一步增大了灵活性。l由于继承的重要性,所以在面向对象的程序设计中,它经常被重点强调。作为新加入这一领域的程序员,或许早已先入为主地认为“继承应当随处可见”。沿这种思路产生的设计将是非常笨拙的,会大大增加程序的复杂程度。相反,新建类的时候,首先应考虑“组合”对象;这样做显得更加简单和灵活。利用对象的组织,我们的设计可保持清爽。74java面向对象设计1.4 每个对象都有其职责(1)l“接口”(Interface)规定了可对一个特定的对象发出哪
5、些请求。然而,必须在某个地方存在着一些代码,以便满足这些请求。这些代码与那些隐藏起来的数据便叫作“隐藏的实现”。对象的职责就是决定如何对这条消息作出反应(执行相应的代码)。l每个对象都有一种模版。l类:具体相同或相似性质的对象的抽象就是类。因此,对象的抽象是类,类的具体化是对象,也可说实例是对象。类具体属性和操作。84java面向对象设计1.4 每个对象都有其职责(2)l一个类最重要的特征就是“能将什么消息发给它?”。lJava采用三个显式关键字以及一个隐式关键字来设置类边界:public,private,protected以及暗示性的friendly。若未明确指定其他关键字,则默认为后者。这
6、些关键字的使用和含义都是相当直观的,它们决定了谁能使用后续的定义内容。94java面向对象设计1.5 对象职责由下属对象协作实现(1)l我们费尽心思做出一种类后,假如不得不又新建一种类,令其实现大致相同的功能,那会是一件非常令人灰心的事情。但若能利用现成的类,对其进行“克隆”,再根据情况进行添加和修改,情况就显得理想多了。“继承”正是针对这个目标而设计的。但继承并不完全等价于克隆。104java面向对象设计1.5 对象职责由下属对象协作实现(2)l有两种做法可将新得的衍生类与原来的基础类区分开。l第一种做法:为衍生类添加新函数(功能)。一般都是意识到基础类不能满足我们的要求。新类“类似”原类l
7、第二个办法是改变基础类一个现有函数的行为。我们将其称作“改善”那个函数。只需为衍生类的函数建立一个新定义即可。我们的目标是:“尽管使用的函数接口未变,但它的新版本具有不同的表现”。新类“等价”原类114java面向对象设计1.5 对象职责由下属对象协作实现(3)l由于类为“圆”(Circle)的一个对象也属于类为“形状”(Shape)的一个对象,所以一个圆完全能接收形状消息。l这意味着可让程序代码统一指挥“形状”,令其自动控制所有符合“形状”描述的对象,其中自然包括“圆”。这一特性称为对象的“可替换性”,是OOP最重要的概念之一。l若通过继承增添了一种新类,如“三角形”,那么我们为“形状”编写
8、的代码不用改变。所以说程序具备了“扩展能力”。124java面向对象设计2、从实例理解面向对象设计思想l假定我们要设计一个媒体播放器。该媒体播放器目前只支持音频文件mp3和wav。初步设计出来的播放器可能很简单:publicclassMediaPlayerprivatevoidplayMp3()System.out.println(Playthemp3file.);privatevoidplayWav()System.out.println(Playthewavfile.);publicvoidplay(stringaudioType)switch(audioType.ToLower()cas
9、e(mp3):playMp3();break;case(wav):playWav();break;134java面向对象设计2、需求变更促使我们改善l自然,你会发现这个设计非常的糟糕。因为它根本没有为未来的需求变更提供最起码的扩展。当你为应接不暇的需求变更而焦头烂额的时候,你可能更希望让这份设计到它应该去的地方,就是桌面的回收站。l仔细分析这段代码,它其实是一种最古老的面向结构的设计。如果你要播放的不仅仅是mp3和wav,你会不断地增加相应地播放方法,然后让switch子句越来越长,直至达到你视线看不到的地步。l好吧,我们先来体验对象的精神。根据OOP的思想,我们应该把mp3和wav看作是一个
10、独立的对象。那么是这样吗?144java面向对象设计2、建立对象,统一接口lpublicclassMP3publicvoidplay()System.out.println(Playthemp3file.);lpublicclassWAVpublicvoidplay()System.out.println(Playthewavfile.);你已经知道怎么建立对象了。更可喜的是,你在不知不觉中应用了重构的方法,把原来那个垃圾设计中的方法名字改为了统一的play()方法。但似乎你并没有击中要害,以现在的方式去更改MediaPlayer的代码,实质并没有多大的变化。154java面向对象设计2、引入
11、继承,为了?l既然mp3和wav都属于音频文件,他们都具有音频文件的共性,为什么不为它们建立一个共同的父类呢?publicclassAudioMediapublicvoidplay()System.out.println(PlaytheAudioMediafile.);l现在我们引入了继承的思想,OOP也算是象模象样了。得意之余,再认真分析下,其实在现实生活中,我们播放的只会是某种具体类型的音频文件,因此这个AudioMedia类并没有实际使用的情况。对应在设计中,就是:这个类永远不会被实例化。所以,还得动一下手术,将其改为抽象类。164java面向对象设计2、出现类层次(继承+组合)l好了,
12、现在的代码有点OOP的感觉了:publicabstractclassAudioMediapublicabstractvoidplay();publicclassMP3extendsAudioMediapublicvoidPlay()System.out.println(Playthemp3file.);publicclassWAVextendsAudioMediapublicvoidPlay()System.out.println(Playthewavfile.);publicclassMediaPlayerpublicvoidplay(AudioMediamedia)media.play()
13、;174java面向对象设计2、无止境的发展l看看现在的设计,保证了类的最小化原则,更利于扩展(到这里,你会发现play方法名改得多有必要)。即使你现在又增加了对WMA文件的播放,只需要设计WMA类,并继承AudioMedia,重写play方法就可以了,MediaPlayer类对象的play方法根本不用改变。l是不是到此就该画上圆满的句号呢?然后刁钻的客户是永远不会满足的,他们希望你的媒体播放器能够支持视频文件。你又该痛苦了,因为视频文件和音频文件有很多不同的地方,你可不能偷懒,让视频文件对象认音频文件作父亲啊。你需要为视频文件设计另外的类对象了,假设我们支持RM和MPEG格式的视频:184j
14、ava面向对象设计2、追加一个继承层次publicabstractclassVideoMediapublicabstractvoidPlay();publicclassRMextendsVideoMediapublicvoidPlay()System.out.println(Playthermfile.);publicclassMPEGextendsVideoMediapublicvoidPlay()System.out.println(Playthempegfile.);l糟糕的是,你不能一劳永逸地享受原有的MediaPlayer类了。因为你要播放的RM文件并不是AudioMedia的子类。
15、194java面向对象设计2、接口可是个利器l不过不用着急,因为接口这个利器你还没有用上。虽然视频和音频格式不同,别忘了,他们都是媒体中的一种,很多时候,他们有许多相似的功能,比如播放。根据接口的定义,你完全可以将相同功能的一系列对象实现同一个接口:publicinterfaceIMediaabstractvoidplay();publicabstractclassAudioMediaimplementsIMediapublicabstractvoidplay();publicabstractclassVideoMediaimplementsIMediapublicabstractvoidpl
16、ay();再更改一下MediaPlayer的设计就OK了:publicclassMediaPlayerpublicvoidplay(IMediamedia)media.play();204java面向对象设计2、总结,思考l从MediaPlayer类的演变,我们可以得出这样一个结论:在调用类对象的属性和方法时,尽量避免将具体类对象作为传递参数,而应传递其抽象对象,更好地是传递接口,将实际的调用和具体对象完全剥离开,这样可以提高代码的灵活性。l不过,事情并没有完。虽然一切看起来都很完美了,但我们忽略了这个事实,就是忘记了MediaPlayer的调用者。 还记得文章最开始的switch语句吗?看起来我们已经非常漂亮地除掉了这个烦恼。事实上,我在这里玩了一个诡计,将switch语句延后了。虽然在MediaPlayer中,代码显得干净利落,其实烦恼只不过是转嫁到了MediaPlayer的调用者那里。 214java面向对象设计