【重构】-重复代码(duplicated Code)

2023-11-01

重构一  duplicated Code(重复代码)

场景演义:

议题一

同一个类的两个函数有相同代码片段

重构手法(Extract Method)

把一段代码组织在一起并独立,放进一个独立函数中,并让函数名称解析该函数的用途。

演义讲解

public static void main(String[] args) {
	     A();
	     System.out.println("B"); 
	     System.out.println("C"); 
	}
	
	public static void A(){
	    System.out.println("A");
	}
对上面使用 Extract Method
	public static void main(String[] args) {
	     A();
	     B();
	}
	public static void A(){
	    System.out.println("A");
	}
	
	public static void B(){
		    System.out.println("B"); 
	       System.out.println("C"); 
	}

动机

处理复杂函数,过长函数,细粒度函数容易复用,易注释,易覆写。

重构前

viod printOwing(){
	Enumeration e=orders.elements();
	double outstanding=0.0;
	
	//打印横幅
	System.out.println(...............);
	System.out.println(...............);
	System.out.println(...............);
	
	//计算outstanding值
	while(e.hasMoreElements){
		Order order=(Order)e.nextElement();
		outstanding+=each.getAmout();
	}
	
	//打印细节
	System.out.println?(...............);
	System.out.println?(...............);
}

重构以后

范例一:无局部变量

viod printOwing(){
	Enumeration e=orders.elements();
	double outstanding=0.0;
	//打印横幅
	printOwing()
	//计算outstanding值
	while(e.hasMoreElements){
		Order order=(Order)e.nextElement();
		outstanding+=each.getAmout();
	}
	//打印细节
	System.out.println(...............);
	System.out.println(outstanding);
}


public void printOwing(){
	
	System.out.println(...............);
	System.out.println(...............);
	System.out.println(...............);
	
}

范例二:有局部变量

viod printOwing(){
	Enumeration e=orders.elements();
	double outstanding=0.0;
	//打印横幅
	printOwing()
	//计算outstanding值
	while(e.hasMoreElements){
		Order order=(Order)e.nextElement();
		outstanding+=each.getAmout();
	}
	//有局部变量的extract method的方式
	printdetail(outstanding);
}

public void printdetail(double outstanding){
	//打印细节
	System.out.println(...............);
	System.out.println(outstanding);
}

范例三 对局部变量再赋值

viod printOwing(){
	double outstanding=getOutstanding();
	//打印横幅
	printOwing()
	//有局部变量的extract method的方式
	printdetail(double outstanding);
}

public double getOutstanding(){
	double result=0.0;
	Enumeration e=orders.elements();
	//计算outstanding值
	while(e.hasMoreElements){
		Order order=(Order)e.nextElement();
		result+=each.getAmout();
	}
	return result;
}


public void printOwing(){
	
	System.out.println(...............);
	System.out.println(...............);
	System.out.println(...............);
	
}


public void printOwing(){
	
	System.out.println(...............);
	System.out.println(...............);
	System.out.println(...............);
	
}

public void printdetail(double outstanding){
	//打印细节
	System.out.println(...............);
	System.out.println(outstanding);
}

议题二

两个互为兄弟的子类有相同代码片段

重构手法

extract method(提取重复代码)

Pull UpMethod(推入超类):有些函数在各个子类中产生完全相同的效果,将该函数移至超类中。


动机

避免修改一个而没有修改另一个,有大量冗余的工作要做

如上图所示 我们可以看到两个子类中都有createBill()和chargeFor(Date start,Date end)

这两个方法,遗憾的是只有createBill()方法是相同的,然而chargeFor方法确实不同的,所以我们只能使用pull up method 把createBill(); 提取到超类中,在超类中申明chargeFor方法为抽象方法。

class Customer{
	public abstract double chargeFor(Date start,Date end);

}

如上类图所示 createBill已经通过pull up method提升到超类中了,chargeFor也在超类中被申明为了一个抽象类。

FormTemplate Method(模板方法)

