【大学课件】C网络编程技术教程

上传人:m**** 文档编号:568549398 上传时间:2024-07-25 格式:PPT 页数:53 大小:416.52KB
返回 下载 相关 举报
【大学课件】C网络编程技术教程_第1页
第1页 / 共53页
【大学课件】C网络编程技术教程_第2页
第2页 / 共53页
【大学课件】C网络编程技术教程_第3页
第3页 / 共53页
【大学课件】C网络编程技术教程_第4页
第4页 / 共53页
【大学课件】C网络编程技术教程_第5页
第5页 / 共53页
点击查看更多>>
资源描述

《【大学课件】C网络编程技术教程》由会员分享,可在线阅读,更多相关《【大学课件】C网络编程技术教程(53页珍藏版)》请在金锄头文库上搜索。

1、1 1C#C#网络编程技术教程网络编程技术教程第三章 C#面向对象编程 http:/ 3章章 C C# #面面向向对对象象编编程程2 2学习目标学习目标理解面向对象的基本概念。理解面向对象的基本概念。了解基本的面向对象分析、设计方法,主要是了解基本的面向对象分析、设计方法,主要是UMLUML中的类图和序列图。中的类图和序列图。掌握掌握C#C#中类的定义和实例化方法。中类的定义和实例化方法。掌握掌握C#C#中继承、多态、接口的实现方法。中继承、多态、接口的实现方法。第第3 3章章 C C# #面面向向对对象象编编程程3 3本章内容本章内容3.1 3.1 面向对象的基本概念面向对象的基本概念 3.

2、2 3.2 类和对象类和对象 3.3 3.3 字段字段 3.4 3.4 方法方法 3.5 3.5 属性与索引属性与索引 3.6 3.6 委托与事件委托与事件 3.7 3.7 继承与多态继承与多态 3.8 3.8 基于基于UMLUML的系统分析与设计方法的系统分析与设计方法 第第3 3章章 C C# #面面向向对对象象编编程程4 43.1 3.1 面向对象的基本概念面向对象的基本概念 客观世界是由各种各样的对象组成的,如汽车、飞机、火车、人等。每种对象都有各自的内部状态和运动规律,不同对象之间的相互作用和联系就构成了各种不同的系统。将客观世界中的对象模型化,形成一种计算机化的表示,并以此为基础来

3、分析和解决问题便形成了面向对象技术。PeterCoad和EdwardYourdon提出了下列等式来说明面向对象技术。面向对象=对象+分类+继承+消息通信可以说,采用对象、类、继承、消息这4个概念开发的软件系统是面向对象的。第第3 3章章 C C# #面面向向对对象象编编程程5 53.1 3.1 面向对象的基本概念面向对象的基本概念 1对象在面向对象技术中,任何客观事物都是对象,对象是对客观事物的抽象。任何复杂的事物都可以通过对象的某种组合结构构成。复杂对象可由相对比较简单的对象以某种方式组成。对象由属性和方法组成。属性反映了对象的信息特征,而方法则定义改变属性状态的各种操作。因此,对象是属性和

4、方法的一个封装体。通过封装可以更好地隐蔽对象的内部细节,只保留有限的对外接口实现对外联系。每个对象都有自身唯一的标识,通过这种标识,可找到相应的对象。在对象的整个生命期中,它的标识都不改变,不同的对象不能有相同的标识。2类具有相同属性和方法的对象可归纳成类,对象是类的一个实例,而对象的抽象是类。类具有属性,它是对象的状态的抽象,用数据结构来描述类的属性;类具有操作,它是对象的行为的抽象,用操作名和实现该操作的方法来描述。第第3 3章章 C C# #面面向向对对象象编编程程6 63.1 3.1 面向对象的基本概念面向对象的基本概念 3继承类有一定的结构,可以派生出子类,子类除了继承父类的属性和方

5、法外还可以有自己的属性和方法。对象和类之间的层次结构靠继承关系维系。继承是子类自动共享父类数据结构和方法的机制,也是面向对象程序设计语言不同于其他语言的最重要的特点。在类层次中,将子类只继承一个父类的数据结构和方法的方式称为单重继承;将子类继承多个父类的数据结构和方法的方式称为多重继承。在软件开发中,类的继承使所建立的软件具有开放性、可扩充性,这是信息组织与分类的行之有效的方法,它简化了对象、类的创建工作量,增加了代码的重用性。同时,通过类的继承关系,使公共的特性能够共享,提高了软件的重用性。4消息对象之间的联系主要是通过传递消息来实现,消息传递是对象间通信的手段,一个对象通过向另一个对象发送

6、消息来请求其服务。一个消息通常包含接收对象的标识、发送给接收对象的消息名(方法名)和适当的参数。消息只告诉接收对象需要完成什么操作,但并不指示接收者如何完成操作。消息完全由接收者解释,并由其独立决定采用什么方法完成所需的操作。第第3 3章章 C C# #面面向向对对象象编编程程7 73.1 3.1 面向对象的基本概念面向对象的基本概念 5多态性多态性是指相同的操作或方法可作用于多种类型的对象上并获得不同的结果。即将不同的对象收到同一消息时产生不同的结果的现象称为多态性。多态性允许每个对象以适合自身的方式去响应共同的消息,增强了软件的灵活性和重用性。面向对象技术正是利用对现实世界中对象的抽象和对

7、象之间的相互关联和相互作用的描述来模拟现实世界,并且使其映射到目标系统中。第第3 3章章 C C# #面面向向对对象象编编程程8 83.2 3.2 类和对象类和对象 类是对象的抽象描述,类似于模板。从定义上来说,类是一种复杂的数据结构,其中包含数据成员和功能成员。在C#中,类必须先定义后使用。1类的定义类是C#中最基础的类型。类是一个数据结构,将数据成员(状态)和功能成员(行为)组合在一个单元中,进而体现了面向对象技术的封装性。类的定义格式如下:Attribute类修饰符class类名:基类和实现的接口列表类成员定义其中,类的修饰符如下表所示。修饰符描述none、internal类只能在当前项

