避免过度精简临时变量----重构的问题
在我重构的过程中,我的代码出现了一个问题,出现了一个死循环!
重构的一个重要手段就是把可恶的临时变量去掉,而改之以方法的调用。这是Martin Fowler非常强调的一个思想。
重构的一大手段和目标是提炼出方法来。 将大段的代码分解成许多微型函数。而提炼函数的一大障碍就是到处出现的变量,特别是有时用途不多的临时变量。
于是,接受了这一思想的我也就把临时变量当作了眼中钉、肉中刺,千方百计予以删除,用多个方法调用来代替这些临时变量。
但是,间接的代码运行中却出现了致命的死循环!
请看这一个方法:
public boolean isNoneRepeatInList(List excelModelList) throws Exception{
/*
* 不要使用多于一个方法,对于 适当的临时变量,还是需要的!
* 注意: 有些方法还是工厂方法. 如果连用方法, 就会导致每次都新建实例的问题出现!
* */
Od1AdslUserForecastModelService service = (Od1AdslUserForecastModelService) getBean(SystemConstantsSDL.Od1AdslUserForecastModel_Service);
while(excelModelList.iterator().hasNext()){
Od1AdslUserForecastModel tmpModel=(Od1AdslUserForecastModel) excelModelList.iterator().next();
List repeatModelList=service.queryBySectionNameSubstationNameNodeNameForecastYear1ForecastQuarter1Name(tmpModel);
if(repeatModelList.size()>1){
//删除本批记录 deleteByBatchNum(String batchNum)
// public void deleteByBatchNum(DataDeclareQueryModelAdslForecast model) throws Exception
service.deleteByBatchNum(tmpModel);
throw new TelecomException("info.howDoIfError","对不起,您上传的Excel文件中含有已经录入的数据,请检查您的Excel文件!");
}
}
return true;
}
这一个方法中,我使用了excelModelList.iterator().hasNext()和excelModelList.iterator().next()这两句代码。
excelModelList.iterator()实际是创建了一个对象。
上面那两句导致了每一次都新建了一个对象,再调用它的.hasNext()。这样,即使是List只有1个对象,也可以永远有.hasNext()==true!
这就是问题所在!
所以,可以得出如下结论:
1, 不要连续使用多个方法。 一次只应该调用一个方法。 以免弄错!
2, 不要排斥使用临时变量。 临时变量确实能够使代码更易理解。 虽然有时它们提供了冗余的信息,但是这比信息不足导致的错误实现要好得多!
-------宁多勿缺!
3, 实际上,我们反对的临时变量, 是反对的那些一词多义的 临时变量。
即,我们反对 一个临时变量被在不同语句中赋值多次----代表多个语义。
4, 解决之道,就是保证变量值被赋值一次。 在变量前面加上final可以显式防止变量被多次赋值!
附上正确的代码:
public boolean isNoneRepeatInList(List excelModelList) throws Exception{
/*
* 不要使用多于一个方法,对于 适当的临时变量,还是需要的!
* 注意: 有些方法还是工厂方法. 如果连用方法, 就会导致每次都新建实例的问题出现!
* */
Od1AdslUserForecastModelService service = (Od1AdslUserForecastModelService) getBean(SystemConstantsSDL.Od1AdslUserForecastModel_Service);
Iterator iterator=excelModelList.iterator();
while(iterator.hasNext()){
Od1AdslUserForecastModel tmpModel=(Od1AdslUserForecastModel)iterator.next();
List repeatModelList=service.queryBySectionNameSubstationNameNodeNameForecastYear1ForecastQuarter1Name(tmpModel);
if(repeatModelList.size()>1){
//删除本批记录 deleteByBatchNum(String batchNum)
// public void deleteByBatchNum(DataDeclareQueryModelAdslForecast model) throws Exception
service.deleteByBatchNum(tmpModel);
throw new TelecomException("info.howDoIfError","对不起,您上传的Excel文件中含有已经录入的数据,请检查您的Excel文件!");
}
}
return true;
}