一些子类,其中相应的某些函数以相同顺序执行类似操作,但各个操作细节上有所不同。将这些函数都放进独立的函数中,并保持他们都有相同的签名,于是原函数也变得相同了,然后将原函数移至超类。


如上所示。原本有两个子类都有同名函数。可是有些操作却不一样,把这些不同的操作以相同的函数签名用extract method抽取成独立的单元,把原函数pull up mehtod上升到父类中,再把这些不同的函数的公共方法签名作为抽象方法,放进超类中。

动机:两个子类之中有类似的函数,就可以提升至超类中,两个函数执行以大致相近的操作,又不完全相同,可以将完全相同的的顺序移至超类中,并借助多态来保持差异,这样的函数称为模板方法。

 

重构前范例
public Class Statement{
	
	public String  stateString(){
		String result=null;
		result=result+"你好";
		result=result+"是的"
		return result;
	}
	
}

public String  stateString(){
		String result=null;
		result=result+"<html><head></hea><body>你好";
		result=result+"是的</body></html>"
		return result;
}
	
}

如上代码段所示,是两种不同方式的问好方法,一个是html的方式,一个是普通字符串的方式,但是它们都实现同样的效果。此时我们应该把这两个方法作为两种策略,封装成两个类


第一步 并把两个实现相同功能的方法封装,重新进行方法签名

public class Statement{
	
	
}
public class Htmlstatement extends Statement{
	
	public String  value(){
		String result=null;
		result=result+"<h1>欢迎你</h1>";
		result=result+"<html><head></hea><body>你好";
		result=result+"我是小梅</body></html>"
		return result;
	}
}



public class Textstatement extends Statement{
	
	public String  value(){
		String result=null;
		result=result+"欢迎你";
		result=result+"你好";
		result=result+"我是小龙"
		return result;
	}
	
}

第二步:提取相同序列中的不同部门,代之以相同的方法签名

public class Statement{
	
	
}
public class Htmlstatement extends Statement{
	
	public String  value(String customer){
		String result=null;
		result=result+headString(customer);
		result=result+eachRentalString(customer);
		result=result+footerString(customer);
		return result;
	}
	
	
	public String headString(String customer){
		return "<h1>欢迎你</h1>";
	}
	
	public String eachRentalString(String rental){
		return "<html><head></hea><body>你好";
	}
	
	public footerString(String customer){
		return "我是小梅</body></html>";
	}
}



public class Textstatement extends Statement{
	
	public String  value(String customer){
		String result=null;
		result=result+headString(customer);
		result=result+eachRentalString(customer);
		result=result+footerString(customer);
		return result;
	}
	
	public String headString(String customer){
		return "欢迎你"+ customer;
	}
	
	public String eachRentalString(String rental){
		return "你好"+ Rental;
	}
	
	public footerString(String customer){
		return "我是小龙"+ customer;
		
	}
}

第三步 把相同的序列方法用pull up method 提到超类中,把相同的方法签名在超类中利用抽象方法进行申明。

public class Statement{
	public String  value(String customer){
		String result=null;
		result=result+headString(customer);
		result=result+eachRentalString(customer);
		result=result+footerString(customer);
		return result;
	}
	public abstract String headString(String customer);
	public abstract String eachRentalString(String rental);
	public abstract String footerString(String customer);
	
}

子类不做改变:

重构完毕后的类图。

SubstituteAlgorithm(替换算法)

将某个算法替换为另一个更清晰的算法。

议题三

多个毫不相干的类中有相同代码片段

重构手法

ExtractClass 提炼类:某个类做了应该由两个类做的事情,建立一个新类,将相关字段和函数从旧类搬移到新类。


一个类应该是一个清楚的抽象,处理一些明确的责任。

重构前:

public class Person{
	private String name;
	private String areaCode;
	private String areaphomenum;
	
	public void setName(String name){
		this.name=name;
	}
	
	public String getName(){
		retunr this.name;
	}
	
	public String getTeleAcreCode(){
		return this.areaCode;
	}
	
