不要重复发明轮子:C++重用的5重境界
2014-11-11 20:34
746 查看
软件领域有一个著名的描述软件重用的谚语:不要重复发明轮子!
这个道理是很简单,也很明白的,谁都不想重复无用的劳动,但具体实践中我们该如何避免重复发明轮子呢?
各位注意了,谚语中是说“重复发明”,不是说“重复使用”,也就是说我们实践中其实也是避免不了重复使用轮子的,因此实践中我们的对策也可以用一句简单的语句表达:发明能够重复使用的轮子!
下面我们就以C++语言为例,看看究竟如何“发明重复使用的轮子”。
第一重境界:代码重用
最简单的当然就是代码重用了:写一段公共代码,然后放到各个项目里面去编译。
这种方式最直观,但如果你真的在实践中如此应用,那么将面临如下问题(假设3个项目共用):
1)一份代码,三份拷贝
因为采用的是代码编译,所以一份代码在存储时会占用3份的磁盘空间,在运行时会占用3份的内存空间。
当然在现在这个磁盘空间动不动上100G,内存动不动上G的年代,可能大家对这种浪费不以为然,但是回过头去看看历史,如果在你的内存只有32M的年代,这种浪费就不一般了,将会对系统产生很大影响。
2)一次修改,三次编译
假如某一天这份代码修改了,也许是一个小小的BUG,也许是一点小小的优化,但最终的结果都是一样的:所有用到这个公共代码的项目都需要重新编译。
对于普通的小程序来说,编译可能是几秒到几分钟的事情,功能验证也很简单,编译问题看起来还不是很严重;但如果是企业级、电信级的程序,这种编译加验证的工作量是巨大的,而且要部署到已经运行的系统中时,可能需要卸载安装。
第二重境界:简单DLL
稍有经验的人都知道,要解决代码重用的问题其实已经有简单的方法了,那就是动态链接库(Windows平台是DLL,Linux/UNIX是so,下面以DLL为例说明)。
简单的DLL实现如下:将对象、方法的定义放在DLL里面,使用时只需要包含DLL的头文件即可。
这样简单的一个设计,就能够解决代码重用的一个大问题:一份DLL只占一份磁盘空间、一份内存空间。
但为什么我没有说解决了另外一个大问题——编译的问题呢?
乍一看好像是解决了编译的问题,例如我修改函数体内的某个执行语句,或者加一个逻辑判断,只需要编译DLL就可以了呀!
如果只修改函数体那当然是没有问题,但关键是世界没有那么完美和简单,我们可以做很多的修改,例如:
1) 修改类定义:例如增加一个成员变量。
2) 修改函数定义:例如增加一个函数参数,修改某个入参类型;
3) 修改函数体:例如增加一个语句,一个调用等。
以上修改除了第三种修改只需要编译DLL外,其它两种修改都需要重新编译整个项目,也就是说,DLL能够解决空间和编译的部分问题,不能解决所有的编译问题。
革命尚未成功,同志还需努力!!
第三重境界:代理接口DLL
看到这个名字,可能大家有点迷糊:代理?接口?DLL?三个风马牛不相及的东东扯到一块是什么意思呢?
其实只要按照字面意思就能够大概理解:
代理:就是设计模式中的代理模式;
接口:就是Java中的Interface一个概念;
DLL:就是动态链接库了:)
翻译成一句完整的话就是:DLL通过代理模式对外提供接口。
下面我们看看这个“代理接口DLL”是如何实现的。
/*******************************DLL代码*********************************/
//声明部分
class __decspec(dllexport) InterfaceClass{ //声明接口类
class RealizeClass; //引入实现类
RealizeClass* m_pRealizeClass; //指向实现类的指针,咦,怎么会有数据?
public:
void Function1(int param1, char param2 );
void Function2(int param1;
void Function3(bool param1, char param2 );
……………………………………………….
}
//实现部分
InterfaceClass::InterfaceClass(){
m_pRealizeClass = new RealizeClass();
}
InterfaceClass:: Function1(int param1, char param2 ){
return m_pRealizeClass-> Function1(param1, param2 );
}
//其它函数略。
第四重境界:继承接口DLL
看起来“代理接口DLL”已经能够很好的完成任务了,但追求完美的你是否总觉得有的地方不够优美呢?
关键就在于这部分:
InterfaceClass:: Function1(int param1, char param2 ){
return m_pRealizeClass-> Function1(param1, param2 );
}
以上这段代码是代理模式的一种实现方法,但也有它的不足之处:对于RealizeClass的函数,InterfaceClass都要写一个函数,每个函数的写法都是一样的:
return m_pRealizeClass-> FunctionXXX(param1, param2 ……………..);
对于只有几个方法的类来说,这可能没有什么,但是如果RealizeClass类有几十上百个方法,那InterfaceClass就有几十上百个这样类似的函数,看起来是不是很晕呢?
有没有一种方法能够不用写这么多的无聊的函数呢?有,这就是本章要介绍的“继承接口DLL”。我们还是按照第三重境界的方法来解释这个方法:
继承:就是面向对象的继承概念
接口:就是Java中的Interface一个概念;
DLL:就是动态链接库了:)
翻译成一句话就是:DLL通过继承的方法对外提供接口
如果你还记得第三重境界的实现方式,一对比就会发现,这两个方法其实大同小异,关键就是具体的实现方式不一样:一个通过代理模式,一个通过继承方式。那么我们就来看看这个继承方式具体如何实现。
/*******************************DLL代码声明部分开始**********************/
class InterfaceClass{ //声明接口类,无成员数据,只有方法,这里不用dllexport声明,//为什么呢,请自行查阅相关资料?
public:
void Function1(int param1, char param2 ) = 0 //声明为纯虚函数,子类必须改写;
void Function2(int param1 = 0 ;
void Function3(bool param1, char param2 ) = 0 ;
}
class RealizeClass::public InterfaceClass{ //继承接口类,函数必须改写
//成员变量
…………………………………..
//继承的函数,需要重写。
public:
void Function1(int param1, char param2 );
void Function2(int param1 );
void Function3(bool param1, char param2 ) ;
}
//这两个函数是“继承接口DLL”实现关键,后面介绍为什么。
extern InterfaceClass* g_InterfaceClassPtr ; //不要和下面的extern混淆哈:)
extern “C” InterfaceClass* __decspec(dllexport) CreateInterfaceClass();
extern “C” InterfaceClass* __decspec(dllexport) DeleteInterfaceClass();
/******************************* DLL代码声明部分结束**********************/
/*******************************DLL代码定义部分开始**********************/
void RealizeClass::Function1(){
//函数具体实现,do what you want!!!
……………………………..
}
void RealizeClass::Function2(){
//函数具体实现,do what you want!!!
……………………………..
}
void RealizeClass::Function3(){
//函数具体实现,do what you want!!!
……………………………..
}
InterfaceClass* g_InterfaceClassPtr = NULL;
InterfaceClass* CreateInterfaceClass(){
if(g_InterfaceClassPtr == NULL){
g_InterfaceClassPtr = new RealizeClass(); //生成的是具体的类
}
return g_InterfaceClassPtr;
}
InterfaceClass* DeleteInterfaceClass(){
delete g_InterfaceClassPtr;
g_InterfaceClassPtr = NULL;
}
/*******************************DLL代码定义部分结束**********************/
/***************************使用DLL的客户端代码********************/
InterfaceClass* pInterfaceClass = CreateInterfaceClass();
pInterfaceClass->Function1(param1, param2);
………………………………………………………
DeleteInterfaceClass();
/***************************使用DLL的客户端代码********************/
样例代码到这里就结束了,我们来总结一下这种方法的关键实现点:
1)实现类继承接口类,而不是“代理接口DLL”中的接口类包含实现类的指针(UML中的聚合Aggregation的一种实现方式);
2)由于第一条的存在,使得客户端不能直接new某个对象,所以要通过CreateInterfaceClass来创建一个具体的实现类。
3)由于第二条创建了实现类,为了避免内存泄漏,所以要DeleteInterfaceClass。
/*******************************DLL代码*********************************/
/***************************使用DLL的客户端代码********************/
InterfaceClass pInterfaceClass = new InterfaceClass();
pInterfaceClass->Function1(param1, param2);
/***************************使用DLL的客户端代码********************/
各位看完上面的样例,基本上应该都能够明白是如何实现的,但可能会问“为什么还是有一个指针数据类型呢”?不是说没成员数据的吗?
是的,这里关键就在于这个指针,虽然有这个成员数据,但是大家想一想,指针是一个固定大小的类型,而且客户端程序是看不到这个指针的。因此不管对于以下哪个变化,InterfaceClass的结构都不变化,客户端的代码也不受任何影响,不需要重新编译。
1) 具体实现的RealizeClass增加、修改、删除成员数据;
2) RealizeClass有一天改了名称变成了RealizeClassSE;
3) RealizeClass的Function1函数改名了,甚至加了一个缺省参数了。
讲了半天,基本上把“代理接口DLL”是一个什么东东、如何实现讲完了,但是最根本的问题还没有回答——这重境界要解决什么问题?
其实看完如何实现后,聪明的你基本上都能猜出要解决什么问题了,当然就是第二重境界遗留的两个问题了:
1) 修改类定义:例如增加一个成员变量。
2) 修改函数定义:例如增加一个函数参数,修改某个入参类型;
代理接口DLL通过代理模式(其实本质上就是一个指针)解决了上述两个问题,把对外呈现和内部实现分别由不同的类实现,然后通过一个简单的指针将两个类连接起来
第五重境界:消息通信
话说当年明教教主在连乾坤大挪移的时候,实际上并没有所谓的第7重,这第7重只是创始人凭借着自己的聪明才智想出来的,根本无法证实是否正确,幸好张无忌没有练才躲过一劫。
其实我们这里的所谓第5重也是我凭空想出来的:)大家接下来也可以看到,这一重境界其实和C++或者DLL完全没有关系,但这一重境界绝对不是凭空乱想,而且也绝对不是无法证实的,这一重境界是每个IT人都知道的,也许是每个人进入IT界接触的第一个重用方法——消息通信。
aha,是不是觉得很简单、很普通、很傻很天真?!!
但是仔细想想,这确实是最高的重用境界,我们将这种方法与DLL方法来比较一下:
1)消息通信和编译无关,DLL和编译相关;
2)消息通信支持分布式部署,DLL不支持分布式部署;
3)消息通信和具体语言无关,C++的程序可以和Java的程序通信;
4)消息通信可以和操作系统无关,DLL和操作系统绑定的;
看起来消息通信这种方式几乎完美了,那我们还要DLL干嘛呢?前面讲了那么多,那不是浪费口水和时间?
当然不是了,消息通信也存在缺点的:
1)要通过某种方式来收发消息,例如TCP、SCTP、TDM链路;
2)要制定协议来规定收发消息规则和行为规则;
3)要对发送消息和接受消息进行编解码;
总结起来就是消息通信是重量级的,DLL是轻量级的。
废话说了这么多,我们举一个简单的样例,由于消息通信实现比较复杂,这里就不写代码了,简单的描述一下。
例如系统有A、B、C、D
4个模块,都需要访问数据库,对数据库进行操作,由于对数据库的操作基本上建立连接、执行操作、释放连接,这些操作基本上都是一样的。
如果是DLL实现方式,那么就把建立连接、执行操作、释放连接做成DLL,然后由每个模块去调用DLL的对应函数。
如果是消息通信,按照如下机制实现一个消息通信:
1)新建一个模块E,这个模块完成建立连接、执行操作、释放操作的功能;
2)规定A、B、C、D通过TCP/IP与E通信;
3)规定消息格式,例如采用TLV编码,或者二进制编码等
4)规定消息内容,例如:发1标识建立连接、100表示建立连接结果,2表示释放连接,200表示释放连接的结果,等等
例子到这里就结束了,是不是觉得很简单,或者意犹未尽?
是的,一旦采用消息通信方式,你可以发挥的余地就很大了,还是上面那个例子,我们可以做很多的优化,例如:
1)A、B、C、D不再需要关注建立连接和释放连接了,只需要关注数据操作就ok了;
2)E模块可以采用连接池、多线程等技术来提高性能;
3)如果底层数据库修改了,只需要修改E就可以了,A、B、C、D完全不需要任何修改,其实ABCD都不知道底层数据库是Oracle还是DB2.
4)E可以用任何编程语言编写,也可以运行在任何操作系统上;
5)E进程可以实现双机主备等机制来保证可靠性或者性能;
……………………………………………………
总结
好不容易把这个东东讲完了,也算是自己总结归纳了一下,当然,由于才疏学浅,难免出现遗漏和错误,还请大家纠正。
由于篇幅有限,每一篇都写得比较简单,基本上就是把设计思想介绍了一下,实际中应用肯定还有很多问题和细节需要大家去解决,在这里就不一一细讲了(例如第4重境界需要解决多线程的同步问题、第5重境界需要设计好消息格式和消息内容等)。
这个道理是很简单,也很明白的,谁都不想重复无用的劳动,但具体实践中我们该如何避免重复发明轮子呢?
各位注意了,谚语中是说“重复发明”,不是说“重复使用”,也就是说我们实践中其实也是避免不了重复使用轮子的,因此实践中我们的对策也可以用一句简单的语句表达:发明能够重复使用的轮子!
下面我们就以C++语言为例,看看究竟如何“发明重复使用的轮子”。
第一重境界:代码重用
最简单的当然就是代码重用了:写一段公共代码,然后放到各个项目里面去编译。
这种方式最直观,但如果你真的在实践中如此应用,那么将面临如下问题(假设3个项目共用):
1)一份代码,三份拷贝
因为采用的是代码编译,所以一份代码在存储时会占用3份的磁盘空间,在运行时会占用3份的内存空间。
当然在现在这个磁盘空间动不动上100G,内存动不动上G的年代,可能大家对这种浪费不以为然,但是回过头去看看历史,如果在你的内存只有32M的年代,这种浪费就不一般了,将会对系统产生很大影响。
2)一次修改,三次编译
假如某一天这份代码修改了,也许是一个小小的BUG,也许是一点小小的优化,但最终的结果都是一样的:所有用到这个公共代码的项目都需要重新编译。
对于普通的小程序来说,编译可能是几秒到几分钟的事情,功能验证也很简单,编译问题看起来还不是很严重;但如果是企业级、电信级的程序,这种编译加验证的工作量是巨大的,而且要部署到已经运行的系统中时,可能需要卸载安装。
第二重境界:简单DLL
稍有经验的人都知道,要解决代码重用的问题其实已经有简单的方法了,那就是动态链接库(Windows平台是DLL,Linux/UNIX是so,下面以DLL为例说明)。
简单的DLL实现如下:将对象、方法的定义放在DLL里面,使用时只需要包含DLL的头文件即可。
这样简单的一个设计,就能够解决代码重用的一个大问题:一份DLL只占一份磁盘空间、一份内存空间。
但为什么我没有说解决了另外一个大问题——编译的问题呢?
乍一看好像是解决了编译的问题,例如我修改函数体内的某个执行语句,或者加一个逻辑判断,只需要编译DLL就可以了呀!
如果只修改函数体那当然是没有问题,但关键是世界没有那么完美和简单,我们可以做很多的修改,例如:
1) 修改类定义:例如增加一个成员变量。
2) 修改函数定义:例如增加一个函数参数,修改某个入参类型;
3) 修改函数体:例如增加一个语句,一个调用等。
以上修改除了第三种修改只需要编译DLL外,其它两种修改都需要重新编译整个项目,也就是说,DLL能够解决空间和编译的部分问题,不能解决所有的编译问题。
革命尚未成功,同志还需努力!!
第三重境界:代理接口DLL
看到这个名字,可能大家有点迷糊:代理?接口?DLL?三个风马牛不相及的东东扯到一块是什么意思呢?
其实只要按照字面意思就能够大概理解:
代理:就是设计模式中的代理模式;
接口:就是Java中的Interface一个概念;
DLL:就是动态链接库了:)
翻译成一句完整的话就是:DLL通过代理模式对外提供接口。
下面我们看看这个“代理接口DLL”是如何实现的。
/*******************************DLL代码*********************************/
//声明部分
class __decspec(dllexport) InterfaceClass{ //声明接口类
class RealizeClass; //引入实现类
RealizeClass* m_pRealizeClass; //指向实现类的指针,咦,怎么会有数据?
public:
void Function1(int param1, char param2 );
void Function2(int param1;
void Function3(bool param1, char param2 );
……………………………………………….
}
//实现部分
InterfaceClass::InterfaceClass(){
m_pRealizeClass = new RealizeClass();
}
InterfaceClass:: Function1(int param1, char param2 ){
return m_pRealizeClass-> Function1(param1, param2 );
}
//其它函数略。
第四重境界:继承接口DLL
看起来“代理接口DLL”已经能够很好的完成任务了,但追求完美的你是否总觉得有的地方不够优美呢?
关键就在于这部分:
InterfaceClass:: Function1(int param1, char param2 ){
return m_pRealizeClass-> Function1(param1, param2 );
}
以上这段代码是代理模式的一种实现方法,但也有它的不足之处:对于RealizeClass的函数,InterfaceClass都要写一个函数,每个函数的写法都是一样的:
return m_pRealizeClass-> FunctionXXX(param1, param2 ……………..);
对于只有几个方法的类来说,这可能没有什么,但是如果RealizeClass类有几十上百个方法,那InterfaceClass就有几十上百个这样类似的函数,看起来是不是很晕呢?
有没有一种方法能够不用写这么多的无聊的函数呢?有,这就是本章要介绍的“继承接口DLL”。我们还是按照第三重境界的方法来解释这个方法:
继承:就是面向对象的继承概念
接口:就是Java中的Interface一个概念;
DLL:就是动态链接库了:)
翻译成一句话就是:DLL通过继承的方法对外提供接口
如果你还记得第三重境界的实现方式,一对比就会发现,这两个方法其实大同小异,关键就是具体的实现方式不一样:一个通过代理模式,一个通过继承方式。那么我们就来看看这个继承方式具体如何实现。
/*******************************DLL代码声明部分开始**********************/
class InterfaceClass{ //声明接口类,无成员数据,只有方法,这里不用dllexport声明,//为什么呢,请自行查阅相关资料?
public:
void Function1(int param1, char param2 ) = 0 //声明为纯虚函数,子类必须改写;
void Function2(int param1 = 0 ;
void Function3(bool param1, char param2 ) = 0 ;
}
class RealizeClass::public InterfaceClass{ //继承接口类,函数必须改写
//成员变量
…………………………………..
//继承的函数,需要重写。
public:
void Function1(int param1, char param2 );
void Function2(int param1 );
void Function3(bool param1, char param2 ) ;
}
//这两个函数是“继承接口DLL”实现关键,后面介绍为什么。
extern InterfaceClass* g_InterfaceClassPtr ; //不要和下面的extern混淆哈:)
extern “C” InterfaceClass* __decspec(dllexport) CreateInterfaceClass();
extern “C” InterfaceClass* __decspec(dllexport) DeleteInterfaceClass();
/******************************* DLL代码声明部分结束**********************/
/*******************************DLL代码定义部分开始**********************/
void RealizeClass::Function1(){
//函数具体实现,do what you want!!!
……………………………..
}
void RealizeClass::Function2(){
//函数具体实现,do what you want!!!
……………………………..
}
void RealizeClass::Function3(){
//函数具体实现,do what you want!!!
……………………………..
}
InterfaceClass* g_InterfaceClassPtr = NULL;
InterfaceClass* CreateInterfaceClass(){
if(g_InterfaceClassPtr == NULL){
g_InterfaceClassPtr = new RealizeClass(); //生成的是具体的类
}
return g_InterfaceClassPtr;
}
InterfaceClass* DeleteInterfaceClass(){
delete g_InterfaceClassPtr;
g_InterfaceClassPtr = NULL;
}
/*******************************DLL代码定义部分结束**********************/
/***************************使用DLL的客户端代码********************/
InterfaceClass* pInterfaceClass = CreateInterfaceClass();
pInterfaceClass->Function1(param1, param2);
………………………………………………………
DeleteInterfaceClass();
/***************************使用DLL的客户端代码********************/
样例代码到这里就结束了,我们来总结一下这种方法的关键实现点:
1)实现类继承接口类,而不是“代理接口DLL”中的接口类包含实现类的指针(UML中的聚合Aggregation的一种实现方式);
2)由于第一条的存在,使得客户端不能直接new某个对象,所以要通过CreateInterfaceClass来创建一个具体的实现类。
3)由于第二条创建了实现类,为了避免内存泄漏,所以要DeleteInterfaceClass。
/*******************************DLL代码*********************************/
/***************************使用DLL的客户端代码********************/
InterfaceClass pInterfaceClass = new InterfaceClass();
pInterfaceClass->Function1(param1, param2);
/***************************使用DLL的客户端代码********************/
各位看完上面的样例,基本上应该都能够明白是如何实现的,但可能会问“为什么还是有一个指针数据类型呢”?不是说没成员数据的吗?
是的,这里关键就在于这个指针,虽然有这个成员数据,但是大家想一想,指针是一个固定大小的类型,而且客户端程序是看不到这个指针的。因此不管对于以下哪个变化,InterfaceClass的结构都不变化,客户端的代码也不受任何影响,不需要重新编译。
1) 具体实现的RealizeClass增加、修改、删除成员数据;
2) RealizeClass有一天改了名称变成了RealizeClassSE;
3) RealizeClass的Function1函数改名了,甚至加了一个缺省参数了。
讲了半天,基本上把“代理接口DLL”是一个什么东东、如何实现讲完了,但是最根本的问题还没有回答——这重境界要解决什么问题?
其实看完如何实现后,聪明的你基本上都能猜出要解决什么问题了,当然就是第二重境界遗留的两个问题了:
1) 修改类定义:例如增加一个成员变量。
2) 修改函数定义:例如增加一个函数参数,修改某个入参类型;
代理接口DLL通过代理模式(其实本质上就是一个指针)解决了上述两个问题,把对外呈现和内部实现分别由不同的类实现,然后通过一个简单的指针将两个类连接起来
第五重境界:消息通信
话说当年明教教主在连乾坤大挪移的时候,实际上并没有所谓的第7重,这第7重只是创始人凭借着自己的聪明才智想出来的,根本无法证实是否正确,幸好张无忌没有练才躲过一劫。
其实我们这里的所谓第5重也是我凭空想出来的:)大家接下来也可以看到,这一重境界其实和C++或者DLL完全没有关系,但这一重境界绝对不是凭空乱想,而且也绝对不是无法证实的,这一重境界是每个IT人都知道的,也许是每个人进入IT界接触的第一个重用方法——消息通信。
aha,是不是觉得很简单、很普通、很傻很天真?!!
但是仔细想想,这确实是最高的重用境界,我们将这种方法与DLL方法来比较一下:
1)消息通信和编译无关,DLL和编译相关;
2)消息通信支持分布式部署,DLL不支持分布式部署;
3)消息通信和具体语言无关,C++的程序可以和Java的程序通信;
4)消息通信可以和操作系统无关,DLL和操作系统绑定的;
看起来消息通信这种方式几乎完美了,那我们还要DLL干嘛呢?前面讲了那么多,那不是浪费口水和时间?
当然不是了,消息通信也存在缺点的:
1)要通过某种方式来收发消息,例如TCP、SCTP、TDM链路;
2)要制定协议来规定收发消息规则和行为规则;
3)要对发送消息和接受消息进行编解码;
总结起来就是消息通信是重量级的,DLL是轻量级的。
废话说了这么多,我们举一个简单的样例,由于消息通信实现比较复杂,这里就不写代码了,简单的描述一下。
例如系统有A、B、C、D
4个模块,都需要访问数据库,对数据库进行操作,由于对数据库的操作基本上建立连接、执行操作、释放连接,这些操作基本上都是一样的。
如果是DLL实现方式,那么就把建立连接、执行操作、释放连接做成DLL,然后由每个模块去调用DLL的对应函数。
如果是消息通信,按照如下机制实现一个消息通信:
1)新建一个模块E,这个模块完成建立连接、执行操作、释放操作的功能;
2)规定A、B、C、D通过TCP/IP与E通信;
3)规定消息格式,例如采用TLV编码,或者二进制编码等
4)规定消息内容,例如:发1标识建立连接、100表示建立连接结果,2表示释放连接,200表示释放连接的结果,等等
例子到这里就结束了,是不是觉得很简单,或者意犹未尽?
是的,一旦采用消息通信方式,你可以发挥的余地就很大了,还是上面那个例子,我们可以做很多的优化,例如:
1)A、B、C、D不再需要关注建立连接和释放连接了,只需要关注数据操作就ok了;
2)E模块可以采用连接池、多线程等技术来提高性能;
3)如果底层数据库修改了,只需要修改E就可以了,A、B、C、D完全不需要任何修改,其实ABCD都不知道底层数据库是Oracle还是DB2.
4)E可以用任何编程语言编写,也可以运行在任何操作系统上;
5)E进程可以实现双机主备等机制来保证可靠性或者性能;
……………………………………………………
总结
好不容易把这个东东讲完了,也算是自己总结归纳了一下,当然,由于才疏学浅,难免出现遗漏和错误,还请大家纠正。
由于篇幅有限,每一篇都写得比较简单,基本上就是把设计思想介绍了一下,实际中应用肯定还有很多问题和细节需要大家去解决,在这里就不一一细讲了(例如第4重境界需要解决多线程的同步问题、第5重境界需要设计好消息格式和消息内容等)。
相关文章推荐
- 不要重复发明轮子:C++重用的5重境界(5)——消息通信(完结篇)
- 不要重复发明轮子:C++重用的5重境界(1)——代码重用
- 不要重复发明轮子:C++重用的5重境界(2)——简单DLL
- 不要重复发明轮子:C++重用的5重境界(3)——代理接口DLL
- 不要重复发明轮子:C++重用的5重境界(4)——继承接口DLL
- 几个常用的JAVA类(坚持“不要重复发明轮子”的原则,留着重用)
- 刚才看别人总结的,JDBC各种数据库连接,汗颜啊。老是抄袭别人的。哎。不要重复发明轮子。。
- 增长黑盒:零代码基础做智能电商网站,不要重复发明轮子
- Please stop re-inventing the wheel (请不要重复发明轮子)
- 请不要重复发明轮子
- 不要重复发明轮子-C++STL
- C++编程 - 真的不要重复造轮子吗
- GitHub Android 最火开源项目Top20 GitHub 上的开源项目不胜枚举,越来越多的开源项目正在迁移到GitHub平台上。基于不要重复造轮子的原则,了解当下比较流行的Android与iOS开源项目很是必要。利用这些项目,有时能够让你达到事半功倍的效果。
- 关于不要重复造轮子的二三事
- Asp.net WebAPI Request参数验证-请不要重复造轮子
- 不相信“不要重复制造轮子”的论述!
- 重复发明轮子 自己实现哈希表。
- 关于不要重复造轮子的二三事
- 我不是在重复发明轮子
- 重复发明轮子又何妨?