【问题】
遗留项目的维护开发中 如何避免新添加代码变成包袱?
需要说明的是本文内容简单但是确实有点长,但是相信耐心看完的你必定会有所收获,这种重构的思路在日常工作中会特别实用,尤其适用于遗留项目的维护开发工作中。不再废话,请看以下C语言代码片段:
/*
* Source file main.c
*/
#include
#include
#include "method.h"
int main()
{
int c = method_one_param("Something needs to be done with only one input parameter!");
if (0 != c)
exit(c);
return 0;
}
/*
* Header file method.h
*/
#ifndef _METHOD_H_
#define _METHOD_H_
extern int method_one_param(char *);
#endif /* _METHOD_H_*/
/*
* Source file method.c
*/
#include "method.h"
int method_one_param(char *str)
{
int ret = 0;
// step one
// step two
// step three
// ...
// other steps
return ret;
}
显而易见,main()函数中我们调用仅包含一个char*类型入参的函数method_one_param()来完成某一逻辑。现在有一个新的需求,需要在main()函数中依据一个bool类型变量的值来决定被调用函数method_one_param()的执行逻辑,比如条件性的增加新的逻辑或者执行某一逻辑。
【问题分析】
为了达到需求,我们需要针对函数method_one_param()增加一个bool变量,当该变量取值为TRUE时执行原有的代码逻辑;当该变量为FALSE时,执行新增加的逻辑。故最终的函数调用情况如下:
/*
* Source file main.c updated
*/
#include
#include
#include "method.h"
int main()
{
int c = 0;
bool isTrue = FALSE;
if (isTrue) { /* TRUE分支保证代码原有行为 -- 调用方式改变 */
c = method_one_param("Something needs to be done when 'isTure = TRUE'!", TRUE);
} esle { /* 新增加逻辑 -- 传递一个值为FALSE类型的变量 */
c = method_one_param("Any otherthing needs to be done when 'isTure = FALSE'!", FALSE);
}
if (0 != c)
exit(c);
return 0;
}
看似可以完美解决当前的问题,但假如函数method_one_param()在其他地方多次被调用,那我们是不是需要更新所有调用处,因为被调用方法增加了一个新的布尔类型变量。仔细想想你肯定遇到过很多类似情况!!!
OK,为了避免多处更新操作,可以使用默认参数啊?听起来很不错,那就试试呗!更新代码如下:
/*
* Header file method.h
*/
#ifndef _METHOD_H_
#define _METHOD_H_
extern int method_one_param(char *, bool);
#endif /* _METHOD_H_*/
/*
* Source file method.c updated
*/
#include "method.h"
int method_one_param(char *str, bool isAllowed = TRUE)
{
int ret = 0;
// step one
// step two
if (isAllowed)
// step three
else
// new added step
// ...
// other steps
return ret;
}
/*
* Source file main.c updated
*/
#include
#include
#include "method.h"
int main()
{
int c = 0;
bool isTrue = FALSE;
if (isTrue) { /* 原有逻辑未作任何改变 -- 调用方式 */
c = method_one_param("Something needs to be done when 'isTure = TRUE'!");
} esle { /* 新增加逻辑,传递一个值为FALSE类型的变量 */
c = method_one_param("Any otherthing needs to be done when 'isTure = FALSE'!", FALSE);
}
if (0 != c)
exit(c);
return 0;
}
接下来编译程序,很意外的出现以下错误提示:
../method.c(5) : error C2143: syntax error : missing ')' before '='
../method.c(5) : error C2072: 'method_one_param' : initialization of a function
../method.c(5) : error C2059: syntax error : ')'
../method.c(6) : error C2143: syntax error : missing ';' before '{'
../method.c(6) : error C2449: found '{' at file scope (missing function header?)
../method.c(6) : error C2059: syntax error : '}'
gmake[1]: *** [../method.obj] Error 2
gmake[1]: Leaving directory `../../test'
错误提示大概意思是:在函数method_one_param(char*, bool)定义处存在问题,有点莫名其妙!如何排查问题?既然因为默认参数的引入导致的,那我们是否需要确认下C语言默认参数的相关知识?最终的答案是:C语言不支持默认参数。
【解决方法】
一个可行的方案:基于原始被调用方法method_one_param(),增加一个新的布尔类型的参数isAllowed,命名为新的静态方法method_internal(char *, bool),其内部逻辑仅仅是依据参数isAllowed稍加改动而已,也就是说新的静态方法是原有被调用方法的条件版本。这样做的好处是:原始被调用方法只需要更新函数体,以特定的isAllowed值调用新的静态方法,也就是对原有的代码逻辑没有任何影响。
/*
* Header file method.h
*/
#ifndef _METHOD_H_
#define _METHOD_H_
extern int method_one_param(char *);
extern int method_one_param_with_option(char *);
static int method_internal(char *, bool);
#endif /* _METHOD_H_*/
/*
* Source file method.c
*/
/* 基于method_one_param()的实现逻辑新增加的静态方法 */
static int method_internal(char *str, bool isAllowed)
{
int ret = 0;
// step one
// step two
if (isAllowed)
// step three
else
// new added step
// step four
// ...
// other steps
return ret;
}
/* 用'isAllowed = TRUE'来调用新增加的静态方法,以此保证原始方法行为未做变更 */
int method_one_param(char *str)
{
return method_internal(str, TRUE);
}
/* 为新的需求而增加的方法 */
int method_one_param_with_option(char *str)
{
return method_internal(str, FALSE);
}
/*
* Source file main.c
*/
int main()
{
bool isTrue = FALSE;
int c = 0;
if (isTrue) { /* 原始的方法调用未有任何改变 */
c = method_one_param("Something needs to be done when 'isTure = TRUE'!");
} esle { /* 新的需求对应的逻辑 */
c = method_one_param_with_option("Any otherthing needs to be done when 'isTure = FALSE'!");
}
if (0 != c)
exit(c);
return 0;
}