1、软件设计与实践,课程主要内容,软件设计基础Visual C#.NET基础Visual C#.NET控件及其应用图形图像和多媒体编程文件操作组件设计数据库编程企业人事管理系统案例图像处理系统案例,软件设计基础,软件设计任务软件设计的任务是从软件需求规格说明书出发,根据需求分析阶段确定的功能设计软件系统的整体结构、划分功能模块、确定每个模块的实现算法以及编写具体的代码,形成软件的具体设计方案。,软件设计基础,软件设计要素软件设计包括软件的结构设计,数据设计,接口设计和过程设计。结构设计是指:定义软件系统各主要部件之间的关系。数据设计是指:将模型转换成数据结构的定义。接口设计是指:软件内部,软件和操
2、作系统间以及软件和人之间如何通信。过程设计是指:系统结构部件转换成软件的过程描述。,表示软件结构的图形工具层次图和HIPO图层次图表示软件层次结构结构图,软件设计基础,软件设计基础,订单处理软件层次图(H图),IBM公司发明的HIPO图:层次图 + 输入 / 处理 /输出图 (H图) (IPO图)(Hierachy Input Process Output),软件设计基础,软件设计基础,确定能够供货模块的IPO图,软件设计基础,软件设计原则单一职责原则:就一个类而言,应该只有一个引起它变化的原因。 例:如果开发一个计算器小程序,只用一个类就可以实现。但这个类就违反了单一职责原则,因为这个类不但
3、有计算逻辑,还用来显示了。所以除了计算外,显示也会引起这个类的变化。如果现在想改成控制台程序呢?容易改吗?,软件设计基础,开-闭原则:软件实体(类,方法等),应该可以扩展,但不能修改。 如何达到这样要求?抽象化与继承。在面向对象语言中,可以创建固定却能够描述一组任意个可能行为的抽象体。这个抽象体就是抽象基类。模块可能对抽象体进行操作。它对于更改是封闭的。同时通过从这个抽象体派生,可以扩展此模块的行为。,软件设计基础,CS游戏中:士兵用枪杀敌,软件设计基础,依赖倒置原则:(1)高层模块不应该依赖底层模块。两个都应该依赖抽象。(2)抽象不应该依赖细节。细节应该依赖抽象。 “依赖抽象,不要依赖具体”
4、 要针对接口编程,不要针对实现编程例:母亲给孩子讲故事,只要给她一本书,她就可以照着书给孩子讲故事了。,classBook publicStringgetContent() returnxxxxxxxxxxxxxxxxxx.; classMother publicvoidnarrate(Bookbook) Console.WriteLine(妈妈开始讲故事); Console.WriteLine(book.getContent(); publicclassProgramstatic void Main(string args) Mothermother=newMother(); mother.
5、narrate(newBook(); ,软件设计基础,让这位母亲讲一下报纸上的故事classNewspaperpublicStringgetContent()returnyyyyyyyyyyyyyyyyy.;,软件设计基础,这里母亲是高层模块,负责复杂的业务逻辑;类书和类报纸是低层模块,负责基本的原子操作;假如修改类母亲,会给程序带来不必要的风险。将类母亲修改为依赖接口,类书和类报纸各自实现接口,类母亲通过接口间接与类书或者类报纸发生联系,则会大大降低修改类母亲的几率。引入一个抽象的接口Ireader-读物,只要是带字的都属于读物。interfaceIReaderStringgetConten
6、t();具体的读物类实现这个接口。,软件设计基础,软件设计基础,里氏替换原则:子类应该能替换掉它的父类。 它表述为一个行为对父类可行的,对子类也一定可行。 里氏代换原则说明了我们不能乱用继承 例:矩形,正方形长方形的长和宽和正方形的长和宽明显有不同的特点。正方形继承长方形是错误的,正确的写法是我们可以把正方形和长方形抽象出来,再让正方形和长方形继承这个抽象类,从而这两个类互不影响,各实现各的功能。,软件设计基础,接口隔离原则: 这个原则要求我们定义多个不同的专门接口,而不要依赖一个大而全的接口。 例:在家具生产的例子里。定义“生产线”,和“产品”这两个接口就是角色的清晰划分,如果将它们混合成一
7、个“家具生产”的接口,这样的接口在角色定义上就失去了意义。,软件设计基础,过于臃肿接口,软件设计基础,拆分为三个接口,软件设计基础,迪米特法则(最少知识原则): 迪米特法则规定的是模块与模块之间的通信量。狭义上说,迪米特法则要求两个类如果不应当直接发生关系,就应该通过一个第三方类来实现,这样一个模块和外界的 接触越少就越有利。广义上说这个法则是对信息间的信息流量,流向以及信息的影响的控制。我们知道一个模块它与外界通信越少,那它的耦合度就越低,那么对于它的改进操作对整体系统的影响就越小。,例:有一个集团公司,下属单位有分公司和直属部门,现在要求打印出所有下属单位的员工ID。定义类:总公司员工类E
8、mployee分公司员工类SubEmployee分公司经理类SubCompanyManager总公司经理类CompanyManager,软件设计基础,软件设计基础,组合/聚合原则: 这个原则要求组合/聚合优先于继承。我们在想获得一个对象的功能的时候,不要随便通过继承,定义一个它的子类来获得它的方法和成员,而应该优先考虑通过拥有它的一个实例的方式 来实现。就是new一个对象来获得它的方法,优先于extends来获得它的方法。,第1章 Visual C#.NET基础,1.1 .NET框架概述,1.1.1 公共语言运行时公共语言运行时(CLR) 提供内存管理、线程管理和远程处理等核心服务,强制实施严
9、格的类型安全及确保代码的准确性。即时(Just-In-Time)编译 垃圾回收机制,第1章 Visual C#.NET基础,1.1.2 基础类库类库是一个由.NET Framework SDK中包含的类、接口和值类型组成的库。类库提供了Internet和企业级开发所需的各种功能。类库分配到不同的命名空间下。,第1章 Visual C#.NET基础,1.1.3 .NET框架编程模型,第1章 Visual C#.NET基础,1.1.4 .NET程序的编译与运行传统的代码编译与运行,第1章 Visual C#.NET基础,1.1.4 .NET程序的编译与运行,第1章 Visual C#.NET基础,
10、可执行的应用程序文件,其他应用程序文件、元数据及资源等,第1章 Visual C#.NET基础,1.1.5 .NET集成开发环境VS 2005、VS2008、VS2010、VS2012,1.2 Visual C#基础知识1.2.1 C#数据类型值类型简单类型、枚举类型、结构类型引用类型类、接口、委托、数组、字符串等,第1章 Visual C#.NET基础,浮点类型Float:32位单精度浮点数;Double: 64位双精度浮点数:Decimal:128位双精度浮点数。Bool类型值为”true”和”false”;不能象C语言中非零为true,零为false:,第1章 Visual C#.NET
11、基础,字符类型charUnicode字符集表示形式转义字符。整数类型byte、int、short、long,第1章 Visual C#.NET基础,字符串类型string:C#将字符串封装成一个类;ToCharArray()把字符串放入一个字符数组中;Length属性返回字符串的长度;,应用举例: string str1=“How”+”are you”; /连接字符串 char c=“Hello,World!”6; /c=W,把字符串中的第7个字符赋给c string str2=“Nice to meet you”; bool b=(str1=str2); /“=”运算符用于两个字符串比较,
12、b=false,第1章 Visual C#.NET基础,枚举类型格式:enum 枚举类型名枚举元素列表;枚举元素以位置顺序进行赋值;例 枚举例题指针类型C+中奉为经典的指针类型,在C#中被取消了,第1章 Visual C#.NET基础,结构类型结构类型与类相似,包括构造函数、析构函数、成员变量、成员属性;结构和类的区别中结构不能继承,类是引用类型,结构是值类型;格式:,struct 结构体名 成员列表; ,第1章 Visual C#.NET基础,数组类型语法 ,应用举例:一维数组int num=1,2,3,4,5;int num1 = new int51,2,3,4,5;多维数组int ,nu
13、m2=new int 2,31,2,3,4,5,6; 锯齿形数组int num=new int 3;num0=new int 3;num1=new int 4;num2=new int5;,第1章 Visual C#.NET基础,流程控制和函数 if/ifelse语句注意C+与C#的区别,int a;if(a=GetNum() /假设GetNum返回一个整数值/a为非0Else/a为0在C+中,上述代码是正确的,但在C#中是错误的,因为if的条件表达式的值必须为bool型,int a=GetNum();if(a!=0) /假设GetNum返回一个整数值/a为非0Else/a为0在C+和C#中,
14、上述代码都是正确的。,第1章 Visual C#.NET基础,switch(表达式)case 值1:语句1;break;case 值2:语句2;break;:case 值n: 语句n; break;default: 语句n+1;break;,流程控制和函数 switch语句使用方法与C+中相同格式,第1章 Visual C#.NET基础,流程控制和函数 for语句使用方法与C+中相同格式,for(int i=循环初值;i=(或str2,返回1; str1=str2,返回0; str1str2,返回-1 */,第1章 Visual C#.NET基础,Equals,Str1.Equals(str2
15、); /*str1!=str2,返回false;str1=str2,返回 true,IndexOf(string):返回指定子字符串的第一 个匹配项的位置。IndexOf使用示例,LastIndexOf(string):返回指定子字符串的 最后一个匹配项的位置。,第1章 Visual C#.NET基础,Copy(string str):创建一个与指定的String字 符串具有相同值的新String类。例如:,String str1=“abc”;String str2=“de”;str2=String.Copy(str1); /str2的值为“abc”,CopyTo(int sourceInde
16、x,char destination, int destinationIndex,int count):将字符串或 部分字符串复制到char类型的数组的指定位置。CopyTo的使用示例,第1章 Visual C#.NET基础,Split(char separator):可将字符串按指定字符分隔成子字符串。Split()使用示例,其它操作Insert, Replace, Remove, PadLeft, PadRight, Trim, TrimEnd, TrimStart等,请参阅相关资料自己学习,Length属性:获得字符串的长度,第1章 Visual C#.NET基础,Split(char
17、separator):可将字符串按指定 字符分隔成子字符串。Split()使用示例,其它操作Insert, Replace, Remove, PadLeft, PadRight, Trim, TrimEnd, TrimStart等,请参阅相关资料自己学习,Length属性:获得字符串的长度,第1章 Visual C#.NET基础,StringBuilder类该类位于System.Text命名空间下,使用StringBuilder类 重新生成新字符串时不再生成一个新实例,直接在原来的字符 串占用的内存空间上处理,使用该类可以提升性能。StringBuilder类新实例的创建。,StringBui
18、lder MyStringBuilder=new StringBuilder(“Hello,World”);,创建StringBuilder类时,可以指定该类的最大容量,当达到最大容量时,自动分配新的空间且容量翻倍。,StringBuilder MyStringBuilder=new StringBuilder(“Hello,World”,25);,第1章 Visual C#.NET基础,StringBuilder类的常用方法。Append方法 将文本或对象所表示的字符串添加到StringBuilder对象表示的字符串的末尾。,StringBuilder MyStringBuilder=new
19、 StringBuilder(“Hello,World!”);MyStringBuilder.Append(“What a Beautiful day”);Console.WriteLine(MyStringBuilder);/输出“Hello,World! What a beautiful day”,第1章 Visual C#.NET基础,AppendFormat方法将文本添加到StringBuilder的末尾处,而且实现了IFormattable接口,因此可以接受格式化部分中描述的标准格式字符串。,Int MyInt=25;StringBuilder MyStringBuilder=new
20、 StringBuilder(“Your total is ”);MyStringBuilder.AppendFormat(“0:C”,MyInt);Console.WriteLine(MyStringBuilder);/输出“Your total is $25.00”,第1章 Visual C#.NET基础,Insert方法将字符串或对象添加到当前StringBuilder中的指定位置。,StringBuilder MyStringBuilder=new StringBuilder(“Hello World! ”);MyStringBuilder.Insert(6,”Beautiful ”)
21、;Console.WriteLine(MyStringBuilder);/输出“Hello Beautiful World! ”,第1章 Visual C#.NET基础,Remove方法从当前StringBuilder中的指定位置移除指定数量的字符。,StringBuilder MyStringBuilder=new StringBuilder(“Hello World! ”);MyStringBuilder.Remove(5,7);Console.WriteLine(MyStringBuilder);/输出“Hello”,第1章 Visual C#.NET基础,Replace方法用另一个指定
22、的字符替换StringBuilder对象内的字符。,StringBuilder MyStringBuilder=new StringBuilder(“Hello World! ”);MyStringBuilder.Replace(!,?);Console.WriteLine(MyStringBuilder);/输出“Hello World?”,第1章 Visual C#.NET基础,DateTime类表示范围在0001年1月1日午夜12:00:00到9999年12月 31日晚上11:59:59之间的日期和时间。TimeSpan类该类可以表示一个时间间隔。其范围可以在Int64.MinValue
23、 到Int64.MaxValue之间。例1-21 求世博会闭幕到今天已经过了多少天:,第1章 Visual C#.NET基础,Math类:位于System命名空间下。,第1章 Visual C#.NET基础,第1章 Visual C#.NET基础,Convert类:位于System命名空间下。,第1章 Visual C#.NET基础,第1章 Visual C#.NET基础,与窗体应用程序相关的类。,1.3 栈模型的实现 【案例1-1】栈是一种重要的数据结构,在内存中占用连续的存储单元。栈有两个端点,固定的栈底和浮动的栈顶。为指示栈顶位置还应设一个指示成员变量(称为栈顶指示器)。栈有两种基本操作
24、:push(压栈)和pop(出栈),压栈是向栈顶位置写入一个元素,然后使栈顶指示器加1,出栈是先使栈顶指示器减1,再把该位置的元素读出来。栈及其操作模型如图1-14所示,sp代表栈顶指示器。请编程实现栈的模型并对之进行测试。,第1章 Visual C#.NET基础,第1章 Visual C#.NET基础,1.3.1 关键技术C#类中包含了程序所要用到的数据和所要执行的方法的定义。每个类中可以有:字段变量声明、构造函数、方法、属性、索引(indexers)、事件等。,第1章 Visual C#.NET基础,1C#类的声明访问修饰符 class 字段变量声明 构造函数 方法 ;,第1章 Visua
25、l C#.NET基础,C#语言中有以下几种访问权限:(1)public: 任何外部的类都可以不受限制的存取这个类的方法和数据成员。(2)private :类中的所有方法和数据成员只能在此类中使用,外部无法存取。(3)protected :除了让本身的类可以使用之外,任何继承自此类的子类都可以存取。(4)internal :在当前项目中都可以存取。该访问权限一般用于基于组件的开发,因为它可以使组件以私有方式工作,而该项目外的其它代码无法访问。(5)protected internal :只限于当前项目,或者从该项目的类继承的类才可以存取。,第1章 Visual C#.NET基础,例如:下面是em
26、ployee类(职员类)的声明:using System;namespace P1_3 public class employee private int No;private string name;private char sex;private string address;public employee(int n, string na, char s, string addr) No=n; name=na;sex=s; address= addr;public void disp_employee()Console.WriteLine(职工号:0 职工姓名:1 , No, name)
27、; Console.WriteLine(性别:0 住址:1 , sex, address); public static void Main() ,第1章 Visual C#.NET基础,声明类后,需要通过new关键字创建类的实例(也就是对象)。类的实例相当于一个引用类型的变量。创建类实例的格式如下: 类名 实例名=new类名(参数);new关键字调用类的构造函数来完成实例的初始化工作。例如: employee p1=new employee(9901,”王海”, ”男”,”广州市中山大道西109号”);也可以使用下述两条语句: employee p1; p1=new employee(990
28、1,”王海”, ”男”,”广州市中山大道西109号”);在Visual Studio.NET集成环境中的,工具箱中的一个控件,是被图形文字化的可视的类,而把这些控件添加到窗体设计器中后,窗体设计器中的控件则是对象,即由工具箱中的类创建的对象。,第1章 Visual C#.NET基础,2类的成员 类的成员可将其分为数据成员(常量、字段)和函数成员(方法、属性、事件、构造函数、析构函数等)。,第1章 Visual C#.NET基础,对类中的成员有五种访问权限: “public” :该成员可以被所有代码访问; “protected”: 该成员只可以被继承类访问; “internal”: 该成员只可以
29、被同一个项目的代码访问; “protected internal”:该成员只可以被同一个项目的代码或继承类访问; “private”:该成员只可以被本类中的代码访问。 类成员的缺省访问权限是“private”。,第1章 Visual C#.NET基础,3静态成员和实例成员 类的成员要么是静态成员,要么是实例成员(非静态成员)。当用static修饰符声明后,则该成员是静态成员。如果没有static修饰符,则该成员是实例成员。两者不同在于静态成员属于类所有,为这个类所有实例共享。而实例成员属于类的实例所有。,第1章 Visual C#.NET基础,using System;namespace P1
30、_4 public class Myclassprivate int A, B, C;static int Sum;public Myclass(int a, int b, int c)A = a;B = b;C = c;Sum += A+B+C;public Myclass() public void GetNumber()Console.WriteLine(Number=0,1,2 , A ,B,C); public void GetSum()Console.WriteLine(Sum=0 , Sum); ,编译程序并运行可得到下面的输出:Number=3,7,10Number=14,9,
31、11Sum=54Sum=54,public static void Main() Myclass M=new Myclass (3, 7, 10); MyclassN=new Myclass(14, 9, 11); M.GetNumber(); N.GetNumber(); M.GetSum(); N.GetSum(); ,第1章 Visual C#.NET基础,4类的构造函数和析构函数构造函数和析构函数是在类体中说明的两种特殊的成员函数。构造函数的功能是在创建实例(也就是对象)时,使用给定的值来将实例初始化。析构函数的功能是用来从内存中释放一个实例的,在删除实例前,用它来做一些清理工作,它与
32、构造函数的功能正好相反。,第1章 Visual C#.NET基础,5方法一个方法是表现对象或类行为的成员函数。方法必须放在类定义中。方法同样遵循先声明后使用的规则。C#中的方法必须放在类定义中声明,也就是说,方法必须是某一个类的方法。,第1章 Visual C#.NET基础,方法有四种形式参数:数值参数,它不用任何修饰符声明。 数值参数在方法被调用时创建,并将实参的值复制给数值参数,在方法中对数值参数的修改不会影响对应的参数例1-5A数值参数示例,第1章 Visual C#.NET基础,引用参数,它用ref修饰符声明。用ref修饰符声明的参数是引用参数,引用参数不分配新的存储位置,而是使用与相
33、应实参相同的存储位置,因此引用参数的修改会影响对应的实参。例1-5B引用参数示例,第1章 Visual C#.NET基础,输出参数,它用out修饰符声明。用out修饰符声明的参数称为输出参数,输出参数不被分配新的存储位置,而是使用与相应实参相同的存储位置,在作为实参传送给方法时不须明确赋值,但在方法返回前必须明确赋值。例1-7 输出参数应用程序示例,第1章 Visual C#.NET基础,参数数组,它用params修饰符声明。用params修饰符声明的参数是参数数组,参数数组必须是形参列表中的最后一个,形式为int、int,但是类型int,不能作为形参。不能将params修饰符与ref和out
34、修饰符组合起来使用。与参数数组对应的实参可以是同类型的数组名,也可以是与该数组元素属于同一类型的简单变量。如果实参是数组,则按引用传递数值;若实参是变量或表达式,则按值传递。例1-8 使用参数数组应用程序示例,第1章 Visual C#.NET基础,6静态方法和非静态方法静态方法属于是类所有,是所有对象实例公用的方法,只能用类名调用静态方法。它不属于某一个具体的对象实例,因此静态方法中没有隐含的this,也就是说我们不能通过this获得调用该方法的对象。既然找不到这个对象实例,我们不能在其中访问该对象实例的成员,这和非静态方法是不一样的。,第1章 Visual C#.NET基础,7方法的重载
35、所谓方法重载就是指同一个方法名有多个不同的实现方法。具体地讲,定义方法重载时要求方法的参数或者至少有一个类型不同,或者个数不同。,第1章 Visual C#.NET基础,using System; namespace P1_10 public class TestMethod public double volume (double x) /立方体体积return x*x*x; public double volume (double r, double h) /圆柱体体积 return Math.PI*r*h; public double volume (double a, double b
36、, double c) /长方体体积 return a*b*c; public static void Main() TestMethod t1=new TestMethod(); Console.WriteLine(cube volume = 0 , t1. volume (2.5); Console.WriteLine(cylinder volume = 0 , t1. volume (2,4);Console.WriteLine(cuboid volume = 0 , t1. volume (5,3,4); ,第1章 Visual C#.NET基础,8属性一个类的数据成员变量可以有两种方式:字段和属性。字段作为数据成员变量可以被直接访问,而属性不能直接进行访问,必须通过访问器进行访问。,第1章 Visual C#.NET基础,(1)声明属性在类定义中声明属性的语法格式为: 访问修饰符 类型 属性名 get set ,第1章 Visual C#.NET基础,例如:class Student / 类名为Student private string name; / 声明字段 public string Name / 对应name的属性 get return name; set name=value; ,