软件配置管理(四)代码味道与重构

文章目录

  • 重构的概念及意义
  • 代码味道
  • 代码味道分类
    • 1.类内味道
      • 1.1 可度量的味道-Measured Smells
        • 1.1.1 过长函数-Long Method
        • 1.1.2 过大类-Large Class
        • 1.1.3 过长参数列-Long Parameter List
        • 1.1.4 过多的注释-Comments
      • 1.2 不必要的复杂性-Unnecessary Complexity
        • 1.2.1 夸夸其谈的未来性-Speculative Generality
      • 1.3 重复-Duplication
        • 1.3.1 重复代码-Duplicated Code
        • 1.3.2 异曲同工的类-Alternative Classes with Different Interfaces
      • 1.4条件逻辑-Conditional Logic
        • 1.4.1 Switch惊悚现身-Switch Statements
    • 2.类间味道
      • 2.1 数据-Data
        • 2.1.1 基本类型偏执-Primitive Obsession
        • 2.1.2 纯稚的数据类-Data Class
        • 2.1.3 数据泥团-Data Clumps
        • 2.1.4 令人迷惑的暂时字段-Temporary Field
      • 2.2 继承-Inheritance
        • 2.2.1 被拒绝的遗赠-Refused Bequest
        • 2.2.2 狎昵关系-Inappropriate Intimacy
        • 2.2.3 冗赘类-Lazy Class
      • 2.3 职责-Responsibility
        • 2.3.1 依恋情结-Feature Envy
        • 2.3.2 过度耦合的消息链-Message Chains
        • 2.3.3 中间人-Middle Man
      • 2.4 协调变化-Accommodating Change
        • 2.4.1 发散式变化-Divergent Change
        • 2.4.2 霰弹式修改-Shotgun Surgery
        • 2.4.3 平行继承体系-Parallel Inheritance Hierarchies
      • 2.5 库类-Library Classes
        • 2.5.1 不完善的程序库类-Incomplete Library Class

重构的概念及意义

重构是使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。提高其可理解性,降低修改成本。
重构可以改进软件设计、使软件更加容易理解、帮助找到软件缺陷、提高变成速度。

代码味道

指程序中存在的一些不良的编程或设计方案。可以作为重构的指示。

代码味道分类

1.类内味道

1.1 可度量的味道-Measured Smells

1.1.1 过长函数-Long Method

方法太长。
手段:

  • 把函数变小:提炼函数
  • 函数内有大量参数和临时变量:以查询代替临时变量
  • 参数太多:引入参数对象
  • 太多临时变量和注释:以函数对象取代函数
  • 条件表达式和循环:分解条件表达式

1.1.2 过大类-Large Class

一个类职责过多,拥有过多的实例变量。
手段:

  • 太多实例变量或太多代码:提炼类、提炼子类
  • 确定客户端如何使用:提炼接口
  • 把数据和行为移到一个独立的领域对象,但保留一些重复数据:复制“被监视的数据”。

1.1.3 过长参数列-Long Parameter List

一个方法需要传递太多的参数。
手段:

  • 向已有对象发出一条请求就可以取代一个参数:以函数取代参数
  • 参数缺乏合理的对象归属:引入参数对象
  • 将来自一个对象的参数收集起来:保持对象完整

1.1.4 过多的注释-Comments

在非必要时不要写注释,优先重构代码以使代码具有自解释性。
手段:

  • 需要注释来解释一块代码做了什么:提炼函数
  • 函数已经提炼出来,但仍需注释:函数改名
  • 需要注释来说明系统的需求规格:引入断言

1.2 不必要的复杂性-Unnecessary Complexity

1.2.1 夸夸其谈的未来性-Speculative Generality

当程序中过量的使用设计模式,导致在代码的阅读过程中很难找到主要的逻辑走向。放置过量的钩子或特殊情况来处理一些非必要的事情,可能在代码的编写调试过程中加深跟踪Bug的难度。
手段:

  • 某个抽象类没有太大作用:折叠继承体系
  • 不必要的委托:将类内联化
  • 函数的某些参数未被使用:移除参数
  • 函数名称带有多余的抽象含义:函数改名
  • 无用函数:内联函数、移除函数

1.3 重复-Duplication

1.3.1 重复代码-Duplicated Code