8、目中访问public类可以在任何地方访问abstract、internalabstract类只能在当前项目中访问,且不能实例化,只能继承publicabstract类可以在任何地方访问,且不能实例化,只能继承sealed、internalsealed类只能在当前项目中访问,且只能实例化,不能继承publicsealed类可以在任何地方访问,且只能实例化,不能继承第第3 3章章 C C# #面面向向对对象象编编程程9 93.2 3.2 类和对象类和对象 下面是一个名为Point的简单类的声明。publicclassPointprivateintx,y;/数据成员publicPoint(intx,

9、inty)/功能成员this.x=x;this.y=y;第第3 3章章 C C# #面面向向对对象象编编程程10103.2 3.2 类和对象类和对象 2类的成员类的成员分为数据成员和功能成员,其中数据成员包括:成员常量,代表与类相关的常数数据;字段,类的变量。功能成员包括:方法,即类中的成员函数;属性,定义了命名的属性以及读写属性的相关的行为;索引,允许类的实例通过与数组相同的方法来索引;操作符,定义了可以用于类的实例上的表达式操作;事件,定义了由类产生的事件公告;构造函数,对类的实例进行初始化的操作;析构函数,在类的实例销毁前执行与资源释放相关的操作。3类成员的可访问性类的每个成员都有关联的

10、可访问性,它控制能够访问该成员的程序区域。在C#中,有5种可能的可访问性,如下表所示。可访问性描述public访问不受限制,定义的成员可以在类的外部访问protected访问仅限于包含类或从包含类派生的类internal访问仅限于当前程序集(包)protectedinternal访问仅限于从包含类派生的当前程序集(包)或类private访问仅限于包含类第第3 3章章 C C# #面面向向对对象象编编程程11113.2 3.2 类和对象类和对象 4静态成员和非静态成员类的成员可以是静态成员,也可以是非静态成员。在C#中,用关键字static修饰的类成员(包括字段、方法、属性、事件、操作符或构造函

11、数)称为静态成员,它们属于类。而没有用关键字static修饰的类成员称为非静态成员,它们属于对象。静态成员具有如下特征。一个静态字段对应一个存储位置,不管其包含类创建了多少个实例,总是只有一个静态字段的备份。静态成员(包括方法、属性、事件、操作符或构造函数)不会对非静态成员进行操作,也不能使用this。静态成员属于类,因此可以在包含类的实例之间共享它们。静态成员一般通过类来访问,例如Console.ReadLine(),其中ReadLine()就是类Console中的静态方法。对于非静态字段,在包含类的每个实例中都包括一个它的独立备份,同时在非静态成员中可以使用this,也可以对非静态成员进行

12、操作。非静态成员通过包含类的实例来访问。第第3 3章章 C C# #面面向向对对象象编编程程12123.2 3.2 类和对象类和对象 5对象对象是类的实例。与C+不同,在C#中,类是一种引用类型,因此在C#中不能直接用类来定义对象,它定义的只是一个对象引用变量。一般可以使用new运算符动态创建一个对象,再将其赋值给一个对象引用变量。例如:Pointp1=newPoint(0,0);/指向一个动态创建的Point对象Pointp2=p1;/p1和p2指向同一个Point对象Pointp3;/不指向任何对象当不再使用对象时,该对象所占的内存将被自动回收。在C#中,没有必要也不可能显式地释放对象。而

13、是通过系统中的垃圾回收器来实现对无用对象的回收操作。6构造函数与析构函数C#既支持实例构造函数,也支持静态构造函数。实例构造函数用来初始化类实例中的数据成员。静态构造函数用来在类首次加载时初始化类本身的数据成员,即静态字段。构造函数的名称与类名相同,没有返回类型。若构造函数的声明中包含static修饰符,则它声明了一个静态构造函数,否则声明的是实例构造函数。静态构造函数不需要访问修饰符,同时也不带任何参数;实例构造函数可以带参数表,可以加访问修饰符进行修饰,不能被继承。如果一个类没有声明任何实例构造函数,则会自动为它提供一个默认的空的实例构造函数,一般其参数列表为空,函数体也为空。第第3 3章

14、章 C C# #面面向向对对象象编编程程13133.2 3.2 类和对象类和对象 由于实例构造函数可以带参数,因此实例构造函数可以重载,并且可以通过参数列表(参数的个数、类型和顺序)来区分不同的实例构造函数。析构函数是用于实现析构类实例所需操作的成员。析构函数不能带参数,不能具有可访问性修饰符,也不能被显式地调用。当没有任何代码要使用一个实例时,系统中的垃圾回收器会自动调用该实例的析构函数对其进行析构,如代码实例所示。usingSystem;namespaceex_3_1classProgramprivateintdata;/非静态数据成员(字段)staticprivateintstaticd

15、ata;/静态数据成员publicProgram()/无参数实例构造函数Console.WriteLine(无参数构造函数);data=0;publicProgram(intvalue)/带参数实例构造函数Console.WriteLine(带参数构造函数);data=value;staticProgram()/静态构造函数Console.WriteLine(静态构造函数);staticdata=100;Program()/析构函数Console.WriteLine(析构函数);publicvoidPrint()/打印方法Console.WriteLine(Staticdatais0,Data

16、is1,staticdata,data);staticvoidMain(stringargs)Programp1;/没有创建对象Programp2=newProgram();/创建一个对象Programp3=newProgram(50);/创建一个对象p1=p3;p1.Print();p2.Print();p3.Print();第第3 3章章 C C# #面面向向对对象象编编程程14143.3 3.3 字段字段 字段,即类的变量,类中的数据成员,用来存储类所需的数据信息。它可以声明为静态的,也可以声明为只读的(readonly)。当字段被声明为只读时与声明为const的效果是一样的,区别在于只

17、读型表达式在程序运行时形成,而const型表达式的值在编译时形成。只读型字段可以通过构造函数赋值,但实例创建后则不能再对其进行赋值。字段声明的格式如下:修饰符字段类型字段名列表;其中修饰符可以是public、protected、internal、private、static和readonly;字段类型可以是基本类型、用户自定义类型和其他类。例如:classCalendarDatepublicreadonlyintmonth;/只读字段,实例创建后不能对其赋值publicintday;publicstaticintyear=2005;/静态字段,属于类的成员虽然字段是一种类变量,但是C#为每个未

