如何避免代码重复
2015-04-07 11:34
155 查看
对于每个编码人员来说,避免重复代码可能是大家都想做的。对于有一定经验(对基本的OO原则有一定经验)的开发人员来说,大部分情况下都能比较自然地避免重复代码的问题,写代码的时候,感觉有逻辑重复的情况,会很自然的凭感觉经验做相应的处理和复用。 以下是个人经验,供新手参考。
既然我们在用Java之类的面向对象的语言编码,那么重复代码可以大致分为如下两种情况:
1、类型体系之内(父类型和子类型、子类型之间)存在重复逻辑代码
2、类型体系之外的重复代码
【类型体系内的重复代码处理】
1、如果重复代码属于类型本身操作(即应该是以实例方法存在),则很自然的应用重构技巧,公共代码往上走。如果Sub Type之间有这种重复代码,把重复代码迁移到DefaultAdatper中。
2、如果重复代码不属于类型本身操作(即应该是以静态方法存在),则需要判断一下这种静态代码的功能使用范围:
A、如果是非常全局性的,例如有关java流的辅助操作,则应该果断的抽取出来,封装到一个Utility工具类中,例如可以叫做IOUtil。把这个Utility类放置到非常底层模块中,这样上层很多功能模块中都可以使用,否则可能会导致上层多个模块中都有类似IOUtil的类,又是重复代码。
1 public class IOUtil {
2 /**
3 * 工具类,不需要产生实例。 但是也不需要应用单态!!!
4 */
5 private IOUtil() {}
6
7 public static InputStream buildInputSteam(File file) {//
}
8
9 //其他公共静态操作
10 }
B、如果这种静态操作只对本类型体系有意义,则有两种常用的处理方法:第一种是把这种静态方法迁移到基类DefaultAdapter中,但是不要在DefaultAdapter中放置过多的类似静态方法;第二种是把这种静态方法封装到一个helper助手类中,例如MyTypeHelper,其中放置了MyType类型体系中需要使用的一些静态方法。如果第一种DefaultAdapter中堆放了较多的静态方法,则可以用helper助手类的方式。
1 public class MyTypeHelper {
2 /**
3 * 助手类,不需要产生实例。 但是也不需要应用单态!!!
4 */
5 private MyTypeHelper() {}
6
7 public static boolean validateParamer(Object paramer) {//
}
8
9 //其他公共静态操作
10 }
这个helper一般需要和接口、默认适配类一起暴露,便于扩展子类型使用。示意图如下:
【类型体系之外的重复代码处理】
类型体系之外的重复代码处理相对就很简单了,根据重复代码功能适用范围,封装到对应的Util类或者Helper类中。这里就不细讲了~_~
【有关公用代码的几个概念】
个人意见,仅供参考。
助手类(Helper class):我觉得首先这个类产生的目的是为特定模块或者特定功能服务的(助手吗~_~),不是全局的。而且完全可以隐藏在特定模块内部,很多时候不需要暴露。Helper类的命名要有针对性,不能搞成一个麻辣烫,里面的静态操作既为这种功能服务,又为那种功能服务,尽量做个忠臣,不要同时当多个主子的助手。
工具类(Utility class):一般是全局的,往往有一定普世价值,也就是说往往是全局通用的。
例如你在做一个模块,这个模块功能是处理表单,则关于处理表单的一些公用静态操作就应该放
4000
置到该模块的一个助手类中,名称类似于FormProcesserHelper。再有一个导出报表的功能,则对应的助手类可以称之为ExportReportHelper,建议这两个helper不要混在一起。 有人可能会说,这样会不会导致大量的助手类呢?这边有个粒度把握的问题(经验会发生作用~_~),但是只要是助手类命名规范,则一个助手类的名字就基本上可以告诉用户你提供什么样的服务了。
假如你现在处理的是有关IO操作的重复代码,则需要迁移到全局的工具类中,因为这样的操作往往适应于全局的。
Facade class(门面类):这个乍看起来和助手类有点像,往往是绑定于特定模块。但是,要搞清楚,门面类是用来封装子系统的,代理对模块常用核心功能的访问的,针对用户需要的常用场景提供一些辅助操作,帮助用户更好的使用此模块的主要功能。面向客户端或者其他子系统或模块的,不是用来处理对应模块中重复代码的!!!有关详细信息,请参加Facade设计模式的文档。
【注意】Helper class、Utility class、Facade class一般都不需要生实例,暴露的都是静态操作,更不需要误写成单态,别滥用单态!!!
重复代码
第一个例子:
第一个方法:getCount
第二个方法:pageQueryKbdb
上面两个方法中,第一个是求总数,第二个方法是分页查询详细内容。
这两个方法的SQL中除了select count(ID)不一样,其他一模一样,这样的代码,如果将来SQL变了,你需要同时修改两个地方,如果没有注意,两个SQL不一致,结果会差很多。
上面的的SQL完全可以从from KBJCJL这里开始单独创建一个方法,方法返回一个String类型的SQL即可。
将上面的两个方法修改后如下:
增了一个方法getKbdsSql
原来的两个方法修改为:
上面这种修改方式很容易,主要是因为这两个SQL差异太小,但是如果JAVA处理SQL时,不同的地方很多,可能需要上面的方法再拆分成多个方法重新组合。
这个类中,还有多处类似的代码,看下面的GetClCount方法:
你觉得这个方法眼熟吗?
但是这个方法写的和前面的两个方法不一样,但是逻辑呢?
其实逻辑一模一样,而且结果也一样,并且这里写的switch-case比上面的要规范,为什么?
因为这里的case是从1到18排列的,并且其中的13、14是用default处理的。
只有13对应的值不一样
所以这看着不一样的代码却做着几乎相同的事,非常的不合理。
完全可以在提取的方法中,单独写出case 13进行处理。
然后GetClCount方法完全可以调用修改后的方法。
记住:
a. 如果有一段代码出现了两次,如果代码很短(4,5行),而且结构不是很好,可以直接复制。如果代码很长,将代码独立出来。
b. 如果方法出现了两次以上,将代码独立出来。
c. 不同类如果调用相同的方法,可以独立到一个公共类中,所有的类都调用这一个类的方法,而不是把该方法分别复制到每个类中。
既然我们在用Java之类的面向对象的语言编码,那么重复代码可以大致分为如下两种情况:
1、类型体系之内(父类型和子类型、子类型之间)存在重复逻辑代码
2、类型体系之外的重复代码
【类型体系内的重复代码处理】
1、如果重复代码属于类型本身操作(即应该是以实例方法存在),则很自然的应用重构技巧,公共代码往上走。如果Sub Type之间有这种重复代码,把重复代码迁移到DefaultAdatper中。
2、如果重复代码不属于类型本身操作(即应该是以静态方法存在),则需要判断一下这种静态代码的功能使用范围:
A、如果是非常全局性的,例如有关java流的辅助操作,则应该果断的抽取出来,封装到一个Utility工具类中,例如可以叫做IOUtil。把这个Utility类放置到非常底层模块中,这样上层很多功能模块中都可以使用,否则可能会导致上层多个模块中都有类似IOUtil的类,又是重复代码。
1 public class IOUtil {
2 /**
3 * 工具类,不需要产生实例。 但是也不需要应用单态!!!
4 */
5 private IOUtil() {}
6
7 public static InputStream buildInputSteam(File file) {//
}
8
9 //其他公共静态操作
10 }
B、如果这种静态操作只对本类型体系有意义,则有两种常用的处理方法:第一种是把这种静态方法迁移到基类DefaultAdapter中,但是不要在DefaultAdapter中放置过多的类似静态方法;第二种是把这种静态方法封装到一个helper助手类中,例如MyTypeHelper,其中放置了MyType类型体系中需要使用的一些静态方法。如果第一种DefaultAdapter中堆放了较多的静态方法,则可以用helper助手类的方式。
1 public class MyTypeHelper {
2 /**
3 * 助手类,不需要产生实例。 但是也不需要应用单态!!!
4 */
5 private MyTypeHelper() {}
6
7 public static boolean validateParamer(Object paramer) {//
}
8
9 //其他公共静态操作
10 }
这个helper一般需要和接口、默认适配类一起暴露,便于扩展子类型使用。示意图如下:
【类型体系之外的重复代码处理】
类型体系之外的重复代码处理相对就很简单了,根据重复代码功能适用范围,封装到对应的Util类或者Helper类中。这里就不细讲了~_~
【有关公用代码的几个概念】
个人意见,仅供参考。
助手类(Helper class):我觉得首先这个类产生的目的是为特定模块或者特定功能服务的(助手吗~_~),不是全局的。而且完全可以隐藏在特定模块内部,很多时候不需要暴露。Helper类的命名要有针对性,不能搞成一个麻辣烫,里面的静态操作既为这种功能服务,又为那种功能服务,尽量做个忠臣,不要同时当多个主子的助手。
工具类(Utility class):一般是全局的,往往有一定普世价值,也就是说往往是全局通用的。
例如你在做一个模块,这个模块功能是处理表单,则关于处理表单的一些公用静态操作就应该放
4000
置到该模块的一个助手类中,名称类似于FormProcesserHelper。再有一个导出报表的功能,则对应的助手类可以称之为ExportReportHelper,建议这两个helper不要混在一起。 有人可能会说,这样会不会导致大量的助手类呢?这边有个粒度把握的问题(经验会发生作用~_~),但是只要是助手类命名规范,则一个助手类的名字就基本上可以告诉用户你提供什么样的服务了。
假如你现在处理的是有关IO操作的重复代码,则需要迁移到全局的工具类中,因为这样的操作往往适应于全局的。
Facade class(门面类):这个乍看起来和助手类有点像,往往是绑定于特定模块。但是,要搞清楚,门面类是用来封装子系统的,代理对模块常用核心功能的访问的,针对用户需要的常用场景提供一些辅助操作,帮助用户更好的使用此模块的主要功能。面向客户端或者其他子系统或模块的,不是用来处理对应模块中重复代码的!!!有关详细信息,请参加Facade设计模式的文档。
【注意】Helper class、Utility class、Facade class一般都不需要生实例,暴露的都是静态操作,更不需要误写成单态,别滥用单态!!!
重复代码
第一个例子:
第一个方法:getCount
第二个方法:pageQueryKbdb
上面两个方法中,第一个是求总数,第二个方法是分页查询详细内容。
这两个方法的SQL中除了select count(ID)不一样,其他一模一样,这样的代码,如果将来SQL变了,你需要同时修改两个地方,如果没有注意,两个SQL不一致,结果会差很多。
上面的的SQL完全可以从from KBJCJL这里开始单独创建一个方法,方法返回一个String类型的SQL即可。
将上面的两个方法修改后如下:
增了一个方法getKbdsSql
原来的两个方法修改为:
上面这种修改方式很容易,主要是因为这两个SQL差异太小,但是如果JAVA处理SQL时,不同的地方很多,可能需要上面的方法再拆分成多个方法重新组合。
这个类中,还有多处类似的代码,看下面的GetClCount方法:
你觉得这个方法眼熟吗?
但是这个方法写的和前面的两个方法不一样,但是逻辑呢?
其实逻辑一模一样,而且结果也一样,并且这里写的switch-case比上面的要规范,为什么?
因为这里的case是从1到18排列的,并且其中的13、14是用default处理的。
只有13对应的值不一样
所以这看着不一样的代码却做着几乎相同的事,非常的不合理。
完全可以在提取的方法中,单独写出case 13进行处理。
然后GetClCount方法完全可以调用修改后的方法。
记住:
a. 如果有一段代码出现了两次,如果代码很短(4,5行),而且结构不是很好,可以直接复制。如果代码很长,将代码独立出来。
b. 如果方法出现了两次以上,将代码独立出来。
c. 不同类如果调用相同的方法,可以独立到一个公共类中,所有的类都调用这一个类的方法,而不是把该方法分别复制到每个类中。
相关文章推荐
- android中从手机添加联系人,如何避免重复添加的代码的问题
- Python OOP中如何在继承中避免代码重复设计
- 如何设计循环避免代码重复,提高代码复用性
- 如何避免重复包含一个头文件?#ifndef #define #endif #Pragma
- ASP.NET 如何避免页面重新整理时重复送...
- 如何避免表单的重复提交
- 如何避免表单的重复提交
- 如何检测和避免代码中的存储转发冲突
- 如何避免重复提交
- Vc++ 6.0 如何避免重复包含一个头文件 error C2011
- 更新操作如何防止带外键的字段出现重复,代码实现方法
- 如何避免重复包含一个头文件?#ifndef #define #endif #Pragma
- 如果只修改部分代码如何避免整个工程重新编译
- 使用简单的javascript代码避免页面的重复提交(没有加入提交代码)
- 如何避免重复定义数组
- sql server:向表中批量插入记录时如何避免重复插入记录
- 如何避免重复包含一个头文件?#ifndef #define #endif #Pragma
- 如何避免重复的http请求
- [转贴]JDK5下避免DAO代码重复--原文名称:不要重复 DAO
- jsp或struts如何避免Form重复提交,不然数据中的插入的纪录有重复的!