关于代码解耦

烂的代码,都有各自烂的地方,不过基本都有一个共同的特点:耦合重,各个模块各个类各个功能点
之间关系牵扯不清,经常你调用我调用你,或者全局变量漫天飞;
对于怎么理清这些模块或者类,《代码大全》讲了很多,比如要形成金字塔型的调用层级关系,如果
不能保证,也一定要保证单向的调用关系,绝对不能形成环状的调用关系;
即: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的回调不限!!



https://blog.csdn.net/qwert9887/article/details/51741227

猜你喜欢

转载自blog.csdn.net/wishfly/article/details/80484539