代码里坏味道_第1页
代码里坏味道_第2页
代码里坏味道_第3页
代码里坏味道_第4页
代码里坏味道_第5页
已阅读5页,还剩27页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、重复代码 症状: 重复的表达式 不同算法做相同的事 类似代码 措施: 一个类中包含两段重复代码时,使用提炼方法提炼方法置于一处 两个相同层次的类含有重复代码时,提炼方法,方法上移提炼方法,方法上移 两个无关类中出现重复代码时,提炼方法提炼方法至其中一个类或其他类中供调用例:方法上移例:方法上移class Customer private Date lastBillDate; addBill(Date dat,double amount)class RegularCustomer:Customer createBill(Date) chargeFor(Date start,Date end)cl

2、ass PreferredCustomer:Customer createBill(Date) chargeFor(Date start,Date end)class Customer private Date lastBillDate; addBill(Date dat,double amount) createBill(Date) abstract double chargeFor(Date start,Date end)class RegularCustomer:Customer chargeFor(Date start,Date end)class PreferredCustomer:

3、Customer chargeFor(Date start,Date end)3方法过长 症状: 存在大量的代码行 注释 条件和循环 措施: 每当需要注释时,写一个方法来代替注释 绝大多数场合下,采取提炼方法技术提炼方法技术来缩短函数 方法带有很多参数和临时变量时,采取查询替换临时变查询替换临时变量量和链式调用替换临时变量链式调用替换临时变量来消除临时变量;采用引入引入参数对象参数对象和保留完整对象保留完整对象技术瘦身参数列表;重型武器:使用方法对象替换方法方法对象替换方法 使用分解条件语句分解条件语句处理条件表达式;使用集合闭包方法集合闭包方法替换循环例:查询替换临时变量例:查询替换临时变量

4、/这是未做重构的简单方法这是未做重构的简单方法double getPrice() int basePrice=_quantity*_itemPrice; double discountFactor; if(basePrice1000) discountFactor=0.95; else discountFactor=0.98; return basePrice*discountFactor;/重构之后的主方法重构之后的主方法double getPrice() return basePrice()*discountFactor();/把临时变量赋值语句等号右边的表达式提炼成一个方法private

5、 int basePrice() return _quantity*_itemPrice;/有了basePrice()的基础很容易提炼出下面的方法private double discountFactor() if(basePrice()1000) return 0.95; else return 0.98;5例:引入参数对象例:引入参数对象class Entry. Entry(double value,Date chargeDate) _value=value; _chargeDate=chargeDate; Date getDate() return _chargeDate; double

