再平常开发过程中,随着平台的增多,以及逻辑的增加,项目会变得难以维护。像下面这样的,例子是上篇字符处理的。不过能够讲明意义即可。
int main(int argc, char *argv[])
{
// output = stdout; // 重定向与错误输出
// qInstallMessageHandler(outputRedirection);
char buf[100] ="TxZ[";
uint16_t len = 0xFFFF;
int len_length = 0;
#ifdef USE_CHAR
typedef uint16_t INT;
len_length =sizeof(len);
memcpy(buf+4,&len,sizeof(len));
#else
typedef int32_t INT;
len_length =4;
char len_hex[5]={0};
memset(len_hex,0,sizeof(len_hex));
snprintf(len_hex,sizeof(len_hex),"%4x",len);
memcpy(buf+4,len_hex,len_length); //长度
#endif
buf[4+len_length]=']';
buf[4+len_length+1]='\0';
fwrite(buf,4+len_length+1,1,stdout);
return 0;
}
所以这里提供几个 技巧,以供参考与启发。
导入源文件
所谓的重构啊,第一步都是将 重复的代码进行 封装 而已。
所以你可以将 上面的 //大段代码... 进行抽取。然后再导入的方式
int main(int argc, char *argv[])
{
//...
#ifdef USE_CHAR
#include "Algorithm1.cpp"
#else
#include "Algorithm2.cpp"
#endif
//...
return 0;
}
然后 你就需要 在每个cpp中 分别实现即可。
//Algorithm1.cpp
typedef uint16_t INT;
len_length =sizeof(len);
memcpy(buf+4,&len,sizeof(len));
//Algorithm2.cpp
typedef int32_t INT;
len_length =4;
char len_hex[5]={0};
memset(len_hex,0,sizeof(len_hex));
snprintf(len_hex,sizeof(len_hex),"%4x",len);
memcpy(buf+4,len_hex,len_length); //长度
上述文件不能添加到 CMakeLists.txt 中。要不然编译不过。
也许这里的例子太过狭隘。现在我在换个地方来导入也许就不会这么突兀了。
//pcre\src\sljit\sljitNativePPC_common.c
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
#include "sljitNativePPC_32.c"
#else
#include "sljitNativePPC_64.c"
#endif
在这里 将 代码 放置在方法体外,从而直接导入 相应的实现即可
通过Makefile 分别导入
现在我们把实现剥离出来
#include "Algorithm.h"
int main(int argc, char *argv[])
{
char buf[100] ="TxZ[";
uint16_t len = 0xFFFF;
int len_length = 0;
dosth(buf);// 这里
buf[4+len_length]=']';
buf[4+len_length+1]='\0';
fwrite(buf,4+len_length+1,1,stdout);
return 0;
}
然后实现分开
//Algorithm.h
#include <inttypes.h>
#ifdef USE_CHAR
typedef uint16_t INT;
#else
typedef int32_t INT;
#endif
int dosth(char * buf,INT len);
//Algorithm1.cpp
#include"Algorithm.h"
#include <string.h>
int dosth(char * buf,INT len){
memcpy(buf+4,&len,sizeof(len));
return sizeof(len);
}
//Algorithm2.cpp
#include <string.h>
#include <stdio.h>
#include "Algorithm.h"
int dosth(char * buf,INT len){
int len_length =4;
char len_hex[5]={0};
memset(len_hex,0,sizeof(len_hex));
snprintf(len_hex,sizeof(len_hex),"%4x",len);
memcpy(buf+4,len_hex,len_length); //长度
return len_length;
}
然后在编译脚本里面 将不同的实现进行导入即可。qmake 的写法
DEFINES += USE_CHAR
contains(DEFINES,USE_CHAR){
SOURCES += Algorithm1.cpp
}else{
SOURCES += Algorithm2.cpp
}
这种方式也是可以,而且更加好看。cmake 的写法
set(USE_CHAR OFF)
option(USE_CHAR "是否使用字符传递,而非hex传递" OFF)
message("use_char value " ${USE_CHAR})
if(USE_CHAR)
add_compile_definitions(USE_CHAR)
set(SRC Algorithm/Algorithm1.cpp)
else()
set(SRC Algorithm/Algorithm2.cpp)
endif()
多态的方案
C++ 也是oop的,所以 java 的那一套 ,在这里也是通用的。
创建三个类用于oop
基类:AAlgor
子类: Algorithm1oop 与 Algorithm2oop
//aalgor.h
#ifndef AALGOR_H
#define AALGOR_H
#include <inttypes.h>
class AAlgor
{
public:
AAlgor();
#ifdef USE_CHAR
typedef uint16_t INT;
#else
typedef int32_t INT;
#endif
virtual int dosth(char * buf,INT len)=0;
};
#endif // AALGOR_H
//algorithm1oop.h
#ifndef ALGORITHM1OOP_H
#define ALGORITHM1OOP_H
#include "aalgor.h"
class algorithm1oop : public AAlgor
{
public:
algorithm1oop();
int dosth(char *buf, INT len) override;
};
#endif // ALGORITHM1OOP_H
//algorithm2oop.h
#ifndef ALGORITHMOOP_H
#define ALGORITHMOOP_H
#include "aalgor.h"
class Algorithm2OOP:AAlgor
{
public:
Algorithm2OOP();
virtual int dosth(char * buf,INT len) override;
};
#endif // ALGORITHMOOP_H
最后调用的位置
#include "aalgor.h"
#include "algorithm1oop.h"
#include "algorithm2oop.h"
int main(int argc, char *argv[])
{
//...
AAlgor * a = new algorithm1oop;
len_length = a->dosth(buf,len);
//...
}
如此即可。 当然 也许 你看到了 这里 采用了直接 赋值给某个真实的对象 algorithm1oop ,根据 设计模式的原则 这里可以采用 工厂模式进行封装。
typedef enum{
ONE = 1,
TWO,
}ALGOR_TYPE;
AAlgor * getAlogor(ALGOR_TYPE type){
if(type ==ONE){
return new algorithm1oop;
}else{
return new Algorithm2OOP;
}
}
int main(int argc, char *argv[])
{
//...
AAlgor * a = getAlogor(ONE);// 这就是工厂
len_length = a->dosth(buf,len);
//...
}
也许你会说,那 每次调用 getAlogor() 都会去实例化一个对象。这个时候就可以使用缓存或其他方式的方式来做了。方法补丁,但是原则相同,设计模式的六大原则。