代码解耦

烂的代码,都有各自烂的地方,不过基本都有一个共同的特点:耦合重,各个模块各个类各个功能点

之间关系牵扯不清,经常你调用我调用你,或者全局变量漫天飞;

对于怎么理清这些模块或者类,《代码大全》讲了很多,比如要形成金字塔型的调用层级关系,如果

不能保证,也一定要保证单向的调用关系,绝对不能形成环状的调用关系;

即:A->B->C

而不能是 A->B->C->A,尤其要避免 A<->B

如果不能避免这种循环调用,A和B将无法区分开来,A和B不可避免的扯到了一起,不能单独开发,不

能单独编译,无论改动A或者B中的一个,都会影响到另外一个;这样,随着功能一多,模块一多,最后全

扯到了一起;造成了你中有我,我中有你的感概恶心的耦合!!

 

如果能保证这种单调单向的调用关系,那代码将形成一定的上下有别的层级,其中任何一层只能调用

下层,绝对不能调用上层,最好是完全不用知道有上层!!即每层都把自己当作是最上层;

这样有几个好处:

1,模块解耦了,如果每层接口设计的好,那每层内部的改动对其他层或者其他模块完全是透明的,

这样有利于分工;

2,模块解耦之后,得到另外的一个好处是:能极大的增强代码模块的复用度,很多模块也许用着用

着就发现提取出来,可以供很多的上层模块调用;

 

对于集群中的svr节点来说,一般可以划分成一些固定的层:比如:核心数据模块,驱动模块,业务

模块,RPC模块,基础框架模块等等;

 

上面这些说的都是理论的玩意,而且很多人也都知道,但其实真正写代码的时候,往往发现事情没这

么简单,很多情况下,会发现A->B,B确实要反过来调用B;比如我经常发现有人这样写代码:

状态机FSM模块需要通过RPC模块拉取数据,得到数据后,然后才能接着往下继续处理;一般的 RPC

模块的接口是 rpc::get_data(req, fsm_id),rpc得到数据后,根据fsm_id从全局FSM管理器 g_fsm_mgr 

取出FSM,然后调用 FSM::on_data_back(resp)...

 

看到没有,rpc 和 fsm 完整的融合在了一起,而且必须要通过全局变量融合(这里就会发生非常多的

恶心的地方,比如svr里面有两类都可能调用此rpc状态机...),明显这里是有非常大的问题,rpc 明明和

业务是没半点关系的,rpc应该做的就是远程操作,至于操作的结果,rpc是不应该管的,他只需要简单的

把结果返回给调用者(即上层)即可;

按上面这种做法,rpc 是无法重用的,如果另外写一个svr,而这个svr用的同一套rpc,那他就只能

把这套rpc代码拷贝过来,然后再改几个地方...重复?恶心?低效?bug滋生?

 

其实对于这个问题,有极其简单极其有效却完全被人忽视的办法:回调!!

rpc提供的接口应该是这样的:

typedef (*on_data_back)(resp,...)

rpc:get_data(req, on_data_back cb, void* params)

rpc只需要在内部建立这个req的标志(比如序列号)和 callback以及params的映射即可,当结果返回

时,只需要通过resp的标志找到回调信息,然后 cb(resp, params) 即可,至于cb到底是干什么的,rpc无

权知道,也不需要知道!!

 

对于所有的下层需要调用上层的情况,回调都应该是最好的选择,也是必须的选择;

C语言的精华是指针,指针的精华是函数指针,C的生命,C的灵动,C的多变来源于函数指针;君不见

稍微大点的纯C项目,函数指针都是极其常见的;

 

说起来其实很简单,确实够简单,却极致够用;那为什么很多项目中还是组织乱成一团麻呢??

 

对于C++,回调没C这么简单,以前一直没有找到好用的自然的类函数指针的玩意,后来发现了boost的

function和bind这两个玩意,能完全实现类的回调,而且能随心所欲的携带参数,用多了感觉比C的函数指

针还好用,特别是携带参数这块;C完全依靠void*这个指针携带,而boost的回调不限!

你可能感兴趣的:(C/C++/JAVA)