6、 getValue() return _value; private Date _chargeDate; private double _value;class Account. double getFlowBetween(Date start,Date end) double result=0; Enumeration e = _entries.elements(); while(e.hasMoreElements() Entry each=(Entry)e.nextElement(); if(each.getDate().equals(start)|each.getDate().equal

7、s(end)|(each.getDate().after(start)&each.getDate().before(end) result+=each.getValue(); return result; double flow=anAccount.getFlowBetween(startDate,endDate);6例:引入参数对象例:引入参数对象class DateRange boolean include(Date arg) return (arg.equals(_start)|arg.equals(_end)&(arg.after(_start)|arg.before(

8、_end) DateRange(Date start,Date end) _start=start; _end=end; Date getStart() return _start; Date getEnd() return _end; private final Date _start; private final Date _end;class Account. double getFlowBetween(DateRange range) double result=0; Enumeration e = _entries.elements(); while(e.hasMoreElement

9、s() Entry each=(Entry)e.nextElement(); if(range.includes(each.getDate() result+=each.getValue(); return result; double flow=anAccount.getFlowBetween(new DateRange (startDate,endDate); 7例:保持对象完整int low = daysTempRange().getLow();int high = daysTempRange().getHigh();withinPlan = plan.withinRange(low,

10、high);withinPlan = plan.withinRange(daysTempRange();8类太大 症状: 出现太多实例变量 包含太多代码 措施: 提炼类提炼类把一些变量打包 可以作为子类时,提炼子类提炼子类 无法作为委托时,提炼模块提炼模块参数列表太长 症状: 参数列表过长 参数列表变化频繁 措施: 传递对象传递对象,使方法自己获取它需要的参数 参数来自同一对象或是对象本身,保留整个对象为参数保留整个对象为参数 参数来自不同对象,引入参数对象引入参数对象或者引入命名参数引入命名参数发散式变化 症状: 一个类因为不同的理由以不同的方式修改 措施: 将两类变化涉及的方法拆为两个对象

11、,每个对象只因为同一类变化而变化 将某种特定原因造成的所有变化提炼为一个新类,新类处理这一类变化霰弹式修改 症状: 发生一次改变时,需要修改多个类的多个地方 措施: 使用移动字段和移动方法将所有修改集中到单个类中。若现有类无好的候选者,创建;通常可以使用内联化类内联化类将整组行为整合到一起。特性依赖 症状: 一个方法调用其他类的方法比较多 一个方法调用到多个类的功能 措施: 移动方法至另一适当的对象中 看哪个类含有最多的数据就把方法和那些数据放在一起数据泥团 症状: 两个类中相同的实例变量 许多方法签名中相同的参数 措施: 对于实例变量,使用提炼类将其变成一个对象 对于方法签名,引入参数对象引

12、入参数对象或保留完整对象保留完整对象来瘦身基本类型偏执 症状: 使用了基本类型(fixnum、string、array) 措施: 使用对象替换数据值使用对象替换数据值 使用多态替换类型码使用多态替换类型码 使用模块扩展替换类型码使用模块扩展替换类型码 使用状态或策略模式替换类型码使用状态或策略模式替换类型码 使用对象替换数组使用对象替换数组例:使用对象替换数组例:使用对象替换数组有一个数组String row=new String3;row0=Liverpool;row1=15;String name=row0;int wins=Integer.parseInt(row1);class Per

13、formance private string _name; private int _wins; public string getName() return _name; public void setName(string arg) _name=arg; public int getWins() return _wins public void setWins(int arg) _wins=arg; 16case语句 症状: 代码使用了case语句 措施: 用多态替换case语句 提炼方法,先把case语句提炼出来; 移动方法至需要多态行为的类; 选择技术:使用多态替换类型码、模块扩展替

14、换类型码、状态或策略模式替换类型码 若分支很少,只在一个方法里起作用,使用显示方法替显示方法替换参数换参数或引入引入Null对象对象来替换case语句平行继承体系 症状: 为某个类增加子类时,必须为另一个类增加子类 某个继承体系类名前缀和另一个继承体系类名前缀相同 措施: 使用移动字段和移动方法冗赘类 症状 类并没有做什么工作 措施: 削减层次削减层次 内联化类或内联化模块内联化类或内联化模块纯臆测的泛化 症状: 类或模块没太大用处 方法、代码分支,或整个类的用户只有测试用例 措施: 类或模块没太大用处,使用削减层次削减层次 不必要的委托,通过内联化类内联化类来移除 带有未使用参数的方法,使用

15、移除参数移除参数 不必要的方法、代码,删除临时字段症状: 某个实例变量仅为某种情况而设置 某些实例变量仅为某个函数的复杂算法少传参数而设置措施: 提炼类提炼类,封装这些变量和需要他们的方法为方法对象方法对象 引入引入null对象对象为变量无效时创建额外组件,消除条件代码消息链 症状: 一长串的 get_This 或临时变量 措施: 使用隐藏委托隐藏委托技术中间人 症状: 一个类的接口中有很多方法在委托另一个类 措施: 这种方法数目很多时,使用移除中间人移除中间人技术,直接和干活的对象打交道 这种方法的数目不多时,内联化方法内联化方法到调用者中 这种方法包含额外的行为时,使用层次替换委托层次替换

16、委托,将实际对象变成一个模块 过分亲密 症状 一个类访问了另一个类的私有部分。 措施 使用移动方法和移动字段可以降低亲密程度 将双向关联改成单向将双向关联改成单向 使用提炼类将公共部分提炼到安全之处 子类知道太多父类不想让他们知道的东西,使用委托替委托替换继承换继承让他们离家异曲同工的类 症状: 完成相同工作,但却使用了不同的方法名 措施: 使用重命名方法重命名方法 使用移动方法将行为移到类中 因此出现冗余代码时,使用提炼模块提炼模块或引入继承引入继承来修正不完善的类库 症状: 类库中函数构造的不够好,想扩展时可能很棘手 措施: 使用移动方法将需要的行为直接移到类库中去数据类 症状: 类仅由属性构成,纯粹用来持有数据,过分细致的依赖于其他类 措施: 对任何不应被修改的实例变量采用移除设值方法移除设值方法 运用封装集合技术封装集合技术封装集合实例变量 尝试移动方法将相关行为移到数据类中,对一些设值方法和取值方法使用隐藏方法隐藏方法被拒绝的馈赠 症状 子类不需要或仅需少部分父类的方法和数据 措施 创建兄弟子类,使用方法下移,将所有不用的方法移到兄弟类中(不推荐) 若子类冲用了行为却不想支持父类里的公共方法时,应该使用委托替换继承技术委托替换继承技术注释 症状: 存在注释 措施: 提炼方法替代注释 提炼之后还需注释,则重命名方法 若需

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论