18、初始化的变量都确认一个默认值,因此字段声明后便可以使用。这在一定程度上保证了程序的安全性。如下代码实例所示为字段使用的程序实例。第第3 3章章 C C# #面面向向对对象象编编程程15153.3 3.3 字段字段 usingSystem;namespaceex_3_2classProgrampublicreadonlyintmonth;publicintday;publicstaticintyear=2005;publicProgram()/无参数的构造函数publicProgram(intd,intm,inty)/构造函数中可以对只读型字段赋值day=d;month=m;year=y;pub

19、licvoidPrint()Console.WriteLine(Yearis0,Monthis1,Dayis2,year,month,day);staticvoidMain(stringargs)Programp1=newProgram(10,10,2005);Programp2=newProgram();/字段具有默认值p1.Print();p2.Print();p1.day=11;/p1.month=11;/错误,只读型字段不能修改p1.Print();第第3 3章章 C C# #面面向向对对象象编编程程16163.4 3.4 方法方法 方法是一种用于实现可以由对象或类执行的计算或操作的功

20、能成员。与C+中的函数成员类似,方法可以是静态也可以是非静态。静态方法只能通过类来访问,非静态方法(即实例方法)则要通过类的实例访问。方法有一个参数表(可能为空),表示传递给方法的值或者引用;方法还有返回类型,用于指定由该方法计算和返回的值的类型。如果方法不返回值,则它的返回类型为void。方法的声明格式如下:修饰符返回类型方法名称(参数列表)方法体其中,方法的名称、参数个数、参数顺序、每个参数的修饰符和类型一起组成方法的签名。在声明方法的类中,该方法的签名必须是唯一的。正因为方法可以带参数,所以类中的方法可以重载,重载方法的签名不同,主要是参数个数、参数类型和参数顺序不同。第第3 3章章 C

21、 C# #面面向向对对象象编编程程17173.4 3.4 方法方法 在C#中,方法中的参数用于将值或者引用变量传递给方法体。当方法被调用时,方法的参数从指定的自变量得到它们实际的值。C#中有4种参数:值参数、引用参数、输出参数和参量参数。值参数:用于输入参数的传递。值参数相当于一个局部变量,它的初始值是从实参获得的。对值参数的修改不会影响其对应的实参。引用参数:用于输入和输出数据的传递。引用参数对应的实参必须是一个变量,并且在方法执行期间,引用参数和其实参指向同一个存储空间,因此,引用参数值的变化将直接影响其实参。引用参数用ref修饰符声明。输出参数:用于输出数据的传递。输出参数类似于引用参数

22、,不同之处在于实参有无初始值无关紧要。输出参数用out修饰符声明。参量参数:可以把一维数组或不规则数组传递给方法。在方法声明的参数列表中,参量参数必须以params开始,例如:publicintsum(paramintintParams)方法体。在带参量参数的方法调用中,既可以传递数组类型的单个实参,也可以传递充当数组元素的若干实参。对于后一种的情形,数组实例将自动被创建,并且通过给定的实参初始化。第第3 3章章 C C# #面面向向对对象象编编程程18183.4 3.4 方法方法 usingSystem;namespaceex_3_3classFunc_Exstaticprivateinto

23、bject_num=0;/静态字段publicintx,y,xy;privateintm_sum;publicFunc_Ex(inta,intb)/构造函数x=a;y=b;object_num+;/统计对象实例个数publicvoidswap(inta,intb)/值参数inttemp;temp=a;a=b;b=temp;publicvoidswap(refinta,refintb,outints)/引用参数,输出参数inttemp;temp=a;a=b;b=temp;s=a+b;publicvoidsum(paramsintintparams)/参量参数m_sum=0;foreach(int

24、vinintparams)m_sum+=v;publicvoidprint()/实例方法Console.WriteLine(x=0,y=1,xy=2,sum=3,x,y,xy,m_sum);staticpublicvoidprintObjectNum()/静态方法Console.WriteLine(已创建的对象个数为0,object_num);staticvoidMain(stringargs)Func_Exf1=newFunc_Ex(10,20);Func_Ex.printObjectNum();f1.print();/静态方法调用f1.swap(f1.x,f1.y);/*值参数的方法调用*

25、/f1.print();f1.swap(reff1.x,reff1.y,outf1.xy);/*引用和输出参数的方法调用*/f1.print();Func_Exf2=newFunc_Ex(100,220);Func_Ex.printObjectNum();/*静态方法调用*/f2.print();f2.sum(10,20,30,45);/*参量参数的方法调用*/f2.print();inta=1,3,5,7,9,11,23;f2.sum(a);/*参量参数的方法调用*/f2.print();第第3 3章章 C C# #面面向向对对象象编编程程19193.5 3.5 属性与索引属性与索引 3.5

26、.1属性属性是对对象或类的字段进行特定访问的成员,是字段的自然扩展,并且访问属性和字段的语法相同。在C#中属性与字段完全相同,属性不表示存储位置。而且属性有访问器,通过这些访问器可以实现对相关字段值(或计算值)的访问。在C#中,属性的声明格式如下:修饰符类型属性名get执行代码;return表达式;set执行代码get访问器和set访问器的功能如下。get访问器相当于一个具有属性类型返回值的无参数方法。当在表达式中引用属性时,会调用该属性的get访问器来计算该属性的值。set访问器相当于一个具有单个名为value的参数和无返回类型的方法。当属性作为赋值运算的左值表达式或者作为+或运算符的操作数

27、被引用时,就会调用set访问器来修改相应字段中的值。第第3 3章章 C C# #面面向向对对象象编编程程20203.5 3.5 属性与索引属性与索引 3.5.1属性两种访问器都包含的属性称为读写属性,只具有get访问器的属性称为只读属性,只具有set访问器的属性称为只写属性。与字段和方法类似,属性可以被定义为实例属性和静态属性。静态属性的声明中具有static修饰符,而实例属性则没有,静态属性只能访问静态成员。属性的访问器可以是虚拟的。当属性声明中包含virtual、abstract、override修饰符时,它们将运用到属性访问器。但是,与字段或方法不完全相同,属性声明时需要注意如下几点属性

