關於代碼解耦

爛的代碼,都有各自爛的地方,不過基本都有一個共同的特點:耦合重,各個模塊各個類各個功能點
之間關係牽扯不清,經常你調用我調用你,或者全局變量漫天飛;
對於怎麼理清這些模塊或者類,《代碼大全》講了很多,比如要形成金字塔型的調用層級關係,如果
不能保證,也一定要保證單向的調用關係,絕對不能形成環狀的調用關係;
即: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的回調不限!!

轉自 http://blog.chinaunix.net/uid-26443921-id-3361188.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章