以上是对一个对象中各函数间的代码复用。另一种情况是这被比较的两份或者多份代码不在同一个对象中,这应该怎么办呢?我们可以采用的办法比较多,首先一种比较直观的办法就是运用“抽取类”将共同的部分抽取到一个工具类中,为其它各类所调用。比如,看看这个例子:
我们有个遗留系统在大量地方需要获取当前服务器时间,该功能在过去版本中这样写:
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)
特别说明:希望网友们在转载本文时,应当注明作者或出处,以示对作者的尊重,谢谢!
分享到:
相关推荐
CMMI 代码复用报告 模板 CMMI 代码复用报告 模板
第5章 函数和代码复用.pdf
我们在软件开发中,经常会碰到多处代码相同或...代码复用的作用也不仅是使得代码编写简单、减少工作量。本文只讨论在一个只使用delphi作为开发工具的团队如何有效的进行代码复用,如何在开发进度、软件维护之间取得平衡
python函数及代码复用学习教案.pptx
c++设计模式简单使用对比-简单体会代码复用。包括虚函数的使用方法,继承等
Python课程资源,有关函数和代码的复用PPT
包含java常用的代码,可以直接拷贝。减少代码编写工作量。
缩短开发时间的最高效方式之一,是代码复用。无论是已经写好还是属于资源库的现有代码,通过利用它,开发者和各领域的专家都能专注于自己的应用,而不再将宝贵的时间和资源用作编程。
利用一个demo实例来实现代码复用,以及自定义属性等
设计模式可复用面向对象软件的基础 源代码 设计模式可复用面向对象软件的基础 源代码 gof
很好用很实用的matlab频分复用代码测试
三种IO多路复用机制: 一:select 二:poll 三:epoll 以上三种IO多路复用的完整代码,皆可以在我的资源列表中获取下载: 资源列表:http://download.csdn.net/user/qiulanzhu
一个命令行Shell程序的基础框架,轻松地用C++编写自己的shell
用matlab仿真时分复用的调制解调过程
代码复用及其原则 代码复用,顾名思义就是对曾经编写过的代码的一部分甚至全部重新加以利用,从而构建新的程序。在谈及代码复用的时候,我们首先可以想到的是继承性。代码复用的原则是: 优先使用对象组合,而不是...
介绍任何编程都提出代码复用,否则话每次开发一个新程序或者写一个新功能都要全新编写的话,那就歇菜了,但是代码复用也是有好要坏,接下来的两篇文章我们将针对代码复用来
运行时代码随机化防御代码复用攻击.pdf
实用的解码解复用源代码和mp4源代码
2.领域:智能优化算法、神经网络预测、信号处理、元胞自动机、图像处理、路径规划、无人机等多种领域的Matlab仿真,更多内容可点击博主头像 3.内容:标题所示,对于介绍可点击主页搜索博客 4.适合人群:本科,硕士...
基于个人文章的查理复用源代码文件,内容只存在驱动,需要根据不同MCU环境进行一定的嵌入