28、不能声明为const,也不能在一个表达式声明多个属性。不能通过set访问器对属性进行初始化。属性不属于变量,不能将属性作为引用参数或输出参数传递。属性必须有返回类型,并且不能为void型。在属性声明中,除了get和set访问器外,不能进行其他任何操作。第第3 3章章 C C# #面面向向对对象象编编程程21213.5 3.5 属性与索引属性与索引 3.5.2索引索引是这样一个成员,它使对象能够用与数组相同的方式进行索引。索引的声明与属性很相似,不同之处在于成员的名字是this,后面的参数列表在定界符“”之间。参数在索引的访问器中是可用的。索引的声明形式如下:修饰符类型this类型indexge

29、t执行代码;/主要是对index值指定的相应数组字段的某个元素进行访问return表达式;set执行代码;/主要是对index值指定的相应数组字段的某个元素进行访问如果包含get和set访问器,则该索引是读写索引;如果只包含get访问器则是只读索引;而只包含set访问器则是只写索引。注意:索引主要是用来通过数组下标的方式操作对象实例中的某个数组型字段成员的数组元素,而不是对象实例数组。第第3 3章章 C C# #面面向向对对象象编编程程22223.5 3.5 属性与索引属性与索引 usingSystem;namespaceEx_3_4classNameListprivatestringname

30、list;/名称数组privatereadonlyintMaxLength;/数组最大长度privateintnamecount=0;/数组当前长度staticprivateintnamelistcount=0;/实例个数privatestringnamelisttile;/名称标题字段publicNameList(intmaxlength)/构造函数MaxLength=maxlength;namelist=newstringMaxLength;namecount=0;namelistcount+;staticpublicintNameListCount/静态属性getreturnnameli

31、stcount;publicstringNameListTile/读写属性getreturnnamelisttile;setnamelisttile=value;publicintMAXLength/只读属性getreturnMaxLength;publicintCount/只读属性getreturnnamecount;publicstringthisintindex/读写索引getif(index=0)&(index=0)&(indexnamecount)namelistindex=value;publicvoidAddName(stringv)/方法if(namecountMaxLengt

32、h)namelistnamecount+=v;publicvoidPrintNamelist()/方法Console.WriteLine(NameListTileis0,namelisttile);for(inti=0;inamecount;i+)Console.WriteLine(tNamelist0is1,i,namelisti);第第3 3章章 C C# #面面向向对对象象编编程程23233.5 3.5 属性与索引属性与索引staticvoidMain(stringargs)/测试代码NameListnl1=newNameList(20);/创建两个对象NameListnl2=newNa

