系统分析与设计第20章将设计映射为代码目标使用面向对象语言将设计映射为代码我们已经为当前迭代完成了交互图和DCD,接下去便可以为这些设计编写代码了。UP包括实现模型,根据设计所编写的代码就是UP中的实现模型,包括源代码、JSP/HTML页面、数据库定义等。20.1编程和迭代、进化式开发1.编程期设计创建代码既是最终目标,也是设计的继续。因为在设计建模中产生的结果并不是完美的,在编程和测试中会发现许多设计中不曾考虑的细节问题,因而会做出许多变更。如果做得好,设计师会以设计建模中产生的结果为基础,在编程期进一步产生更具优雅性和健壮性的系统。这就是编程期设计。2.过程路线图USECASEOOAOODCODING提供了从需求到代码开发过程的端到端路线图。各阶段中所形成的制品能够被可追溯地和有效地输入到其后续制品中,并最终形成可运行的运用。尽管这个过程不会一帆风顺,但过程路线图可以为实现和问题解决提供一个可遵循的方法和研究环境。20.2将设计映射为代码面向对象语言中的实现需要为以下元素编写源代码:类和接口的定义方法的定义下面的实现讨论以Java语言为工具.20.3由DCD创建类的定义DCD描述了类或接口的名称、属性、关联以及操作的特征标记等,这已足以在OO语言中创建基本类的定义了。DCD若是使用UML工具绘制的,还可以从图形中生成基本的类定义。如对于SalesLineItem在Java中的定义,可以直接由DCD映射为属性定义和方法特征标记,看下图:publicclassSalesLineItem{privateintquantity;privateProductDescriptiondescription;publicSalesLineItem(ProductDescriptiondesc,intqty){...}publicMoneygetSubtotal(){...}}SalesLineItemquantity:IntegergetSubtotal():MoneyProductDescriptiondescription:Textprice:MoneyitemID:ItemID...1descriptionSalesLineItem类定义中的:第一个语句定义了一个整形变量quantity,因为类图中有个属性为quantity,是整形变量;第二个语句定义了一个对象实例,名为description,其类型ProductDescription,因为设计类图中有一个description的关联角色标记,说明SalesLineItem对象具有对ProductDescription属性可见性;第三个语句是SalesLineItem的构造器,因为enterItem的交互图中有发送给SalesLineItem的create(desc,qty)消息,因此SalesLineItem必须定义相应的方法。注意类图中不包含create方法是因为这是不言而喻的,是为了保持类图的简洁性。另外,UML使用create表示创建实例,不同的语言使用不同的语句;类定义中的第四个语句定义了一个方法getSubtotal(),其返回类型是Money,因为类图的方法栏中有一个操作标记:getSubtotal():Money可见,由DCD到类定义是一种直接的翻译过程。只要对照设计类图,这个过程不是很难。20.4从交互图创建方法1.交互图中的一系列消息可以转化为方法定义中的一系列语句。例子:从enterItem交互图定义Register中的enterItem()方法。enterItem()消息是发给Register的,这说明Register中有相应的enterItem()方法:PublicvoidenterItem(ItemID,itemID,intqty)该方法实现enterItem操作契约的要求。2.如何根据交互图定义实现方法呢?首先要知道已确定的类定义,如图:ProductCatalog...getProductDesc(...)SaleisComplete:Booleantime:DateTimebecomeComplete()makeLineItem(...)makePayment(...)getTotal()Register...endSale()enterItem(id:ItemID,qty:Integer)makeNewSale()makePayment(cashTendered:Money)publicclassRegister{privateProductCatalogcatalog;privateSalecurrentSale;publicRegister(ProductCatalogpc){...}publicvoidendSale(){...}publicvoidenterItem(ItemIDid,intqty){...}publicvoidmakeNewSale(){...}publicvoidmakePayment(MoneycashTendered){...}}11catalogcurrentSale图中:Register分别拥有一个ProductCatalog的属性可见性catalog和一个Sale的属性可见性currentSale,因此在Register的类定义中有下面两条语句:privateProductCatalogcatalog;privateSalecurrntSale;Register类定义中的操作标记包括四个系统操作和一个构造器。3.现在我们看看其中的enterItem()方法如何实现?这时要根据交互图:2:makeLineItem(desc,qty)enterItem(id,qty)1:desc=getProductDesc(id)2.1:create(desc,qty)1.1:desc=get(id):Register:Sale:ProductCatalogsl:SalesLineItemlineItems:ListSalesLineItem:MapProductDescription2.2:add(sl)交互图显示,Register先后发送两条消息:消息1:Register向ProductCatalog发送getProductDescription消息以便提取匹配的ProductDescription实例并返回在desc中。因此方法定义中应该有如下语句:ProductDescriptiondesc=catalog.getProductDescription(itemID);消息2:以得到的desc和系统消息发来的qty为参数向Sale发送makeLineItem消息。因此方法定义中应该有如下语句:currentSale.makeLineItem(desc,qty);enterItem方法2:makeLineItem(desc,qty)enterItem(id,qty)1:desc:=getProductDescription(id):Register:Sale:ProductCatalog{ProductDescriptiondesc=catalog.ProductDescription(id);currentSale.makeLineItem(desc,qty);}20.5代码中的集合类一对多的关系非常常见。例如Sale必须维护对一组众多SalesLineItem实例的可见性。如:SalesLineItemquantity:IntegergetSubtotal()1..*SaleisComplete:Booleantime:DateTimebecomeComplete()makeLineItem()makePayment()getTtotal()publicclassSale{...privateListlineItems=newArrayList();}AcollectionclassisnecessarytomaintainattributevisibilitytoalltheSalesLineItems.lineItems在OO编程语言中,这种一对多的关系通常使用集合(collection)对象,例如List或Map,或简单的数组来实现。通常OO编程语言中包括对集合类的定义。例如Java库中包括ArrayList和HashMap这样的集合类,它们分别实现List和Map接口。通过使用ArrayList,Sale类可以定义一个引用SalesLineItem实例的有序列表的属性。基于键的查询要使用Map,可增长的有序列表要使用List等。对lineItem属性的声明,其类型是接口。20.6定义Sale.makeLineItem方法基于enterItem交互图还可以写出Sale类的makeLineItem方法。如图:{lineItems.add(newSalesLineItem(desc,qty));}2:makeLineItem(desc,qty)enterItem(id,qty)2.1:create(desc,qty):Register:Salesl:SalesLineItemlineItems:ListSalesLineItem2.2:add(sl)20.7异常和错误处理在目前的开发中还未涉及异常处理,这是有意的。因为我们要关注职责分配和对象设计的基本问题。但是对于应用开发,在设计建模和实现过程中考虑大规模的异常处理策略是明智的,因为它们会影响到架构。20.8实现的顺序类的实现(理想情况下还包括完整的单元测试)顺序:一要按照从耦合度最低到耦合度最高的顺序来完成;二要根据依赖关系,先实现被依赖的类,再实现依赖于的类。例如,我们的案例中首先要实现的类是Payment和ProductDescription,因为Payment的耦合度最低,而对象ProductCatalog和对象SalesLineItem依赖于ProductDescription。如图:SalesLineItemquantity:IntegergetSubtotal()ProductCatalog...getProductDesc(...)ProductDescriptiondescription:Textprice:MoneyitemID:ItemID...Storeaddress:Addressname:TextaddSale(...)Paymentamount:Money...1..*1..*Register...endSale()enterItem(...)makeNewSale()makePayment(...)SaleisComplete:Booleantime:DateTimebecomeComplete()makeLineItem(...)makePayment(...)getTotal()...111111*123456720.9POS学习案例的基本代码下面给出本次迭代中用Java实现的领域层类的样例。所生成的代码都是根据之前讨论的将设计映射为代码的原则,从设计工作中生成的设计类图和交互图中产生的。这些代码所定义的只是简单的情形,其中并不包括同步、异常处理等健壮、完整的部分。主要意图是展示从设计制品到程序代码之间的转换。(见P271)本次课小结代码即实现模型,是软件设计的目标;从设计模型到代码,一般先实现独立的没有耦合的类(层),然后从关联低的类到高的类实现也是以架构为中心的。从架构的观点,可以从底向上实现,需要用驱动模块来测试;也可以从顶向下实现,需要使用桩模块来测试。实现可以使用代码生成工具。今后自动生成的代码比重会越来越大。课后作业阅读教材第20章,理解预习第21章.