面向对象多态变量_第1页
面向对象多态变量_第2页
面向对象多态变量_第3页
面向对象多态变量_第4页
面向对象多态变量_第5页
已阅读5页,还剩75页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

面向对象多态变量6/7/20231第一页,共八十页,编辑于2023年,星期二很少使用赋值,通常是伴随着函数或方法调用,通过数值和参数之间的绑定来实现的。实际用法6/7/20232第二页,共八十页,编辑于2023年,星期二简单变量接收器变量反多态纯多态(多态方法)多态变量形式6/7/20233第三页,共八十页,编辑于2023年,星期二publicclassSolitaire{ . . staticCardPileallPiles[]; . . publicvoidpaint(Graphicsg){ for(inti=0;i<13;i++) allPiles[].display(g); }}简单多态变量6/7/20234第四页,共八十页,编辑于2023年,星期二布局管理器LayoutManager是一个接口标准库为这个接口提供了几种不同的实现通过调用继承自Component类的setLayoutManager方法,将参数赋值给本地多态变量实例6/7/20235第五页,共八十页,编辑于2023年,星期二多态变量最常用的场合是作为一个数值,用来表示正在执行的方法内部的接收器。隐藏伪变量smalltalk:self,C++,Java,C#:this接收器变量6/7/20236第六页,共八十页,编辑于2023年,星期二classThisExample{ publicvoidone(intx){ value=x+4; two(x+3); } privateintvalue; privatevoidtwo(inty){ System.out.println(“Valueis”+(value+y)); }}例6/7/20237第七页,共八十页,编辑于2023年,星期二classThisExample{ publicvoidone(intx){

this.value=x+4;

this.two(x+3); } privateintvalue; privatevoidtwo(inty){ System.out.println(“Valueis”+(this.value+y)); }}等价的明确形式6/7/20238第八页,共八十页,编辑于2023年,星期二多态接收器功能的强大之处表现在消息传递与改写相结合时。这种结合是软件框架开发的关键。一般框架系统中的方法分为两大类:在父类中定义基础方法,被多个子类所继承,但不被改写;父类定义了关于多种活动的方法,但要延迟到子类才实现。