在多个地方发现相似代码结构,
手段:

  • 同一个类含有相同代码:提炼函数
  • 两个兄弟类有相同代码:提炼函数、函数上移、塑造模板函数
  • 两个不相干类有相同代码:提炼类

1.3.2 异曲同工的类-Alternative Classes with Different Interfaces

不同的类完成相同的任务,但有不同的签名(主要指方法签名)。
手段:

  • 两个函数做同一件事,但有不同签名:函数改名
  • 将某些行为移入类,直到两者协议相同:搬移函数
  • 必须重复而冗赘移入代码才能实现上述重构:提炼超类

1.4条件逻辑-Conditional Logic

1.4.1 Switch惊悚现身-Switch Statements

Switch语句(包括if-else)通常会导致代码重复。
手段:

  • 与类型码相关的函数或类:提炼函数、搬移函数、以多态取代条件表达式、以子类取代类型码、以状态模式或策略模式取代类型码。
  • 只在单一函数中有一些选择事件:以明确函数取代参数
  • 选择条件之一是null:引入null对象。

2.类间味道

2.1 数据-Data

2.1.1 基本类型偏执-Primitive Obsession

基本类型被过度使用。
手段:

  • 将原本单独存在的数据值替换成对象:以对象代替数据值
  • 如果想替换的是类型码,而类型码不影响行为:以类取代类型码
  • 如果有与类型码相关的条件表达式:以子类取代类型码、以状态模式、策略模式取代类型码
  • 如果有一组应该总是被放在一起的字段:提炼类
  • 如果在参数列中看到基本类型的数据:引入参数对象
  • 发现自己正从数组中挑选数据:以对象取代数组

2.1.2 纯稚的数据类-Data Class

类只拥有成员变量和对应的setter和getter方法。
手段:

  • 对于public字段:封装字段
  • 如果一个容器的字段没有得到恰当的封装:封装集合
  • 对于那些不该被其他类修改的字段:移除设值函数
  • 找出getter和setter被其他类运用的地点:搬移函数
  • 如果无法搬移整个函数:提炼函数
  • 将getter和setter隐藏起来:隐藏函数

2.1.3 数据泥团-Data Clumps

一些数据项同时出现在多个地方,如一对内的成员变量、多个方法签名的参数等。
手段:

  • 两个类有相同的字段或许多函数签名中的参数相同:提炼类
  • 缩短参数列表、简化函数调用:引入参数对象、保持对象完整

2.1.4 令人迷惑的暂时字段-Temporary Field

一个对象中某个变量仅为某些特定场合而设,导致代码难以理解。
手段:

  • 一个对象中某个实例对象仅为某种特定情况而定:提炼类
  • 在“变量不合法”的情况下创建一个null对象,从而避免写出条件式代码:引入null对象

2.2 继承-Inheritance

2.2.1 被拒绝的遗赠-Refused Bequest

子类继承父类的方法和数据,但仅使用其中一部分。
手段:

  • 子类不想或不需要继承超类(先为子类新建一个兄弟类):提炼子类、函数下移、字段下移
  • 子类复用了超类的行为,却又不愿意支持超类的接口,拒绝继承超类的实现:以委托代替继承

2.2.2 狎昵关系-Inappropriate Intimacy

类之间的关系变得过于紧密。
手段:

  • 类之间的关系过于紧密:搬移函数、搬移字段、将双向关联改为单向关联
  • 如果两个类存在共同点:提炼类、隐藏“委托关系”
  • 从继承体系中分离子类:以委托取代继承

2.2.3 冗赘类-Lazy Class

如果一个类不值其身价,它就应该消失。
手段:

  • 对于几乎没用的组件:将类内联化
  • 如果某些子类没有做足够的工作:折叠继承体系

2.3 职责-Responsibility

2.3.1 依恋情结-Feature Envy

一个方法对别的类的兴趣高于它本身所在的类。
手段:

  • 函数对某个类的兴趣高过对自身所处类的兴趣:搬移函数、搬移字段
  • 函数中只有一部分对其他类更感兴趣:提炼函数、搬移函数

2.3.2 过度耦合的消息链-Message Chains

一个对象请求另一个,后者在请求下一个对象,…这就是消息链【a.getB().getC().getD()】。采取这种方式,意味客户代码将与查找过程中的导航结构紧密耦合,一旦对象间的关系发生任何变化,客户端就不得不做出相应修改。
手段:

  • 隐藏“委托关系”

