导言如果设计模式的选择和类接口规格说明工作做的足够仔细,那么现存大部分设计问题可以解决,但是将模型映射到代码时会产生很多问题(违反契约,随意添加参数,交付压力等),本章介绍一些将模型映射到代码的方法,提高系统质量对象设计活动图映射概述优化类模型减少关联重数加快查询速度,增加冗余关联提高有效性将关联映射到集合上将关联映射到源代码上将契约映射到异常上描述违反契约的操作行为将类模型映射到存储模式上选择存储策略,将类模型映射到存储模式上映射的概念转换的类型模型转换:优化原始模型,如将单一属性转化为类(将地址字符串转化为包含街道,邮编,城市,国家等属性的类)重构:类似模型转换,代码级别的转换映射的概念正向工程:产生与对象模型对应的源代码模板逆向工程:产生与源代码对应的对象模型,主要在系统设计方案丢失时使用模型转换模型转换作用于某一模型上,以产生另一模型,其目的是简化或优化原有模型,转换可能增加,删除,修改类,方法,以及属性。需同步更新对象设计模型。重构重构是对源代码的转换,在不影响系统行为的前提下,提高代码的可读性和可修改性重构好处容易阅读所有逻辑都只在唯一地点指定新的改动不会危及现有的行为简单的表达条件逻辑重构征兆三次法则:如果你重复拷贝某段代码超过3次,考虑重构数量法则:如果某个方法的实现超过20行,考虑重构重构时机在添加新功能时进行重构.在修改bug时进行重构在代码复审时进行重构.什么时候不易进行重构现有的程序无法运行,此时应该是重写程序,不是重构程序到了昀后的交付期限重构与设计重构与设计是互补的,程序应该是先设计,后编码。设计上的不足可以用重构来弥补,但不应该因为有重构而忽视设计。如果能很容易的通过重构来适应需求的变化,那么就不必过度的设计,当需求改变时再重构代码。第一次重构后public class User{protect String email;}public class Student extends User{//....}public class Teacher extends User{//....}第一次重构前public class Student{private String email;//....}public class Teacher{private String email;//....}第二次重构前public class User{protect String email;}public class Student extends User{public Student (String email){this.email=email;}}第二次重构后public class User{private String email;public User(String email){this.email=email;}}public class Student extends User{public Student(String email){super(email);} 正向工程与逆向工程正向工程:保持对象设计模型与源代码的高度一致,减少在实现期间引入的错误数。如将UML模型每个属性映射到Java类中某个私有字段以及get和set方法上将UML模型每个方法映射到Java类中某个方法上逆向工程:根据源代码产生对象模型,是正向工程的逆过程为每一个代码类构建一个UML类并增加属性和方法。因为正向工程会丢失信息(例如关联通过Java集合实现),所以构建出的对象模型与原对象模型不一定一致转换原则每一次转换都面临着风险,所以必须遵守一些原则每个转换对应唯一的判定准则:以改进系统响应时间为目标使系统易于扩展不能同时考虑多个目标每个转换必须是局部的一次尽量改变少量方法和类尽量在一个子系统内进行修改转换原则每一个转换必须与其他更改活动相隔离改变性能的时候不应该增加新的功能增加新的功能时不需要考虑性能每个转换之后必须进行确认对象模型转换:更新顺序图并检查相关用例重构:运行对应类的测试用例增加了新的功能:构造新的测试用例映射活动‐优化对象设计模型优化访问路径:对多重关联的重复遍历,对关联多的一端的遍历,以及错误放置的属性,这些都是导致系统效率低下的原因。映射活动‐优化对象设计模型关联的重复遍历标识经常被调用的操作,并在顺序图的帮助下检查这些多重关联遍历是否必须。浏览器页面的滚动流畅度一直是衡量浏览器是否好用的一个重要指标。一个页面通常由Html,Css,Img,Js等组成,在内存中通过Dom树来表示。htmlheader/bodytexthello world/text/body/html浏览页面时,鼠标滚轮每滚动一下,页面重新绘制了n次,这样才能体现流畅的滚动效果。每一次重新绘制,都需要对Dom树进行一次遍历,重新计算每个元素的位置,重新布局,这样严重影响了效率。解决办法1,如果只是滚动的话,其实元素之间的相对位置并没有发生改变,只需要记录元素相对位置,再加上横纵坐标的平移,重新绘制即可得到正确的视图。解决办法2,将页面完整渲染后保存成图像,滚动仅仅是图像的滚动。将关联“多”的一端化简在二维图形绘制的时候,需要为屏幕中每一个像素点建立一个对象来保存相关信息。在具体渲染的时候,需要按照扫描线遍历每一个像素点,查看当前像素点是否与需要绘制的图形相交,或者处于图形内部,这涉及到排序,不好的排序会导致图形渲染效率低下。错误放置的属性导致系统效率低下的另一个原因是过度建模,类中一些不需要的属性应该从模型中简单的去掉。映射活动‐优化对象设计模型压缩对象:将对象变为属性,对象模型在经历了一些优化后,只剩下很少的属性或行为,若这些类与其他的一个类关联,就可以将对象压缩为属性。映射活动‐优化对象设计模型延时高成本计算创建特殊对象常常是昂贵的,其实可以将对象的创建延时到实际需要使用的时候考虑一个Web页面上面有很多图片,但是并不是所有的图片在同一时间显示映射活动‐优化对象设计模型采用缓存存放高成本计算结果在网页显示中,我们一般将Image图片解码成RGB格式的数据存储在内存缓存中,需要渲染的时候,直接从内存中读出,比再去解码一次会快很多。缓存有一定大小,可以按照昀近昀长使用的策略进行替换。映射活动‐将关联映射到集合关联是UML中的概念,表示2个或多个对象之间有联系,但是不幸的是程序设计语言中并没有关联的概念,取而代之的是引用和集合引用:一个对象存储另外一个对象的句柄集合:存储几个对象的引用并排序单向一对一关联public class Advertiser{private Account account;public Advertiser(){account = new Account();}public Account getAccount(){return account;} }一对一双向关联public class Advertiser{private Account account;public Advertiser(){account = new Account(this);}public Account getAccount(){return account;} }public class Account{private Advertiser owner;public Account(Advertiser owner){this.owner=owner;}public Advertiser getAdvertiser(){return owner;} }一对多关联public class Advertiser{private Set accounts;public Advertiser(){account = new HashSet();}public void addAccount(Account a){accounts.add(a);a.setOwner(this);} }public class Account{private Advertiser Owner;public void setOwner(Advertiser Owner){this.owner=Owner;Owner.addAccount(this);}………….}多对多关联public class Tournament{private List players;public Tournament(){palyers= new ArrayList();}public void addPlayer(Player p){if(!players.contain(p)){players.add(p);p.addTournament(this);}}}public class Player{private List tournaments;public Player(){tournaments = new ArrayList();} public void addTournament(Tournament t){if(!tournaments.contain(t)){tournaments.add(p);t.addPlayer(this);}}}受限关联public class Tournament{private Map players;public void addPlayer(String nickname, Player p) {if(!players.containKey(nickName)){players.put(nickName,p);p.addTournament(nickName,this);}}}public class Player{private Map tournaments; public void addTournament(String nickname, Tournament t){if(!tournaments.containKey(nickName)){tournaments.put(nickName,t);t.addPlayer(nickName,t);}}}映射活动‐将契约映射到异常面向对象语言没有对契约进行支持一般使用异常机制来处理契约事故public class Tournament{//.......private List players;public addPlayer(Player p)throws knownPlayer, TooManyPlayers,UnknownPlayer,IllegalNumPlayers,IllegalMaxNumPlayers{//check precondition !isPlayerAccepted(p)if(isPlayerAccepted(p))throw new knownPlayer(p);//check precondition getNumPlayers()maxNumPlayersif(getNumPlayers()==getMaxNumPlayers())throw new TooManyPlayers(getNumPlayers()); .....//save current player num intpre_getNumPlayers= getNumPlayers();//check postconditionisPlayerAccepted(p)if(!isPlayerAccepted(p))throw new unKnownPlayer(p);//check postconditiongeNumPlayers() = pre_getNumPlayers+1if(geNumPlayers() != pre_getNumPla