1、第7章 面向对象技术总论 7.1概述概述-面向对象方法论面向对象方法论 7.2面向对象技术的基本概念面向对象技术的基本概念 7.3面向对象技术的基本特点面向对象技术的基本特点7.4面向对象分析方法面向对象分析方法 7.5面向对象技术与程序结构面向对象技术与程序结构 7.6面向对象软件工程面向对象软件工程 7.7设计模式(设计模式(Design Pattern)与框架)与框架(framework)7.8基于构件的软件体系结构(基于构件的软件体系结构(com/dcom,corba,internet)7.9 面向对象分析解决(描述)问题的模式面向对象分析解决(描述)问题的模式 第第7章章 面向对象技
2、术总论面向对象技术总论第7章 面向对象技术总论 7.1 概述概述面向对象方法论面向对象方法论面向对象技术的内容包括面向对象系统分析技术、系统设计技术、程序设计技术、测试技术以及各种基于面向对象技术的体系结构、框架、组件、中间件等。面向对象技术的基础是面向对象程序设计,后者是程序结构化发展的必然产物。众所周知,高级程序设计语言经历了非结构化、结构化、面向对象三个发展阶段,这三个阶段的进化都是针对程序的结构和系统分析方法而做出的。程序的结构是指程序代码之间的关系。每到一个新的阶段,程序的结构就更加完善、更加复杂,代码也更容易重用,抽象程度也更高。第7章 面向对象技术总论 软件系统分析方法研究将问题
3、域(现实世界)向求解域(程序域)转换和映射的方法,其目的是把问题域(现实世界)中的概念或者处理过程转换或映射成程序的元素和算法。问题域(现实世界)相对来说是不变的或者变化较缓慢的,但系统分析方法却根据程序设计方法的不同而改变,因此系统分析方法依赖于程序设计技术,依赖于程序设计元素,参见图7.1。结构化分析方法和面向对象分析方法则又分别依赖于结构化程序设计语言和面向对象程序设计语言。第7章 面向对象技术总论 图7.1 系统分析方法对程序设计技术的依赖性 第7章 面向对象技术总论 非结构化分析方法就是要把问题域或现实世界中的概念和处理,如员工工资、计算工资等转换成变量定义和对变量进行处理的语句,其
4、基本元素是变量和语句,即所谓的数据结构+算法。由于当时程序规模普遍比较小,运行和应用环境也比较单一,因此不太考虑程序结构或者软件结构问题。整体来说,非结构化技术是重视算法轻视结构的一种方法。第7章 面向对象技术总论 结构化技术的基本元素是定义良好的程序结构元素,如子程序(函数)结构和单入口/单出口的控制结构。前者是程序的静态结构,后者则是程序的动态结构。子程序结构构成了整个程序的静态结构,是动态控制结构的基础(严格地说,每个语句都可以看成是对函数的调用)。结构化分析方法就是要把问题域(现实世界)中的问题(概念、处理)转换成程序中的数据结构和子程序(函数)。在这类方法中,可以认为:程序=数据结构
5、+函数结构+函数调用。相应的数据流分析方法则将现实世界或者问题域中的业务处理转换为程序的函数结构,这个过程称为分析过程,将系统的结构变成更适合于程序域的形式,比如说具有重用、高效、稳定等特征的结构,则是设计过程。第7章 面向对象技术总论 到了面向对象技术阶段,程序的基本元素是数据结构和函数结构的统一体“类”。类是程序中的静态元素,而动态元素是对象和消息。面向对象方法认为:程序=类结构+对象+消息。面向对象分析的任务则是把现实世界中的概念或者处理都转换为程序域中的类和方法,将现实世界中的过程转换为对象之间的交互过程。面向对象设计使这种类和对象交互更加适合于计算机系统实现,更加合理和高效,更加容易
6、重用。例如将员工、工资都转换成求解域中的类,计算某位员工工资的过程称为向该员工对象发消息。第7章 面向对象技术总论 如上所述,新一代的程序设计语言技术并不是简单地否定上一代语言,而是在上一代语言的基础上增加新的程序结构元素(函数、类),从而实现更复杂的程序结构。这种新的程序元素更直观、更真实、更自然、更完整地抽象了现实世界中的数据和处理(或者事物与概念),更好地抽象了程序中的变量和代码,也进一步增强了程序的易读性、安全性、稳定性和重用性,同时改变了系统的分析和设计方法。归根结底,程序设计语言的发展就是程序结构以及建立在其基础上的分析、设计方法的发展。第7章 面向对象技术总论 上面的例子表明,实
7、现同样的功能可以采用不同的程序元素、程序结构或者程序设计技术。高级的程序设计方法更擅长解决复杂的问题,因为其程序元素和程序结构更为复杂。这实际上是自然界和社会系统的一个普遍规律,即内部结构决定外部功能。如果把系统解决的问题比做该系统实现的外部功能,而把实现这些功能的程序元素及其关系看做是内部结构,越复杂的内部结构就预示着系统的功能越复杂、越强大,比如说,人的大脑结构要比动物的大脑结构复杂得多,因此其功能也要强大得多。第7章 面向对象技术总论 面向对象的程序结构要比面向过程的程序结构更复杂,因此可以实现的功能也就更加强大。程序设计语言技术的发展历史充分证明了客观和主观系统进化中,功能和结构之间关
8、系的一般规律。图7.2表现了系统外部功能和内部结构之间的关系,其内部结构也是分层次的,这也符合了人认识世界的一般规律:由外向内、由表及里。第7章 面向对象技术总论 图7.2 软件系统外部功能和内部结构之间的关系 第7章 面向对象技术总论 图7.3 软件系统外部功能和内部结构关系的例子 第7章 面向对象技术总论 7.2 面向对象技术的基本概念面向对象技术的基本概念7.2.1 类类对象是指现实世界或者概念世界中的任何事物,类是具有相同结构特征的对象的结构抽象。此结构特征包括对象的属性特征和操作接口特征。属性特征定义了所有对象都具有的属性名称及类型;操作接口特征则定义了所有对象都具有的操作和方法。第
9、7章 面向对象技术总论 面向对象程序语言中的类是一个代码的预定义模块或者程序结构元素,类似于函数、结构体或者记录类型定义,其中包含了相关的变量和函数定义。类中的变量称为属性或者成员变量;类中的函数称为成员函数(操作和方法)。操作和方法的区别在于:操作强调其操作接口,方法则强调实现方式和算法。可以把现实世界中的对象映射为程序语言中的类,有时候这种映射比较困难且不明显,则可在其间增加一个概念世界或者概念模型。这种映射的过程即为面向对象的系统分析,如图7.4所示。第7章 面向对象技术总论 图7.4 现实世界向计算机世界的转换 第7章 面向对象技术总论 现实世界中的对象一定能够抽象成类,但程序语言中的
10、类则不一定有现实世界原型。这种不对称性反映了信息系统的特殊性,即程序模型并不一定是现实世界的原始或者简单的等价。因为现实世界中的任何事物都可以被抽象为类,因此可以把面向对象看成是一种世界观和方法论,在这种世界观和方法论基础上,现实世界被转换成程序世界就显得比较自然。例如:企业中的员工、仓库、库存帐目、商品及类别、物体、力等。第7章 面向对象技术总论 在程序设计语言中,类是一个完整的、独立的、可重用的,具有低耦合、高内聚特性的程序模块。类相当于一种自定义数据类型,它类似于C语言中的结构体类型(C+本身就可以使用strut关键字来定义类),不仅包含数据结构也包含操作结构。数据类型作为程序语言中进行
11、变量内存分配、类型匹配、操作检查的基础,为程序的一致性和安全性提供了重要的保证。因此,类概念的引入从类型角度进一步提高了程序的安全性。第7章 面向对象技术总论 7.2.2 对象及对象实例对象及对象实例现实世界中的具体事物就是对象或者对象实例,类则是对象实例的结构抽象。每个对象实例一般具有三方面的特性(亦称对象“三要素”):(1)确定的标识,能够被唯一地确认。(2)具有一定的属性,表示其性质或状态。(3)具有一定的行为能力或者操作能力,可给外界提供服务或者通过操作改变其状态。第7章 面向对象技术总论 对象标识也是对象属性之一,是一类特殊的属性,类似于实体关系模型中的主码。应当注意,对象标识和对象
12、在程序中的标识是不一样的,前者是对象本身的固有属性,后者是在程序空间中给该对象起的名字,仅供程序中使用。现实世界中的任何事物都可以抽象成对象,例如具有具体物质形态的对象,如员工、计算机、汽车等;具有抽象物质形态的对象,如银行账户、力等。第7章 面向对象技术总论 面向对象本身就是一种世界观以及由此派生的方法论,是一种观察世界和认识世界的方式。在面向对象的世界观中,世界是由对象及其关系组成的,对象是由属性和行为组成的,对象之间具有各种各样的联系。类是对象结构的抽象,关系是对象之间联系的抽象。对象世界的发展变化过程就是对象之间的交互过程(面向过程也是一种世界观,认为世界是由过程组成的,每个过程都有自
13、己的目标和处理的对象)。面向对象的世界观中的属性和操作刚好对应了程序世界中保存数据或者状态的变量和实现一定功能的函数。属性是事物的性质和状态描述;行为是对属性的操作,可以对外提供服务,属性则是行为的基础和操作的内容。第7章 面向对象技术总论 根据属性和行为的侧重点不同,对象又可以分成实体对象和过程对象,前者强调对象的状态描述,例如“学生”对象;后者强调对象的过程特性,例如“流程”对象。现实世界中的事物都是有联系的,对象之间也有联系。例如对象间的组成关系:如汽车对象是由零件对象组成的;关联关系(信息联系):如老板有员工的联系方式。对象之间有些联系是暂时的:如某人向你问了一下路(发送消息),你向其
14、提供了服务;有些联系则是永恒的、持久的:如父母、子女之间的关系;有些则是介于两者之间的:如配偶关系等。第7章 面向对象技术总论 从静态角度来看,对象实际上就是由类(包括数据结构和函数结构定义)模板派生的变量;从动态角度来看,对象之间的交互(包括自交互)完成或者实现了功能。在面向对象程序中,类是一种代码模板定义,它类似于函数结构和数据结构,必须要实例化才能使用。实例化就是使用类创建具体的对象变量(也叫对象实例),由类产生对象变量相当于在工厂中使用模具生产产品。在程序中只有创建了具体的对象变量,系统才会给其分配内存,程序才能访问其属性和操作。第7章 面向对象技术总论 由于对象变量占用的内存空间不固
15、定,其内存分配方式多采用动态分配和回收机制。在面向对象程序设计语言中,除了对象变量本身,还有一种引用变量(reference variable),其本质上是指针或者地址,可以指向对象变量,其类型必须是一致的。通过引用变量访问对象变量简化了对动态分配的对象内存空间的访问。如Student是Java语言中定义的类,语句Student s=new Student();声明了一个引用变量s,创建了一个对象变量new Student(),并通过赋值语句将该对象变量所在的内存区域的首地址存放到s中,通过s可以对此内存区域进行操作。一般来说,引用变量和对象变量是在不同的内存空间中,前者存放在堆栈空间中,后者
16、是放在堆空间中,这两种内存空间所允许的操作是有所不同的(如图7.5所示)。第7章 面向对象技术总论 图7.5 引用变量和对象变量之间的关系 第7章 面向对象技术总论 7.2.3 消息机制消息机制纯面向对象程序设计语言如Java中,所有的函数或者操作都依附于一个对象主体,这种依附于某个对象的函数叫做成员函数或者对象操作(方法)。在纯面向对象程序中,对任何一个函数的调用都是对某个对象的方法调用,同时会把该对象的信息(一般是内存地址)传递给被调用函数,这就是函数的实例化过程。在面向对象程序中,调用一个对象的方法或者操作叫做向该对象发消息,调用者叫做消息发出者,被调用者叫做消息接受者。消息、事件和函数
17、调用或者事件响应是相辅相承的。程序中,消息就是现实世界中的请求或者通知事件,这一般都是通过对系统执行一定的操作完成的。对该请求或者通知可以响应,也可以不响应,响应可以是同步的,也可以是异步的。第7章 面向对象技术总论 例如,客户如果想从ATM机中取钱,通常会按下取钱按键,这实际上就是向ATM机发送了取钱消息,也是向ATM机发送了取钱请求,ATM机会显示一个取钱界面,让用户输入取款数额,这是通过ATM机的一个方法或者操作实现的。用户输入取款金额后按下确定键,相当于又向ATM机发送新的消息,导致ATM机的另一个方法的调用,通常在该方法中又会向其他对象发送消息,例如该客户的账户Account对象,通
18、过调用该账户对象的draw()操作实现账户上资金的更新。用户通过和ATM机一系列的请求/响应的交互活动完成了执行系统的某个功能,如取钱。客户对象、ATM对象、Account对象之间的消息交互见图7.6。第7章 面向对象技术总论 图7.6 消息机制 第7章 面向对象技术总论 7.3 面向对象技术的基本特点面向对象技术的基本特点7.3.1 封装性封装性程序的基本元素是变量定义以及对变量的处理。对于规模比较小的程序,每个变量的意义和访问都由程序员自己控制,但对于需要多人长时间开发的大规模程序,存在访问其他人定义的变量的情况,这时候变量的安全性则成为问题。程序中有很多错误都是由于错误地访问了不该访问的
19、变量而引起的。面向过程程序设计语言中的函数结构中的局部变量在一定程度上解决了这个问题,但是全局数据结构或者变量中还是存在不安全的访问问题。面向对象程序将存储数据的变量和对数据(变量)的处理(方法)封装起来(私有化),从程序外部不能直接访问数据,而必须通过对外公开的方法进行访问,这就避免了对正确数据的错误操作,如图7.7所示。第7章 面向对象技术总论 图7.7 对象的封装性 第7章 面向对象技术总论 将Account对象中表示余额的属性balance(实型变量)隐藏起来,对外部程序不可见,外部程序只能通过公开的方法save()或者draw()来改变balance的值,这样就可以避免外部程序对其进
20、行错误的操作。比如说:在程序中直接对balance变量做乘除法操作(例如实现存钱操作时将“+”敲成“*”号),而编译程序是没有办法发现此错误的,因为对于实型变量来说,不能限制对其做乘除操作,从语法上来看这些都是合法的操作。对于账户余额来说,乘除法则是无意义的操作。因此可以通过隐藏数据,公开合法的操作接口来限定账户这种对象的内涵和外延,增加程序的安全性。第7章 面向对象技术总论 面向对象的封装性实现的是信息隐藏。仅将需要向外公开的方法和属性向外公开;所有不需要向外公开的方法和属性都被隐藏起来。正像电视机一样,内部电路元件对用户都隐藏起来,对外只公开用户可用的接口,如开关、音量调节、调台等。这种封
21、装性通过定义合适的操作接口来进一步确定事物的本质特征。对于传统的面向过程的程序设计语言来说,表示银行存款和图形尺寸时都是使用实型变量,没有区别,但实际上对这两种量的操作是有区别的。很明显,银行存款只允许增加、减少或者查询;对尺寸来说却能按比例放大或者缩小,即执行乘除法。类似的还有数据结构中的例子,保存线性表、堆栈、队列元素的数据存储结构可以是一样的,但对其允许的操作是不一样的。封装性增强了程序中变量的安全性,同时也增强了程序中数据类型、数据结构和变量的语义内涵,提高了程序分析方法的直观性。第7章 面向对象技术总论 7.3.2 继承性继承性软件重用技术始终是软件开发技术研究中的一个重要课题,从程
22、序行的简单复制到宏替换,从数据结构定义再到函数定义,从类的定义到类的继承,从构件到框架等,都是代码重用技术的体现。继承机制是一种高级的代码重用技术,子类自动继承父类的所有代码并且可以进行任意的覆盖和扩充。如图7.8所示,子类研究生继承了父类学生中的属性和操作,又扩充了新的属性和操作。子类和父类保持一种动态关系:当父类代码改变的时候,子类继承的那部分代码会自动修改,即子类对父类的继承不是简单的复制,而是动态的链接,子类和父类始终保持一种联系,这是一种与生俱来的、静态的联系,一旦定义,则无法改变。第7章 面向对象技术总论 子类对父类的扩充包括对父类同名属性和方法的覆盖以及增加新的属性和方法。过多的
23、继承层次会使程序结构变得异常复杂、难以理解并且难以维护。子类不仅仅继承了父类的代码,也继承了父类的类型,或者说和父类型是相容的。程序设计语言中的继承关系区别于生物界中的遗传关系,如父子关系,更像事物分类中的分类关系。父类往往是各子类的共性的抽象,是对所有子类对象的抽象。例如:汽车、自行车、三轮车的父类是车,车是一个抽象的概念,凡是具有轮子可以滚动行走的物体都可以称为车。又比如三角形、矩形、圆等具体图形的父类可以定义为图形类等。图7.8中,研究生属于学生中的一种,是特殊的学生,因此是从一般到特殊的分类关系。第7章 面向对象技术总论 图7.8 类的继承关系 第7章 面向对象技术总论 7.3.3 多
24、态性多态性多态性(polymorphism)是指同一种事物可以有多种不同的形态或者含义,也可以认为是从不同的角度观察同一事物,可以得到不同的视图。在面向对象程序设计语言中,多态性有三种含义。多态的第一种含义是方法的重载(Overload),在同一个类中可以存在同名不同参数的操作,这些操作的具体实现是不同的,即同名方法在不同的参数情况下有不同的实现。这反映了客观世界中对事物操作的复杂性和联系性,如对银行来说,存钱是一种操作,但根据用户出示的是存折还是银行卡,其具体的实现有所不同。编译程序通过参数类型或者个数来确定具体调用哪个方法,因为这种多态性是在编译阶段完成的,所以可以称为静态的多态性或者编译
25、期多态性。操作符重载也是基于这种多态性的。例如圆对象可以根据不同的初始条件进行构造,见下面代码。第7章 面向对象技术总论 class Circle public Circle(double x,double y,double r)/已知圆心坐标和半径 public Circle(Point center,double r)/已知圆心和半径 public Circle(double x1,double y1,double x2,double y2,double x3,double y3)/已知圆上三点坐标 public Circle(Point p1,Point p2,Point p3)/已知圆
26、上三点 public Circle(Point p1,Point p2,double r)/已知圆上两点和半径 第7章 面向对象技术总论 下面是引用上述定义创建圆对象的代码:Circle c1=new Circle();/创建一个默认的圆对象Circle c2=new Circle(new Point(2,2),5);/创建已知圆心和半径的圆对象Circle c3=new Cirlce(0,0,2,3,4,5);/创建已知圆上三点坐标的圆上述代码中同名方法具有不同的参数,给出了在不同初始条件下构建圆对象的方法。第7章 面向对象技术总论 多态的第二种含义是子类对父类的方法进行覆盖(overrid
27、e),程序会根据当前对象状态而自动调用父类或者子类对象的方法。这一点和下面讲的多态性的第三种含义本质上是相同的。这种多态性由于在运行期间才能确定,因此称为动态的多态性或者运行期多态性。第7章 面向对象技术总论 例如:Shape是图形类,Circle是其子类,父类和子类的方法getArea()具有不同的实现。public class Shape double getArea()return 0.0;public class Circle extends Shape double r;double getArea()return Math.PI*r*r;第7章 面向对象技术总论 上面类的对象实例创
28、建代码Shape s=new Circle()将子类对象实例赋值给父类的引用变量(这一点正是类型的多态性,本节后面详细解释),那么s.getArea()方法将调用父类还是子类的方法呢?按照类型分析,s是Shape类型,则s.getArea()方法应该是Shape的方法,但是s实际上指向的是Circle对象,所以s.getArea()方法应该是Circle的方法,但这是在运行期间才能确定的,因为s具体指向的对象只有在运行期才能确定。不同的语言在此处有不同的处理方法。在C+中,上述代码调用的是Shape的getArea()方法,但是如果在Shape的getArea方法定义前面加上virtual关键
29、字,即:virtual public double getArea();第7章 面向对象技术总论 则同样的代码s.getArea()调用的方法是子类Circle的方法。方法定义前面加上virtual的意思是指该方法的具体执行代码直到运行期才能确定。在Java中,对象的方法默认都是运行期确定的,因此s.getArea()一定是调用s实际指向的对象的方法,即Circle对象的方法。如果要想调用父类的area()方法,只需要让s指向父类对象即可:Shape s=new Shape();这种运行期确定方法的执行代码正如运行期分配或者删除对象空间一样,是非常灵活高效的,所以Java取其作为语言的默认特性
30、,这也是Java语言简洁高效且能迅速普及的原因之一。第7章 面向对象技术总论 多态的第三种含义是类型的多态或者类型造型(type cast),前者是指一个对象可以看成是多种类型,后者是指子类对象可以造型成父类型,即将子类对象看成是父类类型,类似于类型强制,注意只是“看成”是父类类型,而不是真正的父类对象,子类对象永远不能变成父类对象,而只能扮演成父类对象,以通过程序语法的类型匹配检查,但其本质上还是子类对象。这在生活实际中也是经常遇到的,例如一个研究生去应聘,如果企业只招聘本科生的话,他也可以将自己看成是本科生而降级使用,但他自己本质上还是研究生。除了子类对象可以扮演(造型)成父类类型外,某个
31、类的对象也可以造型成该类实现的接口类型。第7章 面向对象技术总论 造型的方法就是将该类对象赋值给某种类型的引用变量,如:A obj=new B(),B要么实现A接口,要么B是A的子类。定义引用变量并没有创建对象,相当于定义了一种类型约束。在面向对象语言中,这种造型称为向上造型(upcast),它是安全的,因为子类型肯定满足父类型的要求,子类型要么等于父类型,要么大于父类型(扩充)。从类的现实世界语义来看,子类和父类的关系是ISA(读作“是一个”)关系,即子类对象首先是一个父类。图7.9中的关系读作研究生是一个学生,这无疑是客观正确和可理解的。从哲学概念上来看,子类和父类正反映了特殊和一般、个性
32、和共性的关系,一般性寓于特殊性之中,共性寓于个性之中。这是面向对象技术中继承或者接口概念的本质,这也是只有具有继承或者实现接口关系的对象才能造型的原因。第7章 面向对象技术总论 图7.9 ISA关系 第7章 面向对象技术总论 数据类型在程序设计语言中的重要性毋庸置疑,它是内存分配、类型检查、操作检查的基础。程序语言中数据类型的多少是衡量该语言功能是否强大的依据之一,现在的程序语言都提供了大量标准数据类型以及自定义数据类型的机制。在面向对象程序设计语言中,类可以看成是一种自定义类型。类型检查也是程序安全性检查机制之一,通过检查相关操作的类型匹配可以发现很多不兼容的错误。比如:赋值操作、各种运算操
33、作,如果没有类型检查的话,将会出现很多程序员难以察觉的错误,这也是过去类型检查机制较弱的弱类型语言(如C语言)容易出错的原因。第7章 面向对象技术总论 面向对象机制中类的定义实际上增强了类型检查的安全性,一个类就相当于一种自定义的数据类型,不同类定义的变量是不允许相互赋值的,这虽然增强了程序的安全性,但却带来了另外一个问题,那就是代码效率很低,针对每一个事物都需要定义一个类,例如定义堆栈类就得针对不同的元素类型定义多个类,每个类只能接收一种类型元素。C+采用一种叫做模板(template)的机制来处理这个问题,而Java则采用多态性来解决这个问题。多态(polymorphism)的原意就是同一
34、个事物可以具有多种状态,或者说同一个事物在不同的场合、从不同的角度可以看成是不同的东西,这是客观事物复杂性的程序表现。第7章 面向对象技术总论 7.3.4 抽象性抽象性抽象是人类思维的本质特性之一。抽象性是对复杂事物本质和特性的提炼和概括的能力,可以说没有抽象就没有理论思维,就没有指导认识世界改造世界的一般性结论,也就没有系统分析和设计。在程序中始终存在着抽象性,数据类型是数据结构和操作接口的抽象,常量是程序中常数的抽象,变量是程序中变化的数据的抽象,函数是实现某个功能或者处理代码的抽象,类是多个实例对象结构(属性和操作接口)共性的抽象,抽象类或者接口又是多个类公共接口的抽象。第7章 面向对象
35、技术总论 面向对象技术将抽象性引入到代码的实现中,可以实现很多更抽象、更一般、更统一的方法。比如说:Shape是所有图形对象的父类,是抽象的,则方法getArea(Shape s)可以返回任何图形的面积,totalArea(Shape s)则可以返回任意多个任意图形的面积和,draw(Shapes)则可以画出任意多个任意图形。注意:这些方法本身都具有抽象性、一般性的含义。当然,这些抽象的方法并没有真正去实现计算每个具体图形的面积或者画出具体的图形,而只是完成通用的操作,如对所有的图形进行求和或者画出所有的图形(两者都是对集合进行遍历),而把具体的操作都交给具体的子类(如圆、矩形)来实现。在面向
36、对象程序设计语言中,抽象类、接口或者模板类都很好地实现了抽象的功能。第7章 面向对象技术总论 由于程序中引入了抽象的操作,因此使得程序结构出现依赖倒置的现象。过去结构化分析方法得到的系统结构是自上而下、逐步求精,上层抽象的模块依赖于下层具体的模块,上层模块通过调用下层模块完成任务,或者说先有下层模块,才有上层模块。面向对象程序的继承结构中则是下层依赖于上层,因为上层是父类,下层是子类,先有上层再有下层,因此程序变得更抽象。程序结构依赖性对比如图7.10所示,左边部分的每个矩形框是函数,右边部分的每个矩形框是类。第7章 面向对象技术总论 图7.10 顶层模块和底层模块之间的依赖关系 第7章 面向
37、对象技术总论 7.4 面向对象分析方法面向对象分析方法系统分析方法就是把现实世界或者问题域中的概念和过程转换成求解域或程序域中元素的方法。因此系统分析方法是和程序域元素密切相关的。结构化或者面向过程的分析方法是把现实世界或者问题域中的过程处理抽象成概念模型中的数据输入、数据处理和结果输出,然后将处理过程转换成程序结构中的函数。程序中的函数有些是直接来自于现实世界中的处理过程,如计算工资,但仅靠现实世界中的处理过程是不够的,在程序中还有很多处理过程是和计算机或者程序本身密切相关的,如输入数据的过程等。第7章 面向对象技术总论 面向对象的分析方法就是把现实世界或者问题域中的事物、概念、过程等抽象成
38、概念模型中的对象或类,然后转换成程序语言中的对象或类。程序语言中的类概念本身也来自于现实世界中的对象,因此概念模型中的类和程序语言中的类是一致的。但是仅靠现实世界中的类是不够的,作为信息系统或者程序模型,本身也有自己独特的机制和规律,具有区别于现实世界或者问题域的特点,例如每个程序都具有一定的运行环境和操作界面等,这些因素也被抽象为系统中的类,视为系统类。现实世界中抽取的类一般称为业务类或者领域类,即在现实世界中存在有原型的类。业务类又可以分为分析类和设计类,前者是从现实世界中直接抽取的类,后者是对分析类的抽象、包装、组合、扩充和修饰,如设计模式中的一些父类、实用类等。第7章 面向对象技术总论
39、 按照目前广泛流行的MVC模式,现实世界中的类相当于模型类(Model),确定了现实世界事物本身的逻辑、联系和规律等,如学生、职工、工资、力等。其他的类,如表现类(View),则是对模型数据的计算机表现,是人机接口界面类;控制类(Control)则控制系统的运行流程。第7章 面向对象技术总论 从系统的顶层结构到系统的微观结构中,MVC结构都是存在的,例如:Struts框架结构是系统的整体架构,是符合MVC模式的,而Java的图形界面swing组件类本身也是按照MVC模式设计的。MVC模式实际上给出了构建信息系统的一种过程和方法:即从业务对象到系统对象,从业务模型到系统模型的演化过程。首先抽象现
40、实世界中的相关对象,称为业务对象,在此基础上添加对其的表现类即视图类,系统流程(宏观)和业务流程(微观)的控制则转换成控制类。一般来说,业务类可以做到与实现环境或者实现语言无关,但界面类或者系统控制类则可能和实现环境及实现语言有关。从现实世界对象模型到系统对象模型的演化过程如图7.11所示,系统对象中最上层的是业务对象,第二层是控制对象,最底层是界面对象。第7章 面向对象技术总论 图7.11 现实世界的对象模型向程序世界的对象模型转换举例一 第7章 面向对象技术总论 有些系统模型的类会更多一些,另一个现实世界模型向程序世界模型转换的例子超市购物向网上购物网站的转换,其中,业务模型包括产品(Pr
41、oduct)、购物车(Cart)、订单(Order)和客户(User)四种;系统模型类包括产品(Product)、购物车(Cart)、订单(Order)、订单数据库(DB Order)和客户(User)五种。从业务世界模型向程序世界模型转换的示意图如图7.12所示。第7章 面向对象技术总论 图7.12 现实世界的对象模型向程序世界的对象模型转换举例二 第7章 面向对象技术总论 7.5 面向对象技术与程序结构面向对象技术与程序结构7.5.1 概述概述程序对外提供的功能是其外部特性,内部也有着自己独特的结构,即程序结构。程序中具有完整语义的最小语法单位是表达式,语句是程序执行的最小单位,语句的集合
42、组成了程序。语句相当于原子,语句与语句之间的关系形成程序结构,如顺序、选择、循环。数据结构、函数定义也是一种程序结构,称为程序模块,它由完成某个特定功能的多条语句组成。模块的类型包括数据模块、算法模块或者二者的综合。程序模块是作为一个整体存在的,可以独立地开发存储,具有独立性、安全性、语义性和重用性。其中数据模块类似于数据结构定义,比如C语言中的结构体;算法(程序)模块类似于函数。数据和算法(程序)的综合就是面向对象程序中的类。第7章 面向对象技术总论 在程序从非结构化到结构化再到面向对象的进化过程中,程序结构越来越复杂、越来越丰富、重用粒度越来越大、结构层次也越来越深,对外呈现的功能也越来越
43、强大。其内部结构和外在表现之间的关系符合自然界和社会进化的一般规律,即内部结构越复杂,其对外呈现的功能也就越强大。但是,这种内部结构必须是建立在一种优化合理的基础上,而不是简单的堆积。目前的包类函数的层次结构就是一种公认的优化合理结构。第7章 面向对象技术总论 程序结构中包含静态的结构和动态的结构。静态的结构就是程序代码之间的关系,如类的继承、关联关系等,是代码定义阶段的关系;动态结构是函数的调用或者向对象发消息的过程,是代码执行时的关系。动态结构要以静态结构为基础。图7.13和图7.14分别表示了面向过程和面向对象程序之间的静态结构关系和动态结构关系,从图中可以看出,面向对象程序的结构要比面
44、向过程程序的结构复杂得多。第7章 面向对象技术总论 软件工程的实践证明,程序的结构是通过不断的改进而得到优化的,不会一步到位。好的程序结构可以通过有经验的开发人员在设计阶段通过精心设计而得到,也可以通过对已有的结构中不太好的代码进行不断改进而得到。通过代码改进程序结构的方法也称为“重构”。由于重构是从质量欠佳的代码基础进行改进的,而不是一下拿出高质量的结构设计,因此这种方法更受初学者的欢迎,也越来越受到软件界的重视,目前几乎所有的主流开发环境都提供了对重构工具的支持。第7章 面向对象技术总论 图7.13 结构的层次静态结构 第7章 面向对象技术总论 图7.14 程序执行的线索动态结构 第7章
45、面向对象技术总论 7.5.2 重构重构重构(Refactor)是指在不改变代码的外在功能的前提下重新设计已有代码,以获取代码新的特性。这里新的特性主要就是由于结构的改进而带来的高效性、安全性、稳定性、可维护性和可扩充性等。根据上一小节中所描述的程序结构的改进过程可以看出,这种重构是完全可能的,也是很有必要的。根据外在功能和内部结构的关系来看,重构的目的主要在于改进程序结构。需要注意的是,重构不是整体重新建造(Reconstructor),可能只是局部的修改(Refactor),如把一些代码抽象成方法,以提高程序结构的粒度,增加重用度。甚至可能只是非常简单的重命名,以改善程序的可读性等。重构对于
46、那些没有做充分的设计而直接编码的软件开发过程而言是非常有效的。第7章 面向对象技术总论 常见的重构方法有:提取方法(Extract Method)、引入父类(Introduce Super Class)或者接口(Interface)、属性和方法上移或者下移(Attribute or Method Move up or Move down)等。重构所影响的程序范围可能很小或者很大,但是即使最小的变化也可能引入bug。一处修改可能导致整个代码变化,所以重构后必须要测试所有可能受影响的地方,这样才能保证对外的功能不会改变。第7章 面向对象技术总论 重构的种类有很多,重构的工作量有时候也会很大,尤其是
47、当现存代码比较多的时候。目前主流的开发环境如Eclipse、Microsoft Visual Studio 2005等,都提供自动进行重构的工具。当然,不同的语言和开发环境提供的重构工具种类会有所不同,下面列举了一些常见的重构方法:(1)try/catch重构:将普通代码块置于try/catch块中,将代码的正常执行过程和错误处理过程分离开来,可以增加代码的安全性和鲁棒性。第7章 面向对象技术总论(2)重命名(Rename)和移动(Move):由于各种可能的原因,对现存代码中的包、类、接口、方法、属性或域变量、局部变量等进行重新命名,同时对所有相关的引用(reference)都作相应的修改。该
48、重构还包括移动类和包进行重构的方法。即将包或者类从现有的位置移到另外的包中,或把静态成员从一个类中移到另外的类中。这些重构方法都属于静态的结构重构,也可以在设计阶段针对模型进行。如果在设计阶段进行此类重构,则需要重新进行正向工程(Forward Engineering),而且原来的代码会自动注释掉,需要重新编码。如果在代码环境中进行重构,则会自动实现重构之后的所有代码。第7章 面向对象技术总论(3)引入常量、变量和方法(Introduce Constant and Variable,Extract Method):将程序中的常数定义成常量、表达式定义成变量、代码片断定义成方法都是代码结构的改进
49、。也可以把局部变量转换成属性变量,即全局变量。(4)改变方法参数(Change Method Parameter):方法的参数是方法签名的一部分,是方法调用中动态变化的地方。修改参数实际上就是修改方法签名。在提取方法重构中,可以将方法中表达式代码中的常数、变量或者表达式转换成方法参数,这样该方法就具有更一般的意义。第7章 面向对象技术总论(5)泛化类型(Generalize Type):使用父类型代替子类型。这样的程序更具有一般性,更能适应变化。例如:定义一个集合类型变量,使用ArrayList v=new ArrayList();重构成List v=new ArrayList(),这样将来代
50、码无论改成List v=new LinkedList()还是List v=new Vector(),其余代码都不受影响。(6)匿名类转换为内部类(Anonymous class to Inner Class):匿名类转换成内部类,内部类转换成外部类,从而提高可重用性。第7章 面向对象技术总论(7)还原方法:是抽取方法(Extract Method)的逆过程。使用“方法调用”可以改善程序结构,但是这样势必要增加调用开销。若某些方法只有一个调用者,就可以把该方法的代码放入调用者,以减少调用开销,改进性能。(8)封装属性(Encapsulation attribute):是旨在提高程序封装性的一种重
侵权处理QQ:3464097650--上传资料QQ:3464097650
【声明】本站为“文档C2C交易模式”,即用户上传的文档直接卖给(下载)用户,本站只是网络空间服务平台,本站所有原创文档下载所得归上传人所有,如您发现上传作品侵犯了您的版权,请立刻联系我们并提供证据,我们将在3个工作日内予以改正。