2.3.3 中间人-Middle Man

一个类的接口中,一半的方法都委托给了其他类。
手段:

  • 过度运用委托:移除中间人
  • 如果“不干实事”的函数只有几个:内联函数
  • 如果中间人还有其他行为,需要对原对象的行为进行扩展:以继承取代委托

2.4 协调变化-Accommodating Change

2.4.1 发散式变化-Divergent Change

一个类拥有多个引起它变化的原因。
手段:

  • 找出某特定原因而造成的所有变化:提炼类

2.4.2 霰弹式修改-Shotgun Surgery

进行某种修改时,必须对多个不同的类进行对应的小修改。
手段:

  • 把所有需要修改的代码放进同一个类中:搬移函数、搬移字段
  • 如果眼下没有合适的类可以安置这些代码,就创造一个
  • 把一系列相关行为放进同一个类中:将类内联化

2.4.3 平行继承体系-Parallel Inheritance Hierarchies

当为某个类增加子类时,不得不为另一个类也增加一个子类。
手段:

  • 让一个继承体系的实例引用另一个继承体系的实例:搬移函数、搬移字段

2.5 库类-Library Classes

2.5.1 不完善的程序库类-Incomplete Library Class

手段:

  • 如果只想修改库类的一两个函数:引入外加函数
  • 如果想添加大量额外行为:引入本地扩展

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/290574.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Atitit。 《吠陀》 《梨俱吠陀》overview 经读后感  是印度上古时期一些文献的总称...

Atitit。 《吠陀》 《梨俱吠陀》overview 经读后感 是印度上古时期一些文献的总称 1. 印度古《吠陀》经,是印度上古时期一些文献的总称, 1 1.1.1. 医学意义 2 2. 梨俱吠陀(篇章规模,字数) 2 2.1. 神曲结构模式编辑 2 …

【C#/.NET 日常开发技巧】JWT+ActionFilter 简便控制器代码

微信公众号:趣编程ACE关注可了解更多.NET日常开发技巧,如需源码,请公众号留言 源码;JWTActionFilter 简便控制器代码这是微软关于过滤器的介绍:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/controllers/filters?viewaspne…

在P2P市场中代替“看不见的手”的算法在哪里

◆ ◆ ◆ 本文简单探讨P2P市场机制,在此基础上探讨匹配撮合服务的可能性。 ◆ ◆ ◆ P2P市场机制基本定义与假设 首先,我们回顾一些基本定义与假设。P2P市场为“网络借贷是指个体和个体之间通过互联网平台实现的直接借贷。”[2]利率决定一般是平台决定借…

Android之adb jdwp获取debug版本app的进程Id

1、adb jdwp命令 adb jdwp获取debug版本app的进程Id 2、用途 带我们运行一个debug版本的app时候,我们需要过滤日志,我们一般采取这种办法 adb shell ps | grep package 得到进程ID,然后 adb logcat | grep pid 打印日志,有了adb jdwp&…

NPOI格式设置1

using NPOI.SS.UserModel; using NPOI.HSSF.UserModel; //创建Execl IWorkbook hssfworkbook new HSSFWorkbook(); //创建一个Sheet hssfworkbook.CreateSheet("Sheet1"); //HSSFWorkbook实例写入文件 FileStream file new FileStream("test.xls", F…

软件配置管理(五)常用重构技巧

文章目录一、重新组织函数1.提炼函数2.内联函数3.内联临时变量4.以查询取代临时变量5.引入解释性变量6.分解临时变量7.移除对参数的赋值8.以函数对象取代函数9.替换算法二、在对象之间搬移特性1.搬移函数2.搬移字段3.提炼类4.将类内联化5.隐藏“委托关系”6.移除中间人7.引入外…

关于他们回答的 怎样在桌面建一个python GUI的快捷方式 这个问题

在之前的2个随笔里面,有写过《找到可以解决问题的正确的人》、《如何提问》,说白了就是您需要帮助的时候,您得让对方100%懂你,否则没戏。 那么最近看到这样1个古老的问题,和一些没有答到"点儿"上的回答&…

Android之最简单和靠谱的监听Home键和菜单键(最近任务栏)