33、meList(10);nl1.NameListTile=NameBook1;for(inti=0;i10;i+)nl1.AddName(Name+i.ToString();nl2.NameListTile=NameBook2;for(inti=0;i5;i+)nl2.AddName(Book+i.ToString();nl20=ITBook_0;/通过索引设置实例的值nl21=ITBook_1;nl1.PrintNamelist();Console.WriteLine(NameList2Titleis0,nl2.NameListTile);for(intk=0;kemp2.m_age)?tru

34、e:false;staticpublicboolSalaryIsGreater(objecte1,objecte2)Employeeemp1=(Employee)e1;Employeeemp2=(Employee)e2;return(emp1.m_salaryemp2.m_salary)?true:false;classTeststaticpublicvoidSort(objectsortArray,CompareOpgtMethod)/使用委托做函数参数for(inti=0;isortArray.Length;i+)for(intj=i+1;jsortArray.Length;j+)if(g

35、tMethod(sortArrayj,sortArrayi)objecttemp=sortArrayi;sortArrayi=sortArrayj;sortArrayj=temp;第第3 3章章 C C# #面面向向对对象象编编程程27273.6 3.6 委托与事件委托与事件 3.6.1委托staticvoidMain(stringargs)Employeeemployees=newEmployee(Wang,20,1000),newEmployee(Li,23,2001),newEmployee(Xu,34,2500),newEmployee(Liu,56,3000),newEmployee

36、(Zhang,45,2300),newEmployee(Yuan,67,5000);CompareOpCompareByAge=newCompareOp(Employee.AgeIsGreater);/定义委托实例CompareOpCompareBySalary=newCompareOp(Employee.SalaryIsGreater);/定义委托实例Console.WriteLine(Sortedbyage:);Sort(employees,CompareByAge);/委托实例作实参for(inti=0;iemployees.Length;i+)employeesi.Print();Co

37、nsole.WriteLine(Sortedbysalary:);Sort(employees,CompareBySalary);/委托实例作实参for(inti=0;iemployees.Length;i+)employeesi.Print();第第3 3章章 C C# #面面向向对对象象编编程程28283.6 3.6 委托与事件委托与事件 3.6.2事件事件是使对象或类能够提供通知的成员。如果将某个为用户提供服务的类称为服务类,使用服务的类称为客户类,则事件提供了一种在客户类中扩展服务类的某个功能的机制,即在客户类中可以定义事件响应函数。例如,在Windows程序中,窗口是一个对象,当用户

38、在其中单击按钮、按下按键、最大化或最小化窗口时都会激发响应事件,并且用户可以为该响应事件添加执行代码。在C#中,事件机制的实现主要包括声明事件、激活事件、声明事件响应函数、订阅事件等步骤,其中声明事件、激活事件在提供事件通知的服务类中实现,而声明事件响应函数和订阅事件则在使用服务类的客户类中实现。1声明事件事件的声明通过委托来实现,先定义委托,再用委托声明事件,并且通过委托将事件响应函数关联到事件中。激发事件的时候通过调用委托实现对事件响应函数的调用。因此事件可以看成是一种特殊的委托,其声明格式如下:修饰符event类型事件名;其中类型必须是委托类型。例如:publicdelegatevoid

39、AlarmEventHandle(objectsender,stringmsg);/声明委托publiceventAlarmEventHandleAlarm;/定义事件事件的声明与字段的声明类似,不同之处在于事件声明包含一个event关键字,并且事件声明的类型必须是委托类型。在包含事件声明的类中,事件可以像委托类型的字段一样使用。第第3 3章章 C C# #面面向向对对象象编编程程29293.6 3.6 委托与事件委托与事件 3.6.2事件2激活事件当事件激活条件满足并且事件已经与某个事件响应函数关联时便可以激活事件,即通过委托实例调用委托函数,如下:if(m_currentTime=m_al

40、armTime)&(Alarm!=null)Alarm(this,定时时间到!);/条件满足时激活事件3订阅事件订阅事件就是实现事件与事件响应函数的关联,即委托实例与委托函数的关联。在C#中通过“+=”操作符实现事件与事件响应函数的关联,通过“-=”操作符将事件与已关联的事件响应函数去除关联,如下:t1.Alarm+=newAlarmEventHandle(OnAlarm);/事件响应函数与事件关联t1.Alarm-=newAlarmEventHandle(OnAlarm);/去掉事件响应函数与事件的关联如果事件没有实现与事件响应函数的关联则其值为null。第第3 3章章 C C# #面面向向

41、对对象象编编程程30303.6 3.6 委托与事件委托与事件 3.6.2事件4声明事件响应函数事件响应函数是客户类在接收到服务类的事件通知后进行响应处理的函数,类似于回调函数。因此通过事件响应函数可以在客户类中扩展服务类的某个功能。事件响应函数是委托实例的关联函数,因此其签名应与事件的签名一致。下面的OnAlarm函数便是事件Alarm的事件响应函数。staticpublicvoidOnAlarm(objectsender,stringmsg)/声明事件响应函数Console.WriteLine(Alarmmessageis0,msg);事件机制的使用如代码实例3.6所示。该实例中定义了一个定

42、时器类Timer,当定时事件与当前时间一致时将通知客户程序,并通过与Alarm事件关联的事件响应函数进行处理。而在测试类Test中定义了Timer类的对象,并将已定义好的事件响应函数与事件Alarm实现关联,同时也测试了去掉关联后的运行效果。第第3 3章章 C C# #面面向向对对象象编编程程31313.6 3.6 委托与事件委托与事件 3.6.2事件usingSystem;namespaceEx_3_6publicdelegatevoidAlarmEventHandle(objectsender,stringmsg);/声明委托classTimerprivateDateTimem_curre

43、ntTime,m_alarmTime;/定义字段publiceventAlarmEventHandleAlarm;/定义事件publicTimer(DateTimect,DateTimeat)m_currentTime=ct;m_alarmTime=at;publicDateTimeCurrentTimegetreturnm_currentTime;setm_currentTime=value;if(m_currentTime=m_alarmTime)&(Alarm!=null)Alarm(this,定时时间到!);/条件满足时激活事件第第3 3章章 C C# #面面向向对对象象编编程程323

44、23.6 3.6 委托与事件委托与事件 3.6.2事件publicDateTimeAlarmTimegetreturnm_alarmTime;setm_alarmTime=value;if(m_currentTime=m_alarmTime)&(Alarm!=null)Alarm(this,定时时间到!);/条件满足时激活事件classTeststaticpublicvoidOnAlarm(objectsender,stringmsg)/声明事件响应函数Console.WriteLine(Alarmmessageis0,msg);staticvoidMain(stringargs)DateTi

45、mealarmtime=DateTime.Parse(6/2/200821:30:00);Timert1=newTimer(DateTime.Now,alarmtime);t1.Alarm+=newAlarmEventHandle(OnAlarm);/事件响应函数与事件关联t1.CurrentTime=alarmtime;/将激活事件响应函数t1.Alarm-=newAlarmEventHandle(OnAlarm);/去掉事件响应函数与事件的关联t1.CurrentTime=alarmtime;/事件响应函数为空,不作处理第第3 3章章 C C# #面面向向对对象象编编程程33333.7 3

46、.7 继承与多态 3.7.1继承现实世界中实体之间不是相互孤立的,它们往往具有共同的特征,也有着内在的差别。人们可以采用层次结构来抽象描述这些实体之间的相同之处和不同之处,如图3.3所示的交通工具的分类。为了用程序语言对现实世界中的层次结构进行模型化,面向对象技术引入了继承的概念,一个类可以从另一个类派生出来,派生类继承了基类的相应特性,同时,派生类也可以作为其他类的基类,进而实现类间的层次继承关系。因此,继承是一种共性的抽象机制。图3.3交通工具的分类第第3 3章章 C C# #面面向向对对象象编编程程34343.7 3.7 继承与多态 3.7.1继承1继承的定义C+中,派生类可以继承一个基

47、类或多个基类的特性,而在C#中,派生类只能从一个类中继承。派生类的声明格式如下:修饰符class派生类名:基类名派生类成员派生类能从它的直接基类中继承的成员包括方法、字段、属性、事件、索引,即除了构造函数和析构函数,派生类隐式地继承了直接基类的所有成员。在C#中,关于继承需要注意以下几个重要规则。继承是可传递的。如果C从B中派生,B又从A中派生,那么C不仅继承了B中声明的成员,而且继承了A中的成员。派生类应当是对基类的扩展。派生类可以添加新的成员,但不能除去已经继承的成员的声明。构造函数和析构函数不能被继承。除此之外的其他成员,不论对它们声明了怎样的访问方式,都能被继承。基类中成员的访问方式只

48、能决定派生类能否访问它们。派生类如果声明了与继承而来的成员同名的新成员,就可以覆盖已继承的成员。但这并不意味着派生类删除了这些成员,只是不能再访问这些成员。类可以声明虚方法、虚属性,以及虚索引,它的派生类能够重载这些成员,从而实现类的多态性。第第3 3章章 C C# #面面向向对对象象编编程程35353.7 3.7 继承与多态 3.7.1继承2覆盖在派生类的成员声明中,可以声明与继承而来的成员同名的成员,并且使用相同的签名。这时我们称派生类的成员覆盖了基类的成员。在C#中,要实现覆盖的成员,一般在基类中将其声明为virtual或override,而派生类中覆盖成员声明为override。即基类

49、中的virtual成员在派生类中可以覆盖,基类中的覆盖成员在派生类中可以进一步声明为覆盖成员。其中用virtual修饰的成员称为虚成员,而用override修饰的成员称为覆盖成员。如下所示:classShapevirtualpublicvoidPrint()/虚方法Console.WriteLine(Shapeis0,name);classLineClass:ShapepublicoverridevoidPrint()/覆盖方法base.Print();Console.WriteLine(tShapetypeisLine,Lengthis0,Length);如果基类中的成员在派生类中被覆盖了,

50、则在派生类中直接用该成员名访问的将是派生类中声明的成员。为了在派生类中可以继续访问基类中的相应成员,在C#中引入了base关键字,通过该关键字可以访问基类中的成员。因此,可以将base看成是一个指向派生类直接基类的引用,而this则是指向对象实例本身的引用。第第3 3章章 C C# #面面向向对对象象编编程程36363.7 3.7 继承与多态 3.7.1继承3object类为了提高程序员的编程效率,各种编程环境(工具)都提供了许多重用度高的类库,以方便程序员直接使用。同样,在.NET中也提供了相应的类库。其中Object是该类库中最基本的类,它属于System命名空间,通常也写成System.

51、Object。在C#中,所有的类都直接或间接派生于Object类。在声明类时,如果没有明确指明基类,则编译器会自动将Object类指定为其基类。因此,Object类是C#所有类的根,每个类都将从Object类继承类成员。表3.3列出了Object类的常用方法。方法访问修饰符作用stringToString()publicvirtual返回对象的字符串表示intGetHashTable()publicvirtual在实现字典(散列表)时使用boolEquals(objectobj)publicvirtual对当前对象与obj进行相等比较boolEquals(objectobjA,objectob

52、jB)publicstatic在objA和objB之间进行相等比较boolReferenceEquals(objectobjA,objectobjB)publicstatic比较objA和objB是否引用的是同一个对象TypeGetType()public返回对象类型的详细信息objectMemberwiseClone()protected进行对象的浅层复制voidFinalize()protectedvirtual该方法是析构函数的.NET版本第第3 3章章 C C# #面面向向对对象象编编程程37373.7 3.7 继承与多态 3.7.2抽象类与密封类1抽象类为了满足分层次抽象的需要,在许

53、多面向对象的程序设计语言中都引入了抽象类的概念。抽象类是基类的一种特殊形式,它除了拥有普通的类成员之外,还拥有抽象类成员。在C#中,抽象类成员是指那些只有声明没有实现的方法、属性或索引,并且使用了abstract修饰符。因此,抽象类不能实例化,它一般出现在类层次结构中的中间层或根节点上,不能出现在叶节点中。在C#中,包含一个或多个抽象成员的类本身也必须声明为abstract,但是抽象类可以包含非抽象的成员。从抽象类派生的类必须对基类中包含的所有抽象成员进行实现,否则它也是抽象类。抽象成员为隐式的虚成员,因此在抽象类的派生类中实现抽象成员的方法与覆盖一个虚方法类似。如下代码定义了一个抽象类Sha

54、pe,其中包含抽象方法和虚方法。abstractclassShape/抽象类privateintx,y;privatestringname;protectedColorTypeftColor;abstractpublicvoidDraw();/抽象方法virtualpublicvoidPrint()/虚方法Console.WriteLine(Shapeis0,name);第第3 3章章 C C# #面面向向对对象象编编程程38383.7 3.7 继承与多态 3.7.2抽象类与密封类2密封类密封类是指那些不能被继承的类。在C#中,为了提高程序运行效率和稳定性,对那些认定为不能再继承的类可以定义为

55、密封类,用修饰符sealed进行修饰。当一个类被声明为密封类后,就不能再用来派生新的类。因此密封类中不可能存在抽象成员,一般也不存在虚成员。当某个类中的某个成员认定为不能被覆盖时,也可以将其声明为密封成员,即用修饰符sealed对该成员进行修饰。包含密封成员的类不一定要声明为密封类。密封类可以从抽象类派生,也可以使用关键字override覆盖基类中的虚成员。如下代码定义了一个密封类SquareClass,它从基类RectClass派生而来。sealedclassSquareClass:RectClass/密封类publicSquareClass(stringname,intx,inty,int

56、w,intl):base(name,x,y,x+w,y+l)publicoverridevoidDraw()Console.WriteLine(Square0isdrawed,Name);publicoverridevoidPrint()Console.WriteLine(Shapeis0,Name);Console.WriteLine(tShapetypeisSquare,Lengthis0,Areais1,Length,GetArea();由抽象类和密封类的概念可知,在C#中,修饰符sealed和abstract不能同时出现在同一个类或同一个成员中。第第3 3章章 C C# #面面向向对对

57、象象编编程程39393.7 3.7 继承与多态 3.7.3接口在C#中,继承的实现包括两种方式:实现继承和接口继承。其中前面所介绍的类继承方式属于实现继承,它实现的主要是抽象共享,或派生类对基类的修改和扩展等。接口继承是一种对外约定的实现,在接口中定义相关的对外约定(包括方法、属性、索引和事件),即类必须实现的对外行为特征,实现接口的类则实现了这些约定。这样客户程序只要了解类所实现的接口便可以知道其对外提供了哪些服务。在C#中,定义接口的语法规则如下:访问修饰符interface接口名:父接口列表接口成员其中接口成员可以是方法、属性、索引和事件的声明,但仅仅是声明,不需要给出实现体,这与抽象类

58、中的抽象成员类似。父接口列表用于指定接口继承的父接口,这与类有很大区别,接口允许多继承,因此,该列表可以包含无数个接口。如下代码定义了两个接口IRegion和ILine,其中一个接口定义的是方法,另一个定义的是属性。publicinterfaceIRegiondoubleGetArea();publicinterfaceILinedoubleLengthget;接口最终还是要通过类来实现,即要求类来实现接口中的接口成员,这与派生类要实现基类中的抽象成员一样。另外,由于接口中声明的仅仅是功能约定,即抽象的功能成员,没有数据成员,因此不会由于多重继承带来二义性问题。在C#中,一个类最多可以有一个基

59、类,但是可以具有无限个接口。第第3 3章章 C C# #面面向向对对象象编编程程40403.7 3.7 继承与多态 3.7.4多态性多态性是面向对象技术中的一个重要概念。是指通过基类引用绑定不同对象实例时,同样的方法可以具有不同的运行行为,即对象运行时刻的类型决定它的行为,而不是它的引用方法编译时的类型决定它的行为。在C#中,多态性的实现依赖于基类中的虚成员声明以及派生类中对虚成员的覆盖。如下代码表现了多态性的实现。Shapel1=newLineClass(Line1,10,10,20,40);Shaper1=newRectClass(Rect1,20,20,40,50);Shapes1=ne

60、wSquareClass(Square1,30,30,20,30);l1.Draw();l1.Print();/依据Draw和Print在LineClass中的实现来执行r1.Draw();r1.Print();/依据Draw和Print在RectClass中的实现来执行s1.Draw();s1.Print();/依据Draw和Print在SquareClass中的实现来执行因此,通过对象引用调用的方法的执行行为,取决于该对象引用动态绑定的对象类型。多态性在程序运行的动态过程中体现,进而增加了程序的灵活性和通用型。继承与多态的实现方法如代码实例3.7所示,该实例中定义了抽象类Shape、接口I

61、Region和ILine、具体类LineClass、RectClass和SquareClass。第第3 3章章 C C# #面面向向对对象象编编程程41413.7 3.7 继承与多态 3.7.4多态性usingSystem;namespaceEx_3_7enumColorTypeRed,Green,Blue,Black,White,Yellow;abstractclassShapeprivateintx,y;privatestringname;protectedColorTypeftColor;publicShape()name=Nonename;x=0;y=0;publicShape(str

62、ingname,intx,inty)this.name=name;this.x=x;this.y=y;publicColorTypeFtColorgetreturnftColor;setftColor=value;第第3 3章章 C C# #面面向向对对象象编编程程42423.7 3.7 继承与多态 3.7.4多态性publicintXgetreturnx;setx=value;publicintYgetreturny;sety=value;publicstringNamegetreturnname;abstractpublicvoidDraw();virtualpublicvoidPrint

63、()Console.WriteLine(Shapeis0,name);第第3 3章章 C C# #面面向向对对象象编编程程43433.7 3.7 继承与多态 3.7.4多态性publicinterfaceIRegiondoubleGetArea();publicinterfaceILinedoubleLengthget;classLineClass:Shape,ILineprivateinttoX,toY;publicLineClass(stringname,intx,inty,inttoX,inttoY):base(name,x,y)this.toX=toX;this.toY=toY;pub

64、licdoubleLengthgetreturn(Math.Sqrt(toX-X)*(toX-X)+(toY-Y)*(toY-Y);第第3 3章章 C C# #面面向向对对象象编编程程44443.7 3.7 继承与多态 3.7.4多态性sealedpublicoverridevoidDraw()Console.WriteLine(Line0isdrawed,Name);sealedpublicoverridevoidPrint()base.Print();Console.WriteLine(tShapetypeisLine,Lenghtis0,Length);classRectClass:Sh

65、ape,ILine,IRegionprivateinttoX,toY;publicRectClass(stringname,intx,inty,inttoX,inttoY):base(name,x,y)this.toX=toX;this.toY=toY;第第3 3章章 C C# #面面向向对对象象编编程程45453.7 3.7 继承与多态 3.7.4多态性publicdoubleLengthgetdoublew=Math.Sqrt(toX-X)*(toX-X);doublel=Math.Sqrt(toY-Y)*(toY-Y);return(2*(w+l);publicdoubleGetArea

66、()doublew=Math.Sqrt(toX-X)*(toX-X);doublel=Math.Sqrt(toY-Y)*(toY-Y);return(w*l);publicoverridevoidDraw()Console.WriteLine(Rect0isdrawed,Name);第第3 3章章 C C# #面面向向对对象象编编程程46463.7 3.7 继承与多态 3.7.4多态性publicoverridevoidPrint()base.Print();Console.WriteLine(tShapetypeisRect,Lengthis0,Areais1,Length,GetArea(

67、);sealedclassSquareClass:RectClasspublicSquareClass(stringname,intx,inty,intw,intl):base(name,x,y,x+w,y+l)publicoverridevoidDraw()Console.WriteLine(Square0isdrawed,Name);publicoverridevoidPrint()Console.WriteLine(Shapeis0,Name);Console.WriteLine(tShapetypeisSquare,Lengthis0,Areais1,Length,GetArea();

68、第第3 3章章 C C# #面面向向对对象象编编程程47473.7 3.7 继承与多态 3.7.4多态性classTeststaticvoidMain(stringargs)LineClassl1=newLineClass(Line1,10,10,20,40);RectClassr1=newRectClass(Rect1,20,20,40,50);SquareClasss1=newSquareClass(Square1,30,30,20,30);l1.Draw();l1.Print();r1.Draw();r1.Print();s1.Draw();s1.Print();ILinelp=(ILi

69、ne)s1;IRegionrp=(IRegion)s1;Console.WriteLine(Length=0,Area=1,lp.Length,rp.GetArea();第第3 3章章 C C# #面面向向对对象象编编程程48483.8 3.8 基于UML的系统分析与设计方法 3.8.1UML简介对软件系统开发过程中各阶段的成果进行模型化表示是系统分析与设计中的主要技术。UML是目前最常用的一种面向对象建模语言,它用图形化的方法来表示软件概念图,主要包括10种常见的图形化符号,即用例图、类图、对象图、序列图、协作图、状态图、活动图、包图、组件图和部署图,分别表示系统分析与设计过程中不同阶段不同

70、侧面的结果。用例图:用于描述系统的功能单元,它以图形化的方式表示系统内部的用例,系统外部的参考者,以及它们之间的交互。类图:用于展示软件系统中主要类及其关系。对象图:展示了在系统执行的某个特定时刻的一组对象和关系,因此可以把它看作是一个内存快照。序列图:强调时间顺序,显示特定用例的详细流程。序列图有两维:垂直方向是以时间顺序显示消息/调用序列,水平方向则显示消息发送到的对象实例。协作图:展示了对象之间的关系,可以是用于完成某个用例的对象之间的关系,或者整个系统的对象之间的关系。状态图:用于描述系统动态特征,包括状态、转换、事件以及活动等,因此对于理解系统的行为来说,状态图非常有用。活动图:描述

71、系统在处理某项活动时,两个或多个对象之间的活动流程。包图:是一种聚组构造的图形化表示形式,以构成更高层次的单位。组件图:以可视化方式提供系统的物理视图,显示系统中组件的依赖关系。部署图:显示系统如何物理部署到硬件环境之中,是节点和连线的集合。当然,在UML中所包括的图形远不止这些。但类图和序列图是其中最基本的,同时也是最常用的图形。因此,本节主要对其中的类图和序列图进行介绍,以满足后续章节中的使用需要。第第3 3章章 C C# #面面向向对对象象编编程程49493.8 3.8 基于UML的系统分析与设计方法 3.8.2类图类是对一组具有相同特性的对象的描述,或者说是类属事物或系统的表示形式。类

72、图提供了一种表示系统中各个类及其间存在的各种静态关系的图示化方法。同时也表示了类中的属性和操作以及用于对象连接方式的约束。图3.4所示为一个简单的类图实例。1属性属性描述了类中的数据成员,即对象所具备的特性。类可以有任意数目的属性,也可以没有属性。在UML中,类属性的声明语法为:可见性属性名:类型=初始值约束字符串其中,可见性包括公有()、私有()和受保护()。约束字符串则描述了属性的约束特性,如readonly等。图3.4类图实例第第3 3章章 C C# #面面向向对对象象编编程程50503.8 3.8 基于UML的系统分析与设计方法 3.8.2类图2方法方法也称操作,是对类的对象所能做的事

73、务的抽象,即类的功能成员。一个类可以有任意数量的方法或者根本没有方法。返回类型、方法名称和参数一起被称为方法签名。在UML中,类方法的声明语法为:可见性方法名(参数表):返回类型约束字符串其中,参数表中的参数的声明格式为:方向参数名称:类型=默认值方向包括in、out和inout3种,分别表示为传入、传出和双向参数。3关联关联表示了两个类的对象之间的结构关系,如一个类的对象包含另一个类的对象作为其子对象,或者通过包含另一个类的对象引用来访问其成员等。在图3.4所示的类图中的Client类和Shape类之间便是关联关系。关联关系的图形化表示形式是两个类之间有一条实线,方向从源类到目标类。关联包括

74、名称、角色和重数。角色表明了两个类分别对对方所起的作用,重数则表示一个类的对象包含另一个类的对象或对象引用的数量,其表示形式如下:n:n个n1.n2:n1个到n2个*:0个到多个,即没有上限例如在图3.4中,一个类Client的对象实例中可以包含0个到多个Shape对象实例。第第3 3章章 C C# #面面向向对对象象编编程程51513.8 3.8 基于UML的系统分析与设计方法 3.8.2类图4聚合聚合表示一种特殊的关联关系,即一种整体和部分之间的关系,但作为部分的对象有一定的独立性,能够离开整体而存在,往往也称为共享关系,在类的定义中一般表示为一个类的对象中包含另一个类的对象引用。例如图3

75、.4中的Shape类对象和Point类对象之间的关系便是聚合关系,其图形化表示是一个空心菱形开始的实线。聚合关系同样包含重数,图3.4中的Shape类对象只能包含一个Point类对象引用。5组合组合是一种强聚合关系,即一种整体和部分之间的关系,且作为部分的对象不能离开整体而存在,也称为复合关系,在类的定义中一般表示为一个类的对象中包含另一个类的对象作为其子对象。图3.4中的Shape类对象和ShapeAttr类对象之间便是一种组合关系,其图形化表示是一个实心菱形开始的实线。组合关系也包含重数。6泛化用于表示两个类之间的继承关系,其图形化表示为一个空心三角符号开始的实线,空心三角符号方向为父类。

76、图3.4中的Shape类和Rect类,Shape类和Square类之间便是一种泛化关系。在C#中实现时则表示为一种继承关系。第第3 3章章 C C# #面面向向对对象象编编程程52523.8 3.8 基于UML的系统分析与设计方法 3.8.2类图7抽象类在继承关系中,抽象类是一个不能直接被实例化的类,其在UnL中可以图示化为类名为斜体的类,也可以在类名后加上abstract约束来表示抽象类。图3.4中的Shape类便是一个抽象类。8接口接口是一个不具实现的类,接口中没有数据成员,只有功能成员,即方法,并且都是抽象的。在UML中其图示化为一个以,和开始的,没有属性栏的类图形,如图3.4中的ISi

77、ze便是一个接口。9依赖如果一个类的定义可引起另一个类的改动,则称这两个类之间存在一种依赖关系。一般类之间存在依赖的原因有3种:一个类把一个消息发送给另一个类、一个类以另一个类作为其数据成员、一个类把另一个类的对象作为其操作参数。依赖关系图示化为一个带箭头的虚线,如图3.4的Rect类和System.Drawing.Graphics类之间便是依赖关系,表示在Rect类中使用了System.Drawing.Graphics类的对象实例来绘制其形状。第第3 3章章 C C# #面面向向对对象象编编程程53533.8 3.8 基于UML的系统分析与设计方法 3.8.3序列图序列图用来表示完成某个功能(用例)的行为,即用图示法表示完成一个功能所需的对象实例之间的消息传递顺序。序列图表示为一个二维图,其中,纵轴是时间轴,时间沿竖线向下延伸。横轴代表了协作中各独立的对象。图3.5便是一个序列图,表示了Client类的对象实例和Server类的对象实例之间为完成数据传输而执行的消息序列。其中带箭头的实线表示发送消息,而带箭头的虚线表示返回消息。消息的执行顺序自上而下。矩形框中的消息是可以循环执行的消息。在生命线上面有时会加上矩形框来表示对象的激活状态。图3.5序列图实例

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 资格认证/考试 > 自考

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号