	public String getAreaPhone(){
		return this.areaphomenum;
	}
	
}
我们看到跟电话相关的类似乎有点冗余,所以我们应该把它抽取出去

public class TelePhoneNumber{
	private String number;
	private String code;
	
	public String getNumber(){
	   return number;
	}
	
	public String getCode(){
		return code;
	}
	
}

接下来我们把 TelephoneNumber这个类组合进去












本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【重构】-重复代码(duplicated Code) 的相关文章

  • 常用Linux发行版镜像源配置

    最近研究Linux 试了一些Linux发行版 但是大多数发行版的软件源速度都不是很理想 所以我这里干脆做了一个收集 把我用过的一些常用发行版的软件源设置方法做个总结 大家也可以做个参考 Ubuntu 18 04 18 04是目前Ubuntu
  • unity Animation和Animator动画的暂停和继续播放

    1 利用Animator组件实现暂停和继续播放自己创建的Animation动画 需要按以下顺序操作 在需要播放动画的物体身上添加Animator组件 在Project视图下创建AnimatorController并拖入到Animator组件
  • 【vue3+ts+ant】a-table的column绑定点击事件的两种方式

    需求 给标题这一列的数据绑定点击事件 实现交互 第一种 在dom里面插入标签 并绑定点击事件
  • 【牛客网 - 华为机试 - HJ85 最长回文子串】

    描述 给定一个仅包含小写字母的字符串 求它的最长回文子串的长度 所谓回文串 指左右对称的字符串 所谓子串 指一个字符串删掉其部分前缀和后缀 也可以不删 的字符串 数据范围 字符串长度 进阶 时间复杂度 O n O n 空间复杂度 O n O
  • Java编码规范

    目录 1 代码规范 2 1 1 注释规范 2 1 1 1 页头注释
  • redux之react-redux实现原理

    Redux Flow 一 介绍 一 redux 1 reducer念 reducer就是一个纯函数 接收旧的state和action 返回新的state previousState action gt newState 名字由来 Array
  • Java 实现下载文件工具类

    package com liunian utils import lombok SneakyThrows import javax servlet ServletOutputStream import javax servlet http
  • 力扣每日一题——四数相加Ⅱ

    题目链接 class Solution public 将四个组分为两组 即时间复杂度n 4 gt 2 n 2 int fourSumCount vector
  • 服务器域名修改,服务器修改域名

    服务器修改域名 内容精选 换一换 华为云帮助中心 为用户提供产品简介 价格说明 购买指南 用户指南 API参考 最佳实践 常见问题 视频帮助等技术文档 帮助您快速上手使用华为云服务 您可以通过华为云的域名注册服务管理您的域名 如表1所示 服
  • 无法连接imessages信息服务器,如何屏蔽imessage广告 iPhone怎么屏蔽iMessages广告【详解】...

    很多苹果设备用户都会用到iMessages 苹果设备之间聊天很方便 不过iMessages广告却是一个神烦的存在 怎么屏蔽iMessages广告 下面IT百科小编和大家分享几种屏蔽iMessages广告的方法 大家可以根据自己的使用习惯选择
  • QWidget的背景颜色和背景图片的设置

    首先设置autoFillBackground属性为真 然后定义一个QPalette对象 设置QPalette对象的背景属性 颜色或图片 最后设置QWidget对象的Palette 实例 QWidget widget new QWidget
  • web基础学习笔记(九)之节点常用属性和方法

    节点常用属性和方法 getElementsByTagName 获取当前节点的指定标签名孩子节点 gappendChild oChildNode 添加一个子节点 oChildNode是要添加的孩子节点 属性 childNodes 获取当前节点
  • Docker---本地镜像发布到阿里云

    本地镜像发布到阿里云 1 准备前提 2 以当前运行运行的mycentos运行实例 以它为模板commit一个新的mycentos镜像 3 将本地镜像推送到阿里云 3 1 本地镜像素材原型 3 2 登录阿里云开发者平台创建镜像仓库 3 2 1
  • jQuery基本筛选器

    3 jQuery基本筛选器 3 1 first 获取第一个元素 用法 ul li list item 1 li li list item 2 li li list item 3 li li list item 4 li li list it
  • https网络编程——SSL的加密和解密过程

    参考 SSL的加密和解密过程 地址 https qingmu blog csdn net article details 108214105 spm 1001 2014 3001 5502 目录 现在的加密 解密技术主要有三种 对称加密 非
  • 设置EntityFramework中decimal类型数据精度问题(EF默认将只会保留到2为精度)

    原文 设置EntityFramework中decimal类型数据精度 EF中默认的decimal数据精度为两位数 当我们数据库设置的精度大于2时 EF将只会保留到2为精度 e g 2 19990将会被保存为2 20 1 解决方案一是网上找到
  • js作用域、闭包和浏览器渲染原理

    一 js作用域 变量的作用域是指变量在整个程序中作用 可访问 的范围 1 作用域的类型 三个类型 全局作用域 局部作用域 函数作用域 块级作用域 ES6新增 1 全局作用域 如果一个变量为全局作用域 那么这个变量在程序的任意位置都可以访问
  • 主流显卡Linux系统驱动安装--intel、ATi篇

    Intel 集成显卡的Linux驱动安装 目前使用Intel 集成显卡的计算机主要集中在中低端商务台式机和中低端笔记本电脑 这里介绍一下Linux下显卡驱动安装方法 I ntel针对集成显示芯片提供了两种驱动程序 i915Graphics和
  • BigInteger和BigDecimal的使用

    1 BigInteger类的常用方法 java math BigInteger类表示一个超大的整数 而且支持任意精度整数的四则运算 加减乘除 常用方法 方法 含义 public BigInteger String val 将 BigInte

