`
fangang
  • 浏览: 881830 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
311c4c32-b171-3767-b974-d26acf661fb2
谈谈用例模型的那些事儿
浏览量:38960
767c50c5-189c-3525-a93f-5884d146ee78
一次迭代式开发的研究
浏览量:68954
03a3e133-6080-3bc8-a960-9d915ed9eabc
我们应当怎样做需求分析
浏览量:410915
753f3c56-c831-3add-ba41-b3b70d6d913f
重构,是这样干的
浏览量:93691
社区版块
存档分类
最新评论

代码复用应该这样做(2)

阅读更多
以上是对一个对象中各函数间的代码复用。另一种情况是这被比较的两份或者多份代码不在同一个对象中,这应该怎么办呢?我们可以采用的办法比较多,首先一种比较直观的办法就是运用“抽取类”将共同的部分抽取到一个工具类中,为其它各类所调用。比如,看看这个例子:

我们有个遗留系统在大量地方需要获取当前服务器时间,该功能在过去版本中这样写:
Date now = new Date();

后来JDK升级以后该方法被废掉了,所有获取当前时间的代码都要被改成这样:
Calendar calendar = Calendar.getInstance();
Date now = calendar.getDate();

但随后的问题就来了,整个系统有数十处获取当前时间的代码,它们都要被修改,这就很烦人了。此外,还有一些代码是要获取当前的月份:
Calendar calendar = Calendar.getInstance();
int thisMonth = calendar.get(Calendar.MONTH)+1;

它们都十分相似,但功能又不完全相同。这时,可以将它们提取出来形成一个DateUtil工具类:
/**
 * 处理日期时间工具类
 * @author fangang
 */
public class DateUtil {
	/**
	 * @return 获得当前Calendar
	 */
	public static Calendar getCalendar(){
		Calendar calendar = Calendar.getInstance();
		return calendar;
	}
	/**
	 * @return 获得今年
	 */
	public static int getThisYear(){
		return getCalendar().get(Calendar.YEAR);
	}
	/**
	 * @return 获得本月
	 */
	public static int getThisMonth(){
		return getCalendar().get(Calendar. MONTH)+1;
	}
	/**
	 * @return 获得当前时间
	 */
	public static Date getNow(){
		return getCalendar().getDate();
	}
}

这样,系统中所有获得当前时间与当前月份的代码都这样写:
Date now = DateUtil.getNow();
int thisMonth = DateUtil.getThisMonth();

采用工具类的方法非常实用,被合并的代码即使分散在系统的各个角落,各自功能没有任何联系,都可以采用。该方法可以有效解决代码变更中的“散弹枪式修改(Shotgun Surgery)”问题,即一个需求的变更导致分散在各处的代码修改。如果将分散在各处的代码统一成一个工具类,则需求的变更就仅仅变成对这个工具类的修改,“散弹枪式修改”的问题就得以解决。

另外一种与该方法比较类似的方法,就是提取并封装成实体类。当重复代码被分散在原程序的多个代码段中,并且其内部存在着较强的业务相关性时,可将这些代码提取并封装成一个实体类,该实体类应当体现出这种业务相关性。在前一种方法中,工具类仅仅表现为一堆方法的集合,而该方法中,该实体类体现的是一定的业务逻辑,并在使用时需要实例化。看看这个例子:

在许多系统中,诸如Servlet或Action都需要通过request读取前端传送的数据,但这些数据需要频繁通过转换转成各种数据类型。这些转换过程往往会造成大量重复代码:
double amount = Double.valueOf(req.getParameter(“amount”)).doubleValue();
int count = Integer.valueOf(req.getParameter(“count”)).intValue();
String name = new String(req.getParameter(“name”).getBytes(),"GBK");
Date now = DateUtil.getDate(req.getParameter(“now”),"yyyy-MM-dd");

但所有这些操作都存在一个内在的联系,即都是在通过request读取前端数据,因此我们将它们封装成一个Reader类,并将request作为参数,在实例化时传递过去:
/**
 * 默认的读取器,读取POST提交的数据
 * @author fangang
 */
public class Reader {
	private HttpServletRequest req = null;
	/* 
	 * Constructor with request
	 * @param HttpServletRequest
	 */
	public Reader(HttpServletRequest req) throws IOException {
		this.req = req;
	}
	/* 
	 * @param name of a parameter
	 * @return the data of Object
	 */
	public Object getData(String name) throws IOException {
		Object data = req.getParameter(name);
		if (data==null) {
			throw new IOException("读取器未读出相应数据:"+name);
		}
		return data;
	}
	/* 
	 * @param name of a parameter
	 * @return the data of double
	 */
	public double getDouble(String name) throws IOException {
		return Double.valueOf(getString(name)).doubleValue();
	}
	/* 
	 * @param name of a parameter
	 * @return the data of int
	 */
	public int getInteger(String name) throws IOException {
		return Integer.valueOf(getString(name)).intValue();
	}
	/* 
	 * @param name of a parameter
	 * @return the data of String
	 */
	public String getString(String name) throws IOException {
		return getData(name).toString();
	}
	/* 
	 * @param name of a parameter
	 * @return the data of Chinese String
	 */
	public String getChinese(String name) throws IOException {
		return new String(getString(name).getBytes(),"GBK");
	}
	……
}

这样,在编写这类似的程序时就不再那么麻烦了:
Reader reader = new Reader(req);
double amount = reader.getDouble(“amount”);
int count = reader.getInteger(“count”);
String name = reader.getChinese(“name”);
Date now = reader.getDate(“now”);

这样的设计好处多多。首先,如果出现什么因JDK的调整需要修改转换程序的写法时,修改Reader类中的相应方法就可以了,过去这类似的“散弹枪式修改”得到抑制。其次,如果有其它的方法过去需要传递request的,现在将不再需要传递,而是替换成传递reader,这将可以一定程度实现对web容器的解耦。不仅如此,如果今后需要修改设计,不使用request传递数据,而是采用其它方式,则只需要修改Reader的实现就可以了,程序可维护性与易变更性得到提高。
(续)

相关文档
遗留系统:IT攻城狮永远的痛
需求变更是罪恶之源吗?
系统重构是个什么玩意儿
我们应当改变我们的设计习惯
小步快跑是这样玩的(上)
小步快跑是这样玩的(下)
代码复用应该这样做(1)
代码复用应该这样做(2)
代码复用应该这样做(3)
做好代码复用不简单(1)

特别说明:希望网友们在转载本文时,应当注明作者或出处,以示对作者的尊重,谢谢!
分享到:
评论
6 楼 eve 2014-01-15  
public static Calendar getCalendar(){  
        Calendar calendar = Calendar.getInstance();  
        return calendar;  
}

为甚不直接
return Calendar.getInstance()
5 楼 fangang 2014-01-13  
你这样说,想必也有你的道理,咱求同存异
4 楼 LinApex 2014-01-13  
fangang 写道
LinApex 写道
我能说,这一句就不合理么?

if (data==null) { 
            throw new IOException("读取器未读出相应数据:"+name); 


返回null即可。


很多人都是这样写的,但这在许多时候不是一个好的设计,因为返回null以后,是不是会影响到后续的客户程序还要处理null,处理null就意味着封装不够完全。当然不是绝对的,看具体情况,已经设计者的习惯。



处理null,封装不够完全?为什么有这种想法。
在编程世界中,无 就是 null。 空,没有 代表 ""。

我只是想说明,这里不太合理,希望你可以改正一下。

像判断null,我写了一个小工具,批量判断null..
3 楼 fangang 2014-01-13  
LinApex 写道

代码复用? 我只遵循几个规则,其中有一条叫,如果代码中出现了两次以上重复的代码,那你应该要考虑重构了.  复用/重构不是一开始就能考虑到的,但要尽量考虑全面,这东西换个说法,也叫做编程经验。


哎,让我说啥呢,你自己体味吧
2 楼 fangang 2014-01-13  
LinApex 写道
我能说,这一句就不合理么?

if (data==null) { 
            throw new IOException("读取器未读出相应数据:"+name); 


返回null即可。


很多人都是这样写的,但这在许多时候不是一个好的设计,因为返回null以后,是不是会影响到后续的客户程序还要处理null,处理null就意味着封装不够完全。当然不是绝对的,看具体情况,已经设计者的习惯。


LinApex 写道
还有其他的全都是 return Integer.valueOf(getString(name)).intValue();  

没有考虑到复杂一点的业务判断逻辑...

如果有经验的应该这样考虑...

1.封装一个Map工具
2.将parameter值封装进Map.
3.将map转成bean.

其他的日志我就不研究你的了。

代码复用? 我只遵循几个规则,其中有一条叫,如果代码中出现了两次以上重复的代码,那你应该要考虑重构了.  复用/重构不是一开始就能考虑到的,但要尽量考虑全面,这东西换个说法,也叫做编程经验。


不得不说你可能还没有看懂这段代码,这段代码是在还未封装成bean前,一个一个读取request中的数据要做的事情。当然,现在很多框架将这一步都自动完成了,但现在我讨论的是遗留系统,是数年前开发的遗留系统。
1 楼 LinApex 2014-01-13  
我能说,这一句就不合理么?

if (data==null) { 
            throw new IOException("读取器未读出相应数据:"+name); 


返回null即可。


还有其他的全都是 return Integer.valueOf(getString(name)).intValue();  

没有考虑到复杂一点的业务判断逻辑...

如果有经验的应该这样考虑...

1.封装一个Map工具
2.将parameter值封装进Map.
3.将map转成bean.

其他的日志我就不研究你的了。

代码复用? 我只遵循几个规则,其中有一条叫,如果代码中出现了两次以上重复的代码,那你应该要考虑重构了.  复用/重构不是一开始就能考虑到的,但要尽量考虑全面,这东西换个说法,也叫做编程经验。

相关推荐

    CMMI 代码复用报告 模板

    **CMMI 代码复用报告模板详解** 代码复用是软件开发中的一项关键实践,旨在提高效率,减少错误,并促进代码的可维护性。CMMI(Capability Maturity Model Integration,能力成熟度模型集成)是衡量软件开发过程质量...

    delphi中几种代码的复用及其比较

    在Delphi编程环境中,代码复用是提高效率和软件质量的关键策略。代码复用不仅可以简化编码,减少工作量,还能促进团队协作,提高代码的可维护性和一致性。本文主要探讨了在只使用Delphi作为开发工具的情况下,如何...

    运用LabVIEW实现机器人中的代码复用.zip

    本资料包“运用LabVIEW实现机器人中的代码复用.zip”主要关注如何利用LabVIEW提高开发效率,通过代码复用来缩短项目周期。 首先,代码复用是软件工程中的一个核心概念,旨在减少重复工作,提升开发速度和代码质量。...

    C++可复用代码——命令行控制模块

    在C++编程中,代码复用是提高效率和减少错误的关键。本项目“C++可复用代码——命令行控制模块”提供了一个基础框架,帮助开发者轻松构建自定义的命令行Shell程序。这个框架旨在使程序员能够专注于实现特定功能,而...

    第5章 函数和代码复用.pdf

    ### 第5章 函数和代码复用 #### 知识点概述 本章节主要围绕着函数的概念、定义、使用以及代码复用的方式展开讨论。针对Delphi环境下的Python语言程序设计,深入剖析了如何利用函数实现更高效、灵活的编程实践。 #...

    python函数及代码复用学习教案.pptx

    python函数及代码复用学习教案.pptx

    c++设计模式简单使用对比-简单体会代码复用

    这种机制使得代码复用变得简单,同时也促进了类的分层结构,有助于创建更复杂的系统。例如: ```cpp class Worker { public: void work() { // 工人的一般工作 } }; class AdvancedWorker : public Worker { ...

    基于上下文的智能化代码复用推荐.pdf

    《基于上下文的智能化代码复用推荐》这篇文章探讨了如何利用现代技术和大数据分析来提高软件开发中的代码复用效率和质量。代码复用是开发者常用的一种高效开发手段,包括复用相似功能模块、代码片段以及API等不同...

    基于上下文的智能化代码复用推荐.docx

    《基于上下文的智能化代码复用推荐》\n\n代码复用是软件开发中的关键实践,旨在提升开发效率和代码质量。随着互联网的发展,代码大数据的积累为智能化代码复用推荐提供了新的可能性。本文主要探讨了两个核心方向:...

    运行时代码随机化防御代码复用攻击.pdf

    【运行时代码随机化防御代码复用攻击】 代码复用攻击是一种高级的恶意攻击手段,它利用了程序中已存在的可执行代码片段(称为gadgets)来构造新的恶意指令序列,绕过传统安全机制。随着攻击技术的发展,代码复用...

    代码复用避免篇1

    在编程领域,代码复用是提高效率和保持代码可维护性的重要原则。然而,不当的代码复用可能会引入问题。本文将探讨四种常见的代码复用模式,并分析它们的优缺点。 首先,我们来看“默认模式”的代码复用,即通过父类...

    jsp页面代码复用组件工具:easylayout

    2. **代码复用** - 通过easylayout,开发者可以创建可重用的布局和组件,减少重复代码,提高代码质量,同时降低维护成本。 3. **布局管理** - 工具可能提供了预定义的布局模板,如栅格系统、响应式布局等,以适应...

    频分复用的matlab代码

    以下是一个简单的MATLAB频分复用代码示例: ```matlab % 定义信号参数 x = 1544:1558; % 时间轴,范围从1544到1558,步长为1 bandwidth = 0.1; % 子信道带宽 % 生成三个独立的信号 signal1 = exp(-((x-1550)/...

    查理复用下的led数码管.rar

    在本压缩包中,包含的是关于查理复用LED数码管的源代码,适用于那些希望在项目中使用这种高效驱动技术的开发者。 查理复用的基本原理是:假设我们有n个LED和n个GPIO引脚,理论上最多可以控制2^(n-1)个LED,因为不是...

    21丨理论七:重复的代码就一定违背DRY吗?如何提高代码的复用性?1

    DRY(Don't Repeat ...总的来说,理解并正确应用DRY原则,以及掌握如何提高代码复用性,是提高软件质量、降低维护成本的关键。在实际开发中,我们需要时刻注意识别和消除代码的冗余,使我们的代码更加简洁、高效。

    Python语言 Python123 测验5: 函数和代码复用(编程题)

    补充编程模板中代码,完成如下功能:‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪...

    Android自定义view实现代码复用

    本教程将通过一个具体的示例——HZLoginView,深入讲解如何在Android中创建自定义View并实现代码复用及自定义属性。 首先,理解自定义View的基本步骤: 1. 创建一个新的Java类:通常,我们继承自Android的基础View...

    面向Linux的内核级代码复用攻击检测技术.pdf

    2. **内核级代码复用攻击**:针对操作系统内核的代码复用攻击,由于内核权限高,一旦被利用,可能导致系统级别的破坏。 3. **控制流完整性(CFI)**:一种安全技术,用于保护程序免受代码注入和跳转攻击,通过确保...

    IO多路复用之poll——完整代码

    三种IO多路复用机制: 一:select 二:poll 三:epoll 以上三种IO多路复用的完整代码,皆可以在我的资源列表中获取下载: 资源列表:http://download.csdn.net/user/qiulanzhu

Global site tag (gtag.js) - Google Analytics