1、介绍ACTION_CLOSE_SYSTEM_DIALOGS /*** Broadcast Action: This is broadcast when a user action should request a* temporary system dialog to dismiss. Some examples of temporary system* dialogs are the notification window-shade and the recent tasks dialog.*…

.NET Core中行为过滤器ActionFilterAttribute的使用介绍

什么是行为过滤器?行为过滤器是你可以应用到一个控制器行为的,或者整个控制器的,来修改控制器行为的执行方式的属性。当请求进入 API 接口的时候,操作过滤器提供了一个进入之前(before)和进入之后&#xff…

基本线程同步(三)在同步的类里安排独立属性

声明:本文是《 Java 7 Concurrency Cookbook 》的第二章,作者: Javier Fernndez Gonzlez 译者:许巧辉 校对:方腾飞 在同步的类里安排独立属性 当你使用synchronized关键字来保护代码块时,你必须通过一…

旧项目适配iphone6和iphone plus

iphone手机屏幕大小和像素:1.iPhone5/5s 320x568,像素640x1136,2x2.iPhone6 375x667,像素750x1334,2x3.iPhone6 Plus 414x736,像素1242x2208,3x旧的项目在xcode6上运行在iphone6或…

java之用反射实现方法(已知实体对象和实体参数)

1、问题 有个函数需要在Android 23(6.0)以上,但是我们的API是22,所以这个实体对象调用不了这个函数,这个时候我们应该想到的是反射,切记。 2、实现 同时看我写得很着急,因为我是先class.forName("**…

Could not load the Tomcat server configuration at \Servers\Tomcat v7.0 Server at localhost-config

之前不小心删除了server的服务器设置,运行时各种报错Could not load the Tomcat server configuration at \Servers\Tomcat v7.0 Server at localhost-config ,网上找到解决方法记录下: 第一步:将左边的classpath中的server删除掉…

软件项目组织管理(一)项目管理概述

文章目录什么是项目项目的特征项目的组成要素(三维约束)什么是项目管理什么是IT项目什么是软件项目管理项目管理的目标(项目成功的标志)软件项目失败的原因活动的3个基本特点人类活动分为两种类型作业和项目的区别(必考…

ABP Framework 5.2 RC 版本发布及新增功能介绍

本文将介绍 ABP Framework 5.2 RC 版新增的主要功能:•单层解决方案模板•API 版本控制•源代码控制移除libs文件夹•对 Swagger UI 隐藏 ABP 默认端点•CMS Kit应用模块自定义全局 CSS 和 JavaScript关注 ABP Framework 最新开发进度,后面还会陆续发布新…

《计算机组成原理》----2.3 二进制运算

本节书摘来自华章出版社《计算机组成原理》一书中的第2章,第2.3节, 作 者 Computer Organization and Architecture: Themes and Variations[英]艾伦克莱门茨(Alan Clements) 著,沈 立 王苏峰…

JTable常见用法细则

JTable是Swing编程中很常用的控件,这里总结了一些常用方法以备查阅.欢迎补充,转载请注明作者与出处.一.创建表格控件的各种方式:1) 调用无参构造函数. JTable table new JTable();2) 以表头和表数据创建表格. Object[][] cellData {{"row1-col1", "row1-col…

Android之通过ActivityLifecycleCallbacks判断程序是否运行在后台

1、问题 判断程序是否运行在后台运行 2、解决办法 我们可以使用ActivityLifecycleCallbacks,对于ActivityLifecycleCallbacks,看我的这篇博客介绍() Android之ActivityLifecycleCallbacks的得到当前的activity的状态 (http://blog.csdn.net/u01106870…

下拉刷新:继承listView控件

1、首先初始化的时候给控件监听OnScrollListener,其中onScroll的参数里得到第一个显示的条目,当第一个条目为0的时候就可以执行下啦刷新了。第二覆写的方法是 onScrollStateChanged就是滑动状态的监听,3种状态都是常量:快速滑动&a…

软件项目组织管理(二、三)项目管理与信息技术环境、项目管理过程组

文章目录系统方法系统管理三维模型组织环境组织的四个框架组织的结构项目生命周期管理评审虚拟团队什么是过程项目管理过程组系统方法 项目管理工作需要采取系统的方法,描述在解决复杂问题时所需的整体性和分析性方法。 系统哲学:将事情作为系统考虑的…