随机推荐

  • 模型与动画作业

    一 智能巡逻兵 游戏设计要求 创建一个地图和若干巡逻兵 使用动画 每个巡逻兵走一个3 5个边的凸多边型 位置数据是相对地址 即每次确定下一个目标位置 用自己当前位置为原点计算 巡逻兵碰撞到障碍物 则会自动选下一个点为目标 巡逻兵在设定范围内
  • canvas正交坐标系旋转--监听滚轮

    canvas 简单学习canvas 功能实现 效果 简单学习canvas
  • Java读取excel的方式,一篇文章看懂(详细)

    目录 一 excel读取的两种方式 1 1 jxl 和 poi 的区别和选择 二 jxl 的使用 2 1 导入相关依赖 2 2 操作 三 poi 的使用 3 1 导入相关依赖 3 2 操作 四 总结 一 excel读取的两种方式 Java中
  • Java 简单控制台项目之家庭记账本 --- 凌宸1642

    项目一 家庭记账本 模拟实现一个基于文本界面的 模拟实现一个基于文本界面的 家庭记账软件 家庭记账软件 主要涉及以下知识点 变量的定义 基本数据类型的使用 循环语句 分支语句 方法声明 调用和返回值的接收 简单的屏幕输出格式控制 该软件能够
  • Oracle VM Virtualbox虚拟机教程

    Oracle Virtualbox的下载 我们使用不太操作系统的电脑来运行不同的功能和应用 常见的操作系统有Windows MacOS Linux Crome等等 通常我们在电脑上安装一个系统就不动了 当然也有双系统 但是比较麻烦 废时费力
  • proteus中的标签的使用方法。

    我们在proteus中绘制原理图的时候常常会遇到元器件的连线比较繁杂 导致原理图看起来比较乱 或者不是太好看 我们一般采用两种比较典型的方式来解决 一 标签 1 终端模式下的标签 终端模式下的标签须确保我们已经选择了终端模式 如下图 双击终
  • 使用Flask-Migrate迁移数据库

    1 安装 pipenv install flask migrate from flask import Flask from flask sqlalchemy import SQLAlchemy from flask migrate imp
  • static作用(修饰函数、局部变量、全局变量)

    转载自 http www cnblogs com stoneJin archive 2011 09 21 2183313 html 在C语言中 static的字面意思很容易把我们导入歧途 其实它的作用有三条 1 先来介绍它的第一条也是最重要
  • C++面试题:虚函数(virtual)可以是内联函数(inline)吗?

    原文链接 https github com huihut interview 答案 虚函数可以是内联函数 内联是可以修饰虚函数的 但是当虚函数表现多态性的时候不能内联 理由如下 内联是在发生在编译期间 编译器会自主选择内联 而虚函数的多态性
  • python 通过文件头获取文件类型mimetype

    一 MIME Type是什么 资源的媒体类型 MIME Multipurpose Internet Mail Extensions 多用途互联网邮件扩展类型 是设定某种扩展名的文件用一种应用程序打开的方式类型 当该扩展名文件被访问时 浏览器
  • 设计模式——代理模式

    代理模式概述 代理模式是Java开发中使用较多的一种设计模式 代理设计就是为其他对象提供一种代理以控制对这个对象的访问 代理类似中介的身份 应用场景 安全代理 屏蔽对真实角色的直接访问 远程代理 通过代理类处理远程方法调用 RMI 延迟加载
  • 调试HX711

    体重电路板HX711 1 下载程序 如果不正常用万用表测量输出电压是否正常 看BOOT键是否打开 RX TX是否接对 2 首先确保程序正确 I O口对应正确 3 连接体重计 如果串口接收数据不正常 首先检查称重传感器连线问题 然后用万用表测
  • Linux入门笔记-尚硅谷韩顺平-基础篇&实操篇

    文章目录 课程导论 基础篇 Linux入门 Linux介绍 Linux和Unix的关系 Linux和Windows比较 基础篇 Linux的目录结构 基本介绍 具体的目录结构 实操篇 vi和vim的使用 vi和vim的基本介绍 vi和vim
  • 节点编译问题 | FISCO BCOS开发问题排查

    1 源码编译慢 1 1 case1 先前没有编译过源码 修改 etc hosts文件 添加如下内容可加速依赖包的下载 140 82 113 4 github com 185 199 108 153 assets cdn github com
  • 【科普贴】SIM卡接口协议(ISO7816-3)详解

    一 SIM卡介绍 SIM Subscriber Identity Module 卡是GSM系统的移动用户所持有的IC卡 称为身份识别卡 SIM卡内部含有微处理器 它由CPU 8位 RAM 工作存储器 6 16KB ROM 程序存储器 3 8
  • Android.mk 语法详解

    Android mk 语法详解 转 http blog sina com cn s blog 602f8770010148ce html 0 Android mk简介 Android mk文件用来告知NDK Build 系统关于Source
  • 文件删不掉需要管理员权限?分享解决方法

    文件删不掉需要管理员权限 正常情况下 我们使用电脑时 遇到不需要的文件都可以直接手动删除 但有时候会出现无法删除文件的现象 提示 文件夹访问被拒绝 你需要提供管理员权限才能删除此文件 这时该怎么处理呢 下面就一起来看看吧 遇到需要管理员权限
  • 百度自动驾驶平台生态部负责人张亮:Apollo开放平台,连接技术场景 赋能人才生态

    社会的经济发展 国家政策的支持 科学技术的不断进步 消费者的购买热情 共同推动了自动驾驶行业的发展 自动驾驶汽车会使交通事故的发生率大大降低 方便更多的人开车出行 交通秩序变得更好 出行效率变得更高 2022年7月21日 由中国开源软件推进
  • kafka confluent schema registry 实现一个topic支持多个不同schema的表消费(包含报错信息及解决方式)

    背景 上篇文章已经说明confluent schema registry优点及如何实现 本文实现kafka confluent schema registry 一个topic多个不同结构的表消费需求 上篇文章 kafka Confluent
  • 【重构】-重复代码(duplicated Code)

    重构一 duplicated Code 重复代码 场景演义 议题一 同一个类的两个函数有相同代码片段 重构手法 Extract Method 把一段代码组织在一起并独立 放进一个独立函数中 并让函数名称解析该函数的用途 演义讲解 publi