某 Bililive 沿用了 Chromium 负责在 UI 层不同模块通讯的 command/handler 的机制,但是因为 Chromium 对 command 机制使用得很节制,因此相关的代码量不多,其处理函数一直是一个大大的 switch...case
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void ExecuteCommandWithParams(Bililive* receiver, int command, const CommandParamsDetails& params) { switch (command) { case IDC_ALPHA: break;
case IDC_BRAVO: break;
case IDC_CHARLIE: break; ... } }
|
然而到了 Bililive 这里,因为开发人员水平限制,没有最好模块内外的通讯规划,导致存在大量的 command 通信,而 handler 代码依然是直接原封不动写在 switch
里。于是 ExecuteCommandWithParams()
就包含了上千行的实现,而且由于都在一个函数内,没有语法上的 scope 和清晰的语义划分,维护起来相当痛苦。
一个有效的解决方案是采用类似 MFC Message-Mapping 的方式,将不同的 message handler 分离到单独的函数里。至于参数,因为所有 command 的参数都是一致的,直接简化了处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include "base/logging.h"
#define BEGIN_BILILIVE_COMMAND_MAP(cmd_receiver, cmd_id, cmd_params) \ { \ auto __receiver = cmd_receiver; \ auto __id = cmd_id; \ const auto& __params = cmd_params; \ switch (cmd_id) { \
#define ON_BILILIVE_COMMAND(cmd_id, fn) \ case cmd_id: { \ fn(__receiver, __params); \ } \ break; \
#define ON_BILILIVE_COMMAND_UNHANDLED_ERROR() \ default: { \ NOTREACHED() << "Unhandled command " << __id; \ } \ break; \
#define END_BILILIVE_COMMAND_MAP() \ } \ }
|
于是处理相关的代码就变成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| void OnAlpha(Bililive* receiver, const CommandParamsDetails& params) {}
void OnBravo(Bililive* receiver, const CommandParamsDetails& params) {}
void OnCharlie(Bililive* receiver, const CommandParamsDetails& params) {}
void ExecuteCommandWithParams(Bililive* receiver, int command, const CommandParamsDetails& params) { BEGIN_BILILIVE_COMMAND_MAP(receiver, command, params) ON_BILILIVE_COMMAND(IDC_ALPHA, OnAlpha) ON_BILILIVE_COMMAND(IDC_BRAVO, OnBravo) ON_BILILIVE_COMMAND(IDC_CHARLIE, OnCharlie) ON_BILILIVE_COMMAND_UNHANDLED_ERROR() END_BILILIVE_COMMAND_MAP() }
|