架构启蒙篇

240 阅读3分钟

再平常开发过程中,随着平台的增多,以及逻辑的增加,项目会变得难以维护。像下面这样的,例子是上篇字符处理的。不过能够讲明意义即可。

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

子类: Algorithm1oopAlgorithm2oop

//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() 都会去实例化一个对象。这个时候就可以使用缓存或其他方式的方式来做了。方法补丁,但是原则相同,设计模式的六大原则。