第7章构造阶段 在设计完成后,构造阶段是根据设计模型“生产“软件系统的过程。在这个阶 段,关注的重点是如何高效、高质量地把软件代码编写完成。我们需要确定开发 环境、制定编码规范,并按照计划协调各个团队开展工作。 尽管构造阶段看上去似乎不像设计阶段没有那么多创造性,设计中依然也包 括了一些决策和创新工作。有一些人认为如果设计模型做得足够详细,那么代码 生成就是一个机械的翻译过程。这一观点并不正确,因为在构造阶段,必然会发 现一些在设计阶段没有考虑到的细节,或者在设计阶段考虑不够正确的情况,这 些问题需要一一解决。 在本章中,我们将介绍与构造相关的一些概念,包括正向工程、逆向工程、 重构、单元测试等概念。然后介绍依据模型生成代码的具体方法,并对设计中可 能进行的优化进行具体的讨论。 7.1构造阶段的主要内容 构造阶段要完成代码的编写、数据库的设计等工作。构造阶段中运用建模工 具、编程环境、测试工具等多种有助于提高生产力的手段。构造阶段也需要按照 一定的规范去编写代码,以形成风格一致、良好的代码。 在构造阶段,我们除了提交完成的代码、数据库定义文件等交付物,还将撰 写模块开发卷宗,以对自己的开发工作进行记录。 7.2正向工程与逆向工程 7.2.1正向工程与模型驱动的体系架构 正向工程(forward engineering)是通过到实现语言的映射而把模型转换为 代码的过程。通过正向工程可以实现从建模到代码的联接和过渡。许多工具提供 了正向工程的支持
第 7 章 构造阶段 在设计完成后,构造阶段是根据设计模型“生产“软件系统的过程。在这个阶 段,关注的重点是如何高效、高质量地把软件代码编写完成。我们需要确定开发 环境、制定编码规范,并按照计划协调各个团队开展工作。 尽管构造阶段看上去似乎不像设计阶段没有那么多创造性,设计中依然也包 括了一些决策和创新工作。有一些人认为如果设计模型做得足够详细,那么代码 生成就是一个机械的翻译过程。这一观点并不正确,因为在构造阶段,必然会发 现一些在设计阶段没有考虑到的细节,或者在设计阶段考虑不够正确的情况,这 些问题需要一一解决。 在本章中,我们将介绍与构造相关的一些概念,包括正向工程、逆向工程、 重构、单元测试等概念。然后介绍依据模型生成代码的具体方法,并对设计中可 能进行的优化进行具体的讨论。 7.1 构造阶段的主要内容 构造阶段要完成代码的编写、数据库的设计等工作。构造阶段中运用建模工 具、编程环境、测试工具等多种有助于提高生产力的手段。构造阶段也需要按照 一定的规范去编写代码,以形成风格一致、良好的代码。 在构造阶段,我们除了提交完成的代码、数据库定义文件等交付物,还将撰 写模块开发卷宗,以对自己的开发工作进行记录。 7.2 正向工程与逆向工程 7.2.1 正向工程与模型驱动的体系架构 正向工程(forward engineering)是通过到实现语言的映射而把模型转换为 代码的过程。通过正向工程可以实现从建模到代码的联接和过渡。许多工具提供 了正向工程的支持
长久以来,在软件工程领域有一个梦想,那就是仅仅通过构造模型而不用编 写代码就能完成软件开发。随着许多技术包括中间件、UML、XML、软件框架、 设计模式、正向工程等的发展,我们向这一目标不断前进。 模型驱动体系架构(Model Driven Architecture,MDA)是由国际标准化组 织对象管理联盟(Object Management Group,.OMG)提出的一个构想,目的是将 目前的开发行为提升到更高的抽象层级一一分析模型级,把针对特定计算平台的 编码工作交由机器自动完成,这样的情况下,业务逻辑与实现技术实现了解耦, 二者相对独立变化,因此模型的价值被最大化。 MDA在目前技术的基础上,分离出了两个抽象级别的模型:平台无关模型 (Platform Independent Model,.PIM)和平台相关模型(Platform Specialize Model, PSM)。PIM是一个纯粹的不考虑实现技术的分析模型,而PSM可以视为一个基 于特定实现技术,比如J2EE的设计模型。工程师们只需要建立表达业务逻辑的 PIM,从PIM到PSM及至代码实现都是由第三方的自动化工具来完成的。 为了实现MDA,OMG制定了一系列的标准: ● UML:UML被MDA用来描述各种模型。它是MDA的基础。 ● MOF:MOF(Meta Object Facility)是比UML更高层次的抽象,它的目的是 为了描述UML的扩展或者其它未来可能出现的类UML的建模语言。 ● XMI:XMI(XML-based metadata Interchange)是基于XML的元数据交换。 它通过标准化的XML文档格式和DTDs(Document Type Definitions)为各 种模型定义了一种基于XML的数据交换格式。这使得作为最终产品的模型 可以在各种不同的工具中传递。 ●CWM:CWM(Common Warehouse Metamodel)提供了一种数据格式变换 的手段,在任意级别的模型上都可以使用CWM来描述两种数据模型之间的 映射规则。 UML、MOF、XMI、CWM等一系列标准分别解决了MDA的模型建立、模型 扩展、模型交换、模型变换这几个方面的问题。OMG试图通过标准化的定义, 扩大MDA的应用范围。同时通过这样一个可扩展的建模语言环境,T厂商可以 自由实现自己的建模语言,以及语言到可执行代码的映射。 针对MDA的思想,目前不少厂商已经推出了一些工具。然而,目前离OMG 的最终构想还存在一定的差距
长久以来,在软件工程领域有一个梦想,那就是仅仅通过构造模型而不用编 写代码就能完成软件开发。随着许多技术包括中间件、UML、XML、软件框架、 设计模式、正向工程等的发展,我们向这一目标不断前进。 模型驱动体系架构(Model Driven Architecture,MDA)是由国际标准化组 织对象管理联盟(Object Management Group, OMG)提出的一个构想,目的是将 目前的开发行为提升到更高的抽象层级——分析模型级,把针对特定计算平台的 编码工作交由机器自动完成,这样的情况下,业务逻辑与实现技术实现了解耦, 二者相对独立变化,因此模型的价值被最大化。 MDA 在目前技术的基础上,分离出了两个抽象级别的模型:平台无关模型 (Platform Independent Model,PIM)和平台相关模型(Platform Specialize Model, PSM)。PIM 是一个纯粹的不考虑实现技术的分析模型,而 PSM 可以视为一个基 于特定实现技术,比如 J2EE 的设计模型。工程师们只需要建立表达业务逻辑的 PIM,从 PIM 到 PSM 及至代码实现都是由第三方的自动化工具来完成的。 为了实现 MDA,OMG 制定了一系列的标准: UML:UML 被 MDA 用来描述各种模型。它是 MDA 的基础。 MOF:MOF(Meta Object Facility)是比 UML 更高层次的抽象,它的目的是 为了描述 UML 的扩展或者其它未来可能出现的类 UML 的建模语言。 XMI:XMI(XML-based metadata Interchange)是基于 XML 的元数据交换。 它通过标准化的 XML 文档格式和 DTDs(Document Type Definitions)为各 种模型定义了一种基于 XML 的数据交换格式。这使得作为最终产品的模型 可以在各种不同的工具中传递。 CWM:CWM(Common Warehouse Metamodel)提供了一种数据格式变换 的手段,在任意级别的模型上都可以使用 CWM 来描述两种数据模型之间的 映射规则。 UML、MOF、XMI、CWM 等一系列标准分别解决了 MDA 的模型建立、模型 扩展、模型交换、模型变换这几个方面的问题。OMG 试图通过标准化的定义, 扩大 MDA 的应用范围。同时通过这样一个可扩展的建模语言环境,IT 厂商可以 自由实现自己的建模语言,以及语言到可执行代码的映射。 针对 MDA 的思想,目前不少厂商已经推出了一些工具。然而,目前离 OMG 的最终构想还存在一定的差距
Finance Manutacturing E-Commerce e CORBA CES UML Space Model Driven Telecom Architecture MOF CWM JAVA .NET EVENTS Transportation HealthCare More.. 图7-1模型驱动体系架构示意图 7.2.2逆向工程 “逆向工程”的起源是对硬件产品的分析。人们通过分析竞争对手的硬件产 品以便改进自己的产品、或者仿照对手的产品。这个概念应用到软件系统时,指 的是人们利用方法获得对软件系统及软件系统结构的理解。对一个硬件系统实施 逆向工程,一般是为了得到这个系统的复制品:而对一个软件系统实施逆向工程, 通常是为了获得对这个系统在设计层次上的理解,以便于系统的维护、巩固、移 植。 在基于模型进行软件开发的过程中,我们通过正向工程生成了代码框架,在 编写代码的过程中可能会对原来的代码框架进行修改,这些修改会导致模型与代 码的不一致,因此,我们通过逆向工程再次生成模型,从而保证模型与代码的一 致性。 近几年来,开放源代码逐渐成为一种趋势,为了达到软件架构和设计模式的 复用,从源代码中获取软件设计模式和架构模式也将成为广泛的需求,逆向工程 就是一个有用的工具。 7.3单元测试与测试驱动开发 在软件开发过程中,开发者需要保证自己编写的代码是正确的。单元测试就 是由开发者自己编写一小段代码,用于检验被测代码的某一小的、明确的功能是 否正确
图 7-1 模型驱动体系架构示意图 7.2.2 逆向工程 “逆向工程”的起源是对硬件产品的分析。人们通过分析竞争对手的硬件产 品以便改进自己的产品、或者仿照对手的产品。这个概念应用到软件系统时,指 的是人们利用方法获得对软件系统及软件系统结构的理解。对一个硬件系统实施 逆向工程,一般是为了得到这个系统的复制品;而对一个软件系统实施逆向工程, 通常是为了获得对这个系统在设计层次上的理解,以便于系统的维护、巩固、移 植。 在基于模型进行软件开发的过程中,我们通过正向工程生成了代码框架,在 编写代码的过程中可能会对原来的代码框架进行修改,这些修改会导致模型与代 码的不一致,因此,我们通过逆向工程再次生成模型,从而保证模型与代码的一 致性。 近几年来,开放源代码逐渐成为一种趋势,为了达到软件架构和设计模式的 复用,从源代码中获取软件设计模式和架构模式也将成为广泛的需求,逆向工程 就是一个有用的工具。 7.3 单元测试与测试驱动开发 在软件开发过程中,开发者需要保证自己编写的代码是正确的。单元测试就 是由开发者自己编写一小段代码,用于检验被测代码的某一小的、明确的功能是 否正确
单元测试是由程序员自己来完成。程序员有责任编写功能代码,同时也就有 责任为自己的代码编写单元测试。执行单元测试,就是为了证明这段代码的行为 和我们期望的一致。 在实际软件开发过程中,有些时候程序员会由于某些原因没有进行充分的单 元测试,给软件留下了危险。为了改变这个情况,Kent Beck最早在其极限编程 (XP)方法论中,向大家推荐“测试驱动”这一最佳实践,还专门撰写了《测试驱 动开发》一书,详细说明如何实现。测试驱动开发,英文全称Test-Driven Development,简称TDD,是一种不同于传统软件开发流程的新型的开发方法。 它要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功 能代码,通过测试来推动整个开发的进行。这有助于编写简洁可用和高质量的代 码,并加速开发过程。 7.4软件重构 一个项目的代码质量往往有可能会随着时间的推移变得越来糟糕,代码越来 越臃肿,越来越难以理解它的本意,添加新功能越来越难。 重构通常指在不改变代码的外部行为情况下而修改源代码。重构是代码维护 中的一部分,既不修正错误,又不增加新的功能性。而是用于提高代码的可读性 或者改变代码的结构和设计,使其在将来更容易被维护。特别是,在现有的程序 的结构下,给一个程序增加一个新的行为会非常困难,因此开发人员可能先重构 这部分代码,使加入新的行为变得容易。 Martin Fowler等人总结出了一些常用的重构技术,将其写成了一本面向对 象领域的经典著作《重构:改善既有代码的设计》。 重构有以下好处: 1.重构能够改进软件设计,可以减少代码量,使以后的维护,开发更方便 2.重构使软件更容易理解 3.重构的时候,由于必须去阅读代码,分析、理解逻辑,这样就很可能发现一 些逻辑或是简单的错误。 重构可以在添加新功能时、修改错误时、复审代码时进行。 当开发进入尾声的时候,这时候不应该重构,因为这时候重构往往得不偿失, 可能会引入错误,还会拖累项目交付时间
单元测试是由程序员自己来完成。程序员有责任编写功能代码,同时也就有 责任为自己的代码编写单元测试。执行单元测试,就是为了证明这段代码的行为 和我们期望的一致。 在实际软件开发过程中,有些时候程序员会由于某些原因没有进行充分的单 元测试,给软件留下了危险。为了改变这个情况,Kent Beck 最早在其极限编程 (XP)方法论中,向大家推荐“测试驱动”这一最佳实践,还专门撰写了《测试驱 动开发》一书,详细说明如何实现。测试驱动开发,英文全称 Test-Driven Development,简称 TDD,是一种不同于传统软件开发流程的新型的开发方法。 它要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功 能代码,通过测试来推动整个开发的进行。这有助于编写简洁可用和高质量的代 码,并加速开发过程。 7.4 软件重构 一个项目的代码质量往往有可能会随着时间的推移变得越来糟糕,代码越来 越臃肿,越来越难以理解它的本意,添加新功能越来越难。 重构通常指在不改变代码的外部行为情况下而修改源代码。重构是代码维护 中的一部分,既不修正错误,又不增加新的功能性。而是用于提高代码的可读性 或者改变代码的结构和设计,使其在将来更容易被维护。特别是,在现有的程序 的结构下,给一个程序增加一个新的行为会非常困难,因此开发人员可能先重构 这部分代码,使加入新的行为变得容易。 Martin Fowler 等人总结出了一些常用的重构技术,将其写成了一本面向对 象领域的经典著作《重构:改善既有代码的设计》。 重构有以下好处: 1. 重构能够改进软件设计,可以减少代码量,使以后的维护,开发更方便 2. 重构使软件更容易理解 3. 重构的时候,由于必须去阅读代码,分析、理解逻辑,这样就很可能发现一 些逻辑或是简单的错误。 重构可以在添加新功能时、修改错误时、复审代码时进行。 当开发进入尾声的时候,这时候不应该重构,因为这时候重构往往得不偿失, 可能会引入错误,还会拖累项目交付时间
7.5从设计模型生成代码 从设计模型生成代码的映射规则如下: 1.类的映射 在设计类图中定义的每一个类将被映射到代码中的类。 2.属性的映射 设计类中定义的属性将直接映射为代码中的属性。不同编程语言中数据类型 有所差异,在映射时需要考虑这种差异。比如说Java中的Date类型包含了通常 所指的日期和时间。 3.方法的映射 方法一般进行直接映射,有两种方法需要特殊处理: (1)创建方法映射成相应语言中的构造函数: (2)集合对象的方法需要转换成所采用的集合类所具有的方法。 4.类的关系的映射 类的关系有依赖、关联、聚合、组合和继承。从耦合强度的角度看,依次增 强。它们在实现为代码时,也都有相应的体现 (1)依赖关系 依赖关系有如下三种情况: 1、A类是B类中的(某中方法的)局部变量: 2、A类是B类方法当中的一个参数: 3、A类是一个全局对象,B类的对象访问该全局对象的参数。 图7-2为一个依赖关系的例子,其在代码中的体现为Facility作为一个 Meeting方法的一个输入参数。 Meeting Facility +bookfacility() +book(meeting:Meeting):boolean 图7-2依赖关系 public class Meeting public void bookfacility(Facility facility) facility.book(self) pubic class Facility
7.5 从设计模型生成代码 从设计模型生成代码的映射规则如下: 1. 类的映射 在设计类图中定义的每一个类将被映射到代码中的类。 2. 属性的映射 设计类中定义的属性将直接映射为代码中的属性。不同编程语言中数据类型 有所差异,在映射时需要考虑这种差异。比如说 Java 中的 Date 类型包含了通常 所指的日期和时间。 3. 方法的映射 方法一般进行直接映射,有两种方法需要特殊处理: (1) 创建方法映射成相应语言中的构造函数; (2) 集合对象的方法需要转换成所采用的集合类所具有的方法。 4. 类的关系的映射 类的关系有依赖、关联、聚合、组合和继承。从耦合强度的角度看,依次增 强。它们在实现为代码时,也都有相应的体现 (1) 依赖关系 依赖关系有如下三种情况: 1、A 类是 B 类中的(某中方法的)局部变量; 2、A 类是 B 类方法当中的一个参数; 3、A 类是一个全局对象,B 类的对象访问该全局对象的参数。 图 7-2 为一个依赖关系的例子,其在代码中的体现为 Facility 作为一个 Meeting 方法的一个输入参数。 图 7-2 依赖关系 public class Meeting { public void bookfacility(Facility facility) { facility.book(self) }…… } pubic class Facility {