多态变量在框架中的作用6/7/20239第九页,共八十页,编辑于2023年,星期二由于基础方法被子类所继承,因此它们可以用于各个子类实例。接收器变量多态性的展现。当执行基础方法时,接收器实际上保存的是一个子类实例的数值。当执行一个改写方法时,执行的是子类的方法,而不是父类的方法。例6/7/202310第十页,共八十页,编辑于2023年,星期二classWindow{ publicvoidrepaint(){

…paint(graphicsContext);… }

abstractpublicvoidpaint(Graphicsg);privateGraphicsgraphicsContext;}classGraphicsWindowextendsWindow{ publicvoidpaint(Graphicsg){ //dotheappropriatepaintingjob }}例6/7/202311第十一页,共八十页,编辑于2023年,星期二基础方法执行延迟方法的模式。该结合允许在不修改原始代码的条件下,裁剪延迟方法以适应新的形势。是解决软件复用问题的关键。思考6/7/202312第十二页,共八十页,编辑于2023年,星期二向下造型向下造型是处理多态变量的过程,并且在某种意义上这个过程的取消操作就是替换。能够将其赋值给一个声明为子类的变量吗?该取消多态赋值的过程,也称为反多态。6/7/202313第十三页,共八十页,编辑于2023年,星期二其它例常用的数据结构:集合、堆栈、队列、列表。容器对象。可复用的软件组件。将不同的对象放入一个集合,取出时,如何知道对象的类型呢?6/7/202314第十四页,共八十页,编辑于2023年,星期二实现机制ChildaChildIf(aVariableinstanceofChild) aChild=(Child)aVariable

6/7/202315第十五页,共八十页,编辑于2023年,星期二纯多态多态方法支持可变参数的函数。支持代码只编写一次、高级别的抽象以及针对各种情况所需的代码裁剪。通常是通过给方法的接收器发送延迟消息来实现这种代码裁剪的。6/7/202316第十六页,共八十页,编辑于2023年,星期二纯多态例关于纯多态的一个简单实例就是用JAVA语言编写的StringBuffer类中的append方法。这个方法的参数声明为Object类型,因此可以表示任何对象类型。ClassStringbuffer{ Stringappend(Objectvalue){ returnappend(value,toString();}

…}方法toString被延迟实现。6/7/202317第十七页,共八十页,编辑于2023年,星期二纯多态例方法toString在子类中得以重定义。toString方法的各种不同版本产生不同的结果。所以append方法也类似产生了各种不同的结果。Append;一个定义,多种结果。6/7/202318第十八页,共八十页,编辑于2023年,星期二泛型通过类型的使用提供了一种将类或者函数参数化的方法。与通常的函数参数一样,泛型提供了一种无需识别特定数值的定义算法的方法。第18章泛型6/7/202319第十九页,共八十页,编辑于2023年,星期二泛型将名称定义为类型参数。在编译器读取类描述时,无法知道类型的属性,但是该类型参数可以像类型一样用于类定义内部。在将来的某一时刻,会通过具体的类型来匹配这一类型参数,这样就形成了类的完整声明。C++支持泛型6/7/202320第二十页,共八十页,编辑于2023年,星期二我们先来看看一个只能持有单个对象的类。6/7/202321第二十一页,共八十页,编辑于2023年,星期二在JavaSE5之前,我们可以让这个类直接持有Object类型的对象:6/7/202322第二十二页,共八十页,编辑于2023年,星期二有些情况下,我们确实希望容器能够同时持有多种类型的对象。但是,通常而言,我们只会使用容器来存储一种类型的对象。泛型的主要目的之一就是用来指定容器要持有什么类型的对象,而且由编译器来保证类型的正确性。6/7/202323第二十三页,共八十页,编辑于2023年,星期二因此,与其使用Object,我们更喜欢暂时不指定类型,而是稍后再决定具体使用什么类型。要达到这个目的,需要使用类型参数,用尖括号括住,放在类名后面。然后在使用这个类的时候,再用实际的类型替换此类型参数。在下面的例子中,T就是类型参数:6/7/202324第二十四页,共八十页,编辑于2023年,星期二6/7/202325第二十五页,共八十页,编辑于2023年,星期二现在,当你创建Holder3对象时,必须指明想持有什么类型的对象,将其置于尖括号内。就像main()中那样。然后,你就只能在Holder3中存入该类型(或其子类,因为多态与泛型不冲突)的对象了。并且,在你从Holder3中取出它持有的对象时,自动地就是正确的类型。

这就是Java泛型的核心概念:告诉编译器想使用什么类型,然后编译器帮你处理一切细节。

6/7/202326第二十六页,共八十页,编辑于2023年,星期二泛型接口泛型也可以应用于接口。例如生成器(generator),这是一种专门负责创建对象的类。6/7/202327第二十七页,共八十页,编辑于2023年,星期二我们需要IA的doSomething返回的是一个对象这个对象extends于BaseBeanInterfaceIA<TextendsBaseBean>{publicTdoSomething();}classIAImplimplementsIA<ChildBean>{publicChildBeandoSomething(){returnnewChildBean();}}这样当你调用这个实现的时候就能明确地得到返回的对象类型

6/7/202328第二十八页,共八十页,编辑于2023年,星期二Template<classT>Tmax(Tleft,Tright){ //returnlargestargument if(left<right) returnright; returnleft;}名称T是一个参数,但是它不同于函数的两个参数。在函数的代码体中,T可以用于任何合适的类型。C++模板函数6/7/202329第二十九页,共八十页,编辑于2023年,星期二代码体功能决定。并非函数头强加的本例要求可比较对T的限制?6/7/202330第三十页,共八十页,编辑于2023年,星期二Template<classT>classBox{ public: Box(Tinitial):value(initial){}

TgetValue(){returnvalue;} setValue(TnewValue){value=newValue;} private:

Tvalue;};模板类6/7/202331第三十一页,共八十页,编辑于2023年,星期二为了创建模板实例,模板参数必须与具体类型联系起来。Box(int)iBox(7);Cout<<iBox.getValue();???iBox.setValue(12);Cout<<iBox.getValue();???参数必须与接收器的类型相匹配iBox.setValue(3.1415);//ERROR,invalidtype模板类的使用6/7/202332第三十二页,共八十页,编辑于2023年,星期二模板类一般用于开发容器类Template<classT>classList{Public: voidadd(T); TfirstElement(); Tvalue;Private: List<T>*nextElement模板类的应用6/7/202333第三十三页,共八十页,编辑于2023年,星期二在不允许改变原有类的情况下,如何将来自两个或者更多个不同类的元素结合起来。例如以统一的表示方式来处理。思考?6/7/202334第三十四页,共八十页,编辑于2023年,星期二Apple类:使用printOn方法将自身输出。Orange类:使用writeTo方法将自身输出。二进制提供希望将Apple对象和Orange对象保存在同一个列表中,并且使用一个多态函数将它们输出。例6/7/202335第三十五页,共八十页,编辑于2023年,星期二定义一个公共的父类,具有共同行为ClassFruit{ public: virtualvoidprint(ostream&)=0;//纯虚方法};第一步6/7/202336第三十六页,共八十页,编辑于2023年,星期二使用模版,创建一个fruitadapter类,将以Apple或者Orange为参数,同时符合水果的定义Template<classT>ClassFruitAdapter:publicFruit{Public: FruitAdapter(T&f):theFruit(f){} T&value(){returntheFruit;} virtualvoidprint(ostream&out){print(theFruit,out);}Public: T&theFruit;}; 第二步6/7/202337第三十七页,共八十页,编辑于2023年,星期二使用模版函数简化适配器的创建过程Template<classT>Fruit*newFruit(T&f){ returnnewFruitAdapter<T>(f);}; 第三步6/7/202338第三十八页,共八十页,编辑于2023年,星期二AppleanApple(“Rome”);OrangeanOrange;List<Fruit*>fruitList;fruitList.insert(newFruit(anApple));fruitList.insert(newFruit(anOrange));List<Fruit*>::iteratorstart=fruitList.begin();List<Fruit*>::iteratorstop=fruitList.end();For(;start!=stop;++start){ Fruit&aFruit=*start;aFruit.print(cout);}最终方案6/7/202339第三十九页,共八十页,编辑于2023年,星期二对于一类相似问题的骨架解决方案。通过类的集合形成,类之间紧密结合,共同实现对问题的可复用解决方案继承和改写的强大能力体现最常见的框架Java中的GUI框架Web开发中的Struts框架第21章框架6/7/202340第四十页,共八十页,编辑于2023年,星期二框架开发的一个重要基础使用继承的两种方式:代码复用:基本方法,对问题的现存的解决方案。概念复用:特化方法,用于特定应用的解决方案。复用和特化6/7/202341第四十一页,共八十页,编辑于2023年,星期二例:雇员排序。高级抽象和低级抽象6/7/202342第四十二页,共八十页,编辑于2023年,星期二classEmployee{public: stringname; intsalary; intstartingYear; }雇员类6/7/202343第四十三页,共八十页,编辑于2023年,星期二voidsort(Employee*data[],intn){ for(inti=1;i<n;i++){ intj=i-1; while(j>=0&& v[j+1]->startingYear<v[j]->startingYear){ //swapelements Employee*temp=v[j]; v[j]=v[j+1]; v[j+1]=temp; j=j-1; } }}插入排序-根据工作年份6/7/202344第四十四页,共八十页,编辑于2023年,星期二按照薪水排序?按照姓名排序?不再对雇员记录排序,对一个浮点数组排序?思考6/7/202345第四十五页,共八十页,编辑于2023年,星期二源代码级的修改。复用的是排序的思想,不是真正的实现。观察6/7/202346第四十六页,共八十页,编辑于2023年,星期二需要源代码级的修改的地方?元素类型、元素数目、数值比较、元素交换。封装改变OO方案6/7/202347第四十七页,共八十页,编辑于2023年,星期二classInsertionSorter{public: voidsort(){ intn=size(); for(inti=1;i<n;i++){ intj=i-1; while(j>=0&&lessThan(j+1,j)){

swap(j,j+1); j=j-1; } } }OO方案-排序框架6/7/202348第四十八页,共八十页,编辑于2023年,星期二private: virtualintsize()=0;//abstractmethods virtualbooleanlessThan(inti,intj)=0; virtualvoidswap(inti,intj)=0;}OO方案-排序框架6/7/202349第四十九页,共八十页,编辑于2023年,星期二classEmployeeSorter:publicInsertionSorter{public: EmployeeSorter(Employee*d[],intn) {data=d;sze=n;}private: Employee*data[]; intsze=n; virtualintsize(){returnsze;} virtualboollessThan(inti,intj) {returndata[i]->startingYear<data[j]->startingYear;}OO方案-特化6/7/202350第五十页,共八十页,编辑于2023年,星期二 virtualvoidswap(inti,intj){ Employee*temp=v[i]; v[i]=v[j]; v[j]=temp; }}OO方案-特化6/7/202351第五十一页,共八十页,编辑于2023年,星期二基类不再需要改变。特化子类满足不同的需求。如:改变为对收入进行排序只需改变子类,无需改变父类对浮点数进行排序也只需创建一个新的子类,而无需改变父类观察6/7/202352第五十二页,共八十页,编辑于2023年,星期二继承允许进行高级别算法细节的封装还允许在不改变原始代码的情况下修改或特化这些细节。继承6/7/202353第五十三页,共八十页,编辑于2023年,星期二框架改变了应用程序(开发者定义的代码)与库代码之间的关系传统的应用程序中应用程序特定的代码定义了程序执行的总体流程在框架中控制流是由框架决定的,并且随应用程序的不同而不同新的应用程序的创建者只需改变供框架调用的例程即可,而无需改变总体结构.框架占主导地位,而应用程序特定的代码处于次要位置.倒置库6/7/202354第五十四页,共八十页,编辑于2023年,星期二面向对象设计艺术为应用程序预言将来可能发生的变化,并对应用程序进行相应的设计做到这点不容易,需要程序员认识到可以通过类似于以前解决问题的方式或者现存软件系统的方式来解决新问题时,才能够将该问题泛化,使其适合于更广泛的应用程序象C++,需要程序员区分哪些方法可以改写,以及哪些方法不能改写,这种方式过于僵硬了由于程序员在最初无法预言改写某个方法的需求预言变化6/7/202355第五十五页,共八十页,编辑于2023年,星期二多个代理组成的团体?对象绑定到一起的连接特性?第23章对象互连6/7/202356第五十六页,共八十页,编辑于2023年,星期二一种考虑对象互连的方式就是研究可视性和依赖性这两个概念。可视性描述了关于名称的特性,通过该名称句柄可以存取对象,如果对象的名称是合法的且代表该对象,那么在这个特定环境下该对象就是可见的。描述可视性的相关术语还包括标识符的范畴依赖性将两个对象或者类联系起来,在不存在另外一个对象的条件下,如果一个对象的存在无任何意义,就说该对象依赖于另外那个对象。例如:子类几乎总是依赖于它的父类对象互连6/7/202357第五十七页,共八十页,编辑于2023年,星期二耦合(coupling)和内聚(cohesion)的思想提供了一个框架,用于评价对象和类的应用是否有效。耦合描述类之间的关系,内聚描述类内部的关系。耦合和内聚6/7/202358第五十八页,共八十页,编辑于2023年,星期二从最差的耦合到较好的耦合:内部数据耦合全局数据耦合控制(或顺序)耦合组件耦合参数耦合子类耦合耦合的种类6/7/202359第五十九页,共八十页,编辑于2023年,星期二内部数据耦合发生在当一个类的实例直接修改另外一个类中的本地数据值(实例变量)时。ClassSneakyModifier{ public:voidsneaky(){ //changemyfriendsname myFriend->name=“Lucy”; } Person*myFriend;};ClassPerson{ public:Person(){ name=“Larry”; } stringname;};内部数据耦合6/7/202360第六十页,共八十页,编辑于2023年,星期二全局数据耦合发生在两个或者更多个类型都依赖于公用的全局数据结构而绑定到一起的时候。DoubletodaysDow;ClassOne{ public:voidsetDow(){ todayDow=9473; }}ClassTwo{ public:voidprintDow(){ cout<<“TodaytheDowhit”<<todaysDow; }};全局数据耦合6/7/202361第六十一页,共八十页,编辑于2023年,星期二一个类必须以一种由任何位置控制的特定的顺序来执行操作。classMyClass{public: doFirst(){...} doSecond(){...} doThird(){...}}控制或者顺序耦合6/7/202362第六十二页,共八十页,编辑于2023年,星期二被顺序化的类应确保自身能够以正确的顺序实现操作,不应仅依赖于调用者的正确处理classMyClass{public: doStuff(){ doFirst(); doSecond(); doThird(); }protected: doFirst(){...} doSecond(){...} doThird(){...}}控制或者顺序耦合6/7/202363第六十三页,共八十页,编辑于2023年,星期二组件耦合发生在一个类包含的数据字段或数值为另外一个类的实例时ClassSet{ . . private: Listdata;};组件耦合6/7/202364第六十四页,共八十页,编辑于2023年,星期二参数耦合发生在一个类必须调用另外一个类的服务和例程时,此时两个类之间所发生的唯一关系就是一个类需要为另一个类提供参数数目、类型和返回值类型。ClassmyClass{ public: voiddoSomething(Setaset){ //dosomethingusingtheargumentvalue . }}参数耦合6/7/202365第六十五页,共八十页,编辑于2023年,星期二子类耦合是面向对象编程所特有的,描述了一个类与其父类之间的关系。通过继承,子类的实例可以被看成父类的实例。ClassParent{ . .}ClassChildextendsParent{ . .}子类耦合6/7/202366第六十六页,共八十页,编辑于2023年,星期二类的内部内聚性是该结构中各个元素之间绑定程度的量度。内聚6/7/202367第六十七页,共八十页,编辑于2023年,星期二从最弱的内聚到最强的内聚:随机内聚:对程序随意划分逻辑内聚:算术函数库时间内聚:如实现程序初始化的类通信内聚:数据或者设备的manager顺序内聚:避免顺序耦合功能内聚:类中元素通过执行特定功能关联起来数据内聚:数据结构内聚的种类6/7/202368第六十八页,共八十页,编辑于20

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论