坏味道代码和解决方法简介
以下纯粹是概念和解决方法的简介,真实的衡量标准需要在工程实践中累积经验和智慧,最后得到“直觉”,凭借“直觉”判断多少行重复的代码可以判断为重复代码坏味道,方法超过多少行或者方法职能不单一,认定为超长函数等。提供的参考值并无学术上的参考价值,仅仅当前阅读代码能力的参考。
重复代码(Duplicate code):代码结果类似,表达式相似的代码。
解决方法:提取方法(Extract Method),方法上移(Pull Up Method),塑造模板方法(Form Template Method),替换算法(Substitute Algorithm)
参考值:建议不要有超过10行的相似代码
过长函数(long method):一个方法或者函数的代码或者职能过多,影响阅读维护,可读性差。
解决方法:提炼方法(Extract Method),以查询代替临时变量(Replace Temp with Query),引入参数对象(Introduce Parameter Object),保持完整对象(Preserve Whole Object),以函数对象取代函数(Replace Method with Metho Object),分解条件表达式(Decompose Conditional)
参考值:方法只有一个功能;一个方法不要超过50行
过大的类(Large class):类文件的代码数量太多,类做的事情太多,出现太多的实现变量
解决方法:提炼类(Extract Class),提炼子类(Extract Subclass),提炼接口(Extract interface)
参考值:类的职责应该单一,类文件应该不超过2000行
过长参数列(Long Parameter List):一个函数的参数过多;函数参数过多,影响使用,使用这个函数,需要了解所有的参数
解决方法:以函数取代参数(Replace Parameter with Metho),保持完整对象(Preserve Whole Object),引入参数对象(Introduce Parameter Object)
参考值:参数个数应该少于5个
发散式变化(Divergent Change):引起一个类变化的原因不止一个;也就是说类承载的功能过多,修改功能点1和功能点2修改的类是相同的;这同样违反了单一职责原则。
解决方法:提炼类(Extract Class)
参考值:类的功能单一
散弹式修改(Shotgun Surgery):要修改某个功能点,需要在很多类中修改;与发散式变化相反的概念
解决方法:搬移函数(Move method),搬移字段(Move Field),将类内联化(Inline class)
参考值:修改一个功能点,超过3处,可能就是散弹式修改的坏味道。
依恋情结(Feature Envy):函数对其他类的兴趣高过对自己所处类的兴趣
解决方法:搬移函数(Move method),提炼方法(Extract Method)
参考点:需要频繁的去别的类获取数据的情况
数据泥团(Data Clumps):两个类中的相同的字段或者函数签名相同的参数,并且删除其中一个,造成其他函数也变得没有意义。
解决方法:提炼类(Extract Class),保持完整对象(Preserve Whole Object),引入参数对象(Introduce Parameter Object)
参考:如果超过三个字段或者函数的参数超过三个,且这三个参数强关联在一起
基本类型偏执(Primitive Obsession):过多使用基本类型,没有应用面对象特性
解决方法:以对象取代数据值(Replace Data value with Object),以类取代类型码(Replace Type code with Class),以子类取代类型码(Replace Type code with subclass),以State/Strategy取代类型码(Replace Type Code with State/Strategy),提炼类(Extract Class),引入参数对象(Introduce Parameter Object),以对象取代数组(Replace Array with Object)
参考值:确定范围,位置等
Switch惊悚现身(Switch Statements):过多使用switch语句
解决方法:提炼方法(Extract Method),搬移函数(Move method),以子类取代类型码(Replace Type code with subclass),以State/Strategy取代类型码(Replace Type Code with State/Strategy),以多态取代条件表达式(Replace Conditional with Polymorphism),以明确函数取代参数(Replace parameter with explicit Methods),引入Null对象(Introduce NullObject)
参考值:见到Switch就可以考虑是否有这种坏味道
平行继承体系(Parallel Inheritance Hierarchies):当为某个类增加一个子类时,必须为另一个类相应增加子类(这里和工厂模式有些冲突,需要仔细衡量)
解决方法:让一个继承体系的实例应用另一个继承体系的实例。搬移函数(Move method),搬移字段(Move Field)
参考值:略
冗赘类(Lazy class):一个类的职责可被取代或者已不能构成一个单独职能类
解决方法:折叠继承体系(Collapse Hierarchy),将类内联化(Inline class),提炼子类(Extract Subclass)
参考值:略
夸夸其谈未来性(Speculative Generality):类的某字给有可能的场景使用
解决方法:折叠继承体系(Collapse Hierarchy),将类内联化(Inline class),移除参数(Remove Parameter),函数重命名(Rename Method)
令人迷惑的临时字段(Temporary Field):其内某个实例变量仅为某种特定情况而设
解决方法:提炼类(Extract Class),引入Null对象(Introduce NullObject)
参考值:略
过度耦合的消息链(Message Chains):很多的点点点,方法调用方法,继续调用方法的方法返回值
解决方法:隐藏委托(Hide Delegate),提炼方法(Extract Method),搬移函数(Move method)
参考值:点点点超过3ge
中间人(Middle Man):接口类有一半的函数都委托给其他类
解决方法:移除中间人(Remove middle Man),内联方法(Inline Method),继承取代委托(Replace Delegation with Inheritance)
参考值:接口类有一半的函数都委托给其他类
狎昵关系(Inappropriate Intimacy):两个类过于亲密,关注彼此的private成分
解决方法:搬移函数(Move method),搬移字段(Move Field),将双向关联改为单向关联(Change Bidirectonal Association to UniDirectional),提炼类(Extract Class),隐藏委托(Hide Delegate),委托替代委托(Replace Inheritance with Delegation)
参考值:略
异曲同工的类(Alternative Classes with Different Interface):两个函数做同一件事,却有着不同的签名
解决方法:函数重命名(Rename Method),搬移函数(Move method)
参考值:略
不完美的类库(Incomplete Library Class):略
纯稚数据类(Data Class):只有字段和访问字段的代码,只是一个数据容器
解决方法:封装字段(Encapsulate Field),封装集合(Encapsulate Collection),移除设值函数(Remove Setting Method),搬移函数(Move method),提炼方法(Extract Method),隐藏函数(Hide Method)
参考值:略
被拒绝的馈赠(Refused Bequest):子类不想继承超类的函数和紫盾
解决方法:为子类新建兄弟类,然后下移方法(Push down Method)和下移字段(Push Down Field),委托替代委托(Replace Inheritance with Delegation)
参考值:略
过多的注释(Comments):过多的注释
解决方法:提炼方法(Extract Method),函数重命名(Rename Method),引入断言(Introduce Assertion).