软件工程2-11.构件级设计.ppt
《软件工程2-11.构件级设计.ppt》由会员分享,可在线阅读,更多相关《软件工程2-11.构件级设计.ppt(78页珍藏版)》请在三一文库上搜索。
1、软件工程,第二部分 软件工程实践 第11章 构件级设计 Chapter 11 Component-Level Design,在体系结构设计阶段可以定义一套完整的软件构件。这个阶段的软件构件抽象层次比较高,没有接近代码抽象级。 构件级设计定义了数据结构、算法、接口特征和分配给每个软件构件的通信机制。,构件级设计,构件是计算机软件中的一个模块化的构造块。 OMG UML规范对构件的定义:系统中模块化的、可配置的和可替换的部件,该部件封装了实现并暴露了一组接口。 OMG Unified Modeling Language Specification OMG01 defines a component
2、 as “ a modular, deployable, and replaceable part of a system that encapsulates implementation and exposes a set of interfaces.”,11.1 什么是构件,在面向对象软件工程环境中,构件包括一组协作的类(有时,一个构件只包含一个单独的类)。 OO view: a component contains a set of collaborating classes。,11.1.1 面向对象的观点,11.1.1 面向对象的观点,构建分析模型,体系结构设计,构件级设计,可能与Pr
3、icingTable构件协作,可能与JobQueue构件协作,与面向对象的构件相似,传统的软件构件也来自分析模型。不同的是,传统的软件构件是以分析模型中的数据流要素作为导出构件的基础。,11.1.2 传统的观点,11.1.2 传统的观点,相当于PrintJob类定义的操作,相当于PrintJob类定义的操作,相当于PrintJob类定义的操作,相当于PrintJob类定义的操作,相当于PrintJob类定义的操作,相当于PrintJob类定义的操作,前面有两种构件级设计的观点:面向对象观点、传统观点。都假定从头开始设计构件。 另一种方法:使用已有构件来构造系统。,11.1.3 其他相关观点,1
4、1.1.3 其他相关观点,一、相关背景的比较 COM/DCOM/COM+:为了适应更加复杂应用的需要,Microsoft公司推出了构件对象模型COM,COM支持同一台计算机上不同进程间对象的调用;由于分布式处理系统的广泛应用和与CORBA竞争的需要,Microsoft公司于1997年推出了COM的分布式版本,即DCOM,支持对象间通过网络(包括局域网、广域网、因特网)进行通信。 CORBA:CORBA(Common Object Request Broker Architecture公共对象请求代理体系结构)是由OMG工业集团定义的分布对象计算模型和系统结构。OMG与1990年提出了一个对象管
5、理结构(OMA),这是CORBA的最原始的构想及基础。在OMA的基础上,1991年一些大公司联合提出了CORBA1.1版。目前有不少公司从事CORBA的实现工作,并推出了基于CORBA的产品。CORBA仅是一个分布对象规范,没有限定使用何种程序设计语言,其目的是不使CORBA束缚在某种特定程序设计语言上。用不同语言书写的对象,只要符合CORBA规范,就可以相互调用。但由于CORBA规范仅是一个书面的说明,各公司对其理解未必一致,规范中也有不少部分没有做统一规定,由厂家自行决定,因此各厂家基于CORBA的产品未必相互兼容。 Java Beans:Java Beans是于1996年提出的基于Jav
6、a语言的分布对象模型,其构件叫Bean。Bean就是以Java语言中的类和对象为基础定义的。当初,Java Beans主要为一些软件构造工具提供一些可视化构件。后经不断扩充,发展成为一种通用分布对象模型。,11.1.3 其他相关观点,二、基本概念的比较 COM/DCOM:COM/DCOM对象模型设计的指导思想是健壮、高效和切实可行。COM对象具有多个接口,通过每个接口可以访问一组成员函数。成员函数相当于方法。每个对象拥有自己的数据,表示对象的状态。数据只能通过接口访问,用户和应用程序不能越过接口访问数据。每个接口仅包含其所属成员变量函数的调用说明及引用它的指针。成员函数的实现不是对象的一部分,
7、一般可以有两种方法实现:一是用动态链接库DLL实现,二是作为一个可执行模块EXE实现。不管哪一种实现,成员函数都可以动态调用,直接执行,不需要编译连接。甚至调用者所用的程序设计语言与实现成员函数所用的程序设计语言也可以是不同的。用DLL实现时,在调用成员函数前必须将DLL加载到本地进程的地址空间,不能跨进程空间进行访问。而EXE模块不受这个限制,可以跨进程访问。 在COM对象的多个接口中,有一个接口是每个对象必备的该接口被命名为Iunknown,接口名前面加字母I,以便识别。 COM/DDCOM也有类的概念,类也看成是一种对象,称为类对象。由于COM/DCOM不支持继承的概念,一个对象的所有接
8、口及其成员函数都已在对象中定义,在引用对象时不必到其所属的类或其祖先类中查询有关的内容。只有在创建一个对象(即类的一个实例)时,才用到类中的内容。在COM中,除了类以外,还有类型(type)的概念。类型比类更抽象,它与实现无关。而类中可含有一些与实现有关的属性,诸如支持它的软件名称、所用的图表等。例如一个复合文件可以定义成一个类型,但这种类型可用不动的字处理软件、电子表格软件、多媒体软件来实现,形成不同的类,可用不同的图表表示。用户可以根据运行环境在同一类型中选择合适的类。,11.1.3 其他相关观点,二、基本概念的比较 CORBA CORBA的对象模型基本上按OMG所定义的公共对象模型COM
9、(不同于微软的COM),支持类、封装、继承和多态,是一个功能比较完备的对象模型。对象或类之间可按客户/服务器方式互相调用。每个对象或类即可以作为客户,也可以作为服务器,有时还可以兼作客户和服务器。 客户对象和服务器对象只通过消息交互作用。客户对象向服务器对象发出请求,服务器对象响应客户对象的请求完成一定的操作,并返回操作结果和必要的信息。它们只通过消息往来,不必了解与请求无关的功能。即使客户对象或服务对象重新实现,只要接口的语法和语义不变,不影响用户的使用。 客户和服务器的通信方式一般有两种:常用的是同步方式,即客户提交请求后,客户要等到服务器放操作执行完毕并返回操作结果或信息后,才继续运行;
10、另一种方式是异步方式,即客户提交请求后,可继续运行。,11.1.3 其他相关观点,二、基本概念的比较 Java Beans 与其它分布对象模型一样,Java Beans是以对象作为基本构件。类是对象的模板,而对象(即Bean)是有类生成的一个实例。类中可有多种构造对象的函数。如果生成对象时,不指明具体的构造函数,仅指明类名,则用下面的接口调用:new ()。这就表示用类中的缺省构造函数Constructor()生成对象。在Java Beans中,一组对象相互联系,相互作用,有公共的接口,服务于某一应用目的,则这组对象组成一个容器。以上的概念和方法与CORBA、DCOM相类似。,11.1.3 其
11、他相关观点,构件级设计基于分析模型、体系结构模型。面向对象方法中构件级设计主要关注分析类的细化(特定的问题域类)和基础类的定义和精化。,11.2 设计基于类的构件,四个基本设计原则: 开关原则 Liskov替换原则 依赖倒置原则 接口分离原则,11.2.1 基本设计原则,开关原则 模块应该对外延具有开放性,对修改具有封闭性。 The Open-Closed Principle (OCP). “A module component should be open for extension but closed for modification. 包含以下两层意思: 1. 所谓的open就是类,模
12、块,乃至函数对以后扩展而言是开放的,也就是说类,模块,函数要能方便以后的功能扩展。 2. 所谓的close就是类,模块,乃至函数对以后的修改而言是关闭的,也就是说类,模块,函数因需求变更带来的修改应该是最小的。(当然也有特殊的情况,较大的需求变更带来的修改也可能是很大的。),11.2.1 基本设计原则,/ 违背开关原则的一个例子 class GraphicEditor public void drawShape(Shape s) if (s.m_type=1) drawRectangle(s); else if (s.m_type=2) drawCircle(s); public void d
13、rawCircle(Circle r) public void drawRectangle(Rectangle r) class Shape int m_type; class Rectangle extends Shape Rectangle() super.m_type=1; class Circle extends Shape Circle() super.m_type=2; 在这个例子中,如果现在需求变更了,需要支持其他图形的绘制,如果让你在原有的基础上增加代码你会怎么做?毋庸置疑,你需要在drawShape中增加if分支来增加对新的图形的绘制。,但如果我们将原来的设计变更如下: /
14、符合开关原则的一个好例子 class GraphicEditor public void drawShape(Shape s) s.draw(); class Shape abstract void draw(); class Rectangle extends Shape public void draw() / draw the rectangle class Circle extends Shape public void draw() / draw the Circle 看看是不是简洁了很多,再来看看原来的drawShape函数,这里它只是调用了s的draw函数,原来的 drawCir
15、lcle,drawRectangle也没了。现在如果再增加新的图形就容易多了,我只要从Shape继承一个新的类,定义好其draw方法, GraphicEditor不用修改,编译的时候也只用编译新增的图形CPP文件,可使用新增图形类的文件,这里还减少了编译依赖。其实这里还可以看出另外一个原则就是依赖倒置原则,这里GraphicEditor只依赖于Shape接口,并不依赖具体的实现类,像Circle,Rectangle等等。,如何使用开闭原则: 抽象约束 第一,通过接口或者抽象类约束扩展,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的public方法; 第二,参数类型、引用对象尽量使用接口
16、或者抽象类,而不是实现类; 第三,抽象层尽量保持稳定,一旦确定即不允许修改。 元数据(metadata)控制模块行为 元数据就是用来描述环境和数据的数据,通俗地说就是配置参数,参数可以从文件中获得,也可以从数据库中获得。 Spring容器就是一个典型的元数据控制模块行为的例子,其中达到极致的就是控制反转(Inversion of Control),11.2.1 基本设计原则,Liskov替换原则 子类可以替换基类。将子类传递给构件来代替基类时,使用基类的构件应该仍然能够正确完成其功能。 The Liskov Substitution Principle (LSP). “Subclasses s
17、hould be substitutable for their base classes. LSP原则要求源自基类的任何子类必须遵守基类与使用该基类的构件之间的隐含约定。 这里约定既是前置条件构件使用基类前必须为真;又是后置条件构件使用基类后必须为真。 定义:所有引用基类的地方必须能透明地使用其子类的对象。通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。,11.2.1 基本设计原则,里氏替换原则(Liskov Substitution Principel)
18、是解决继承带来的问题。 继承的优点: 代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性; 提高代码的重用性; 子类可以形似父类,但又异于父类; 提高代码的可扩展性; 提高产品或项目的开放性。 继承的缺点: 继承是侵入性的,只要继承就必须拥有父类的所有属性和方法; 降低代码的灵活性,子类必须拥有父类的属性和方法,让子类增加了约束; 增强了耦合性,当父类的常量、变量和方法被修改时,必须考虑子类的修改。,11.2.1 基本设计原则,含义: 子类必须完全实现父类的方法 在类中调用其他类时务必要使用父类或接口,如果不能使用父类或接口,则说明类的设计已经违背了里氏替换原则。 如果子类不能完整地
19、实现父类的方法,或者父类的某些方法在子类中发生了“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承。,11.2.1 基本设计原则,目的: 采用里氏替换原则的目的就是增强程序的健壮性,版本升级时也可以保持非常好的兼容性。即使增加子类,原有的子类还可以继续运行。在实际项目中,每个子类对应不同的业务含义,使用父类作为参数,传递不同的子类完成不同的业务逻辑。,11.2.1 基本设计原则,class Animal private string name; void Animal(string name) this.name = name; public void Description
20、() Console.WriteLine(“This is a(an) “ + name); /下面是它的子类猫类: class Cat extends Animal void Cat(string name) public void Mew() Console.WriteLine(“The cat is saying like mew“); /下面是它的子类狗类: class Dog extends Animal void Dog(string name) public void Bark() Console.WriteLine(“The dog is saying like bark“);
21、 ,/最后,我们来看看客户端的调用过程: public void DecriptionTheAnimal(Animal animal) if (typeof(animal) is Cat) Cat cat = (Cat)animal; Cat.Description(); Cat.Mew(); else if (typeof(animal) is Dog) Dog dog = (Dog)animal; Dog.Description(); Dog.Bark(); 通过上面的代码,我们可以看到这个设计的扩展性不好。 是什么原因呢?其实就是因为不满足替换原则,子类如Cat有Mew()方法父类根本没
22、有,Dog类有Bark()方法父类也没有,两个子类都不能替换父类。这样导致了系统的扩展性不好和没有实现运行期内绑定。,class Animal private string name; void Animal(string name) this.name = name; public void Description() Console.WriteLine(“This is a(an) “ + name); abstract void doAction(); /下面是它的子类猫类: class Cat extends Animal void Cat(string name) public vo
23、id doAction() Console.WriteLine(“The cat is saying like mew“); /下面是它的子类狗类: class Dog extends Animal void Dog(string name) public void doAction() Console.WriteLine(“The dog is saying like bark“); ,/最后,我们来看看客户端的调用过程: public void DecriptionTheAnimal(Animal animal) animal.Description(); animal.doAction(
24、); /或 public void DecriptionTheAnimal(Cat animal) animal.Description(); animal.doAction(); 通过上面的代码,我们可以看到客户端的调用满足替换原则。,依赖倒置原则 依赖于抽象,而非具体实现。 Dependency Inversion Principle (DIP). “Depend on abstractions. Do not depend on concretions.” 在传统的结构化编程中,最上层的模块通常都要依赖下面的子模块来实现,也称为高层依赖底层!DIP原则就是要逆转这种依赖关系,让高层模块不
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 软件工程 11. 构件 设计
链接地址:https://www.31doc.com/p-3499345.html