最近做的几个项目都涉及到了比较复杂的if-else逻辑,刚开始因为是自己码的,所以觉得还行,赶脚自己能hold住,但后面因为在多个项目上不停切换,导致撸主的大脑在切换上下文时,总要重新回忆下复杂的代码逻辑,搞得撸主欲生欲死。
于是今天的主角出场了,撸主死磕了下《代码大全》的表驱动章节后,把之前复杂的代码逻辑,用表驱动法重新调整了下,代码的可读性立马就飙升了几个Level!! Oh yeah妈妈再也不用担心上下文切换了~
废话不多说,上代码。
Lua实现
先来看看原来的肮脏代码:
function do_plug_set_opt(res, plug_opt, plug_code, plug, plug_param)
local format_res = res
local code = nil
if plug_code and plug_opt == "install" then
local install_node = check_plug_code_flag(plug_code)
local plug_install_location, specify_res = specify_install_storage_node(install_node, res)
if specify_res["code"] then
require "MZLog".log(3, res)
log_res(plug_param.plug_opt, res)
return specify_res
end
res, code = install_plugin(plug_code, plug_param.plug_md5, plug_param.plug_url, plug_install_location)
elseif plug_code and plug["plug_name"] then
local plug_exec_fname = get_plug_exec_file_name(plug["plug_code"])
init_plug_install_local_path(plug_location)
if plug_opt == "remove" then
res = remove_plugin(plug_code, plug_exec_fname)
elseif plug_opt == "start"then
res = start_plugin(plug_code, plug_exec_fname)
elseif plug_opt == "stop" then
res = stop_plugin(plug_code, plug_exec_fname)
elseif plug_opt == "cmd_ctrl" then
res = control_plugin(plug_param.cmd_argc_list, plug_exec_fname)
elseif plug_opt == "upgrade" then
res, code = upgrade_plugin(plug_code, plug_param.plug_md5, plug_param.plug_url)
end
end
if code == nil then
format_res = print_res(format_res, res, PLUG_OPT_CODE.NORMAL)
else
format_res = print_res(format_res, res, code)
end
return format_res
end
是不是觉得被各种if-else绕晕了?
是不是一看到这一大坨代码,瞬间赶脚不会再爱了?
别急,再看看优化之后的代码:
plug_set_opt_action = {
["install"] = plug_opt_util.install_plugin,
["async_install"] = plug_opt_util.async_install_plugin,
["remove"] = plug_opt_util.remove_plugin,
["async_remove"] = plug_opt_util.async_remove_plugin,
["start"] = plug_opt_util.start_plugin,
["stop"] = plug_opt_util.stop_plugin,
["cmd_ctrl"] = plug_opt_util.control_plugin,
["upgrade"] = plug_opt_util.upgrade_plugin,
["async_upgrade"] = plug_opt_util.async_upgrade_plugin
}
function do_plug_set_opt(res, plug_opt, plug_code, plug, plug_param)
local format_res, code = res, nil
if plug["plug_name"] then
plug_param.plug_exec_fname = plug_info_util.get_plug_exec_file_name(plug["plug_code"])
local plug_location = plug_info_util.get_plug_location()
init_plug_install_local_path(plug_location)
code, res = plug_set_opt_action[plug_opt](plug_param)
end
return print_res(format_res, res, code)
end
不得不说,代码可读性高太多了,有木有~~
lua非主流?好吧,辣偶用Java实现个...
Java实现
肮脏的代码就不贴了,直接上优化以后的代码哈~
public static Map<Mode_Action, String> mode_map;
private static void init_mode_map() {
mode_map = new HashMap<Mode_Action, String>();
mode_map.put(Mode_Action.HOME_IN_MODE, "回家模式");
mode_map.put(Mode_Action.HOME_OUT_MODE, "离家模式");
mode_map.put(Mode_Action.MOVIE_MODE, "清晨模式");
mode_map.put(Mode_Action.MOVIE_MODE, "沐浴模式");
mode_map.put(Mode_Action.MOVIE_MODE, "观影模式");
}
static MZGrammar identfy_mode_device(String speech) {
Mode_Action mode_action = null;
init_mode_map();
for (Map.Entry<Mode_Action, String> entry: mode_map.entrySet())
{
if (speech.contains( entry.getValue() )) {
mode_action = entry.getKey();
break;
}
}
MZGrammar rtn_grammar = null;
if ( mode_action == null ) {
rtn_grammar = new MZGrammar(mode_action);
}
return rtn_grammar;
}
下面这一份代码,赶脚还有优化空间,但又不知从何下手,还请各位帮忙Review,提点意见哈~
public static Map<IR_Action, ArrayList<String> > ir_map;
private static void add_key_word(IR_Action ir_action, String ...args) {
ArrayList<String> ir_str_ar = new ArrayList<String>();
for (int i = 0; i < args.length; ++i) {
ir_str_ar.add(args[i]);
}
ir_map.put(ir_action, ir_str_ar);
}
private static void init_ir_map() {
ir_map = new HashMap<IR_Action, ArrayList<String>>();
add_key_word(IR_Action.TV_UP_VOL, "加", "音量");
add_key_word(IR_Action.TV_DOWN_VOL, "减", "音量");
add_key_word(IR_Action.TV_UP_CHANNEL, "加", "频道");
add_key_word(IR_Action.TV_DOWN_CHANNEL, "减", "频道");
add_key_word(IR_Action.TV_SWITCH_OFF, "关", "电视");
add_key_word(IR_Action.TV_SWITCH_ON, "开", "电视");
add_key_word(IR_Action.AIR_SWITCH_OFF, "关", "空调");
add_key_word(IR_Action.AIR_SWITCH_ON, "开", "空调");
add_key_word(IR_Action.AIR_TEMPERATURE_UP, "升温", "空调");
add_key_word(IR_Action.AIR_TEMPERATURE_DOWN, "降温", "空调");
}
static MZGrammar identfy_ir_device(String speech) {
IR_Action ir_action = null;
init_ir_map();
for (Map.Entry<IR_Action, ArrayList<String> > entry: ir_map.entrySet()) {
ArrayList<String> keywords = entry.getValue();
boolean is_keyword_contains = true;
for ( String keyword : keywords ) {
if ( !speech.contains(keyword) ) {
is_keyword_contains = false;
break;
}
}
if (is_keyword_contains) {
ir_action = entry.getKey();
break;
}
}
int type = HomeDevice.FLAG_TYPE_IRC;
return new MZGrammar(ir_action, type);
}
C实现
神马?C没有基础的键值对结构,肿么实现?
没事,没有结构,创造结构也要上
/*
* UI_EVENT
*/
typedef enum
{
UI_SWITCH_UI_MODE = 0,
UI_DEMO_FUNC = 1,
UI_RECV_LPRESS_KEY = 2,
UI_RECV_SPRESS_KEY = 3,
UI_RECV_KEY_UP = 4,
UI_RECV_KEY_DOWN = 5,
UI_GET_SWITCH_UI_MODE = 6,
UI_GET_BLE_STATE = 7,
UI_GET_SYS_STATE = 8,
UI_CLOSE_BLE = 9,
UI_OPEN_BLE = 10,
UI_ALARM_REMIND = 11,
UI_SEDENTARY_REMIND = 12,
UI_RTC_SYNC_STEPS = 13,
UI_LOW_BATTERY_WARNING = 14,
} ui_task_id_t;
static const MODULE_EVENT ui_event_table[] =
{
{UI_SWITCH_UI_MODE, switch_ui_mode},
{UI_DEMO_FUNC, demo_func},
{UI_RECV_LPRESS_KEY, recv_lpress_key},
{UI_RECV_SPRESS_KEY, recv_spress_key},
{UI_RECV_KEY_UP, recv_key_up},
{UI_RECV_KEY_DOWN, recv_key_down},
{UI_GET_SWITCH_UI_MODE, get_ui_mode},
{UI_GET_BLE_STATE, get_ble_state},
{UI_GET_SYS_STATE, get_sys_state},
{UI_CLOSE_BLE, ui_close_ble},
{UI_OPEN_BLE, ui_open_ble},
{UI_ALARM_REMIND, ui_alarm_remind},
{UI_SEDENTARY_REMIND, ui_sedentary_remind},
{UI_RTC_SYNC_STEPS, ui_rtc_sync_steps},
{UI_LOW_BATTERY_WARNING, ui_low_battery_warning},
};
static const int UI_EVENT_SIZE = sizeof(ui_event_table) / sizeof(MODULE_EVENT);
/*
* EventType
*/
typedef struct __EventType
{
uint8_t task_id;
const MODULE_EVENT *module_event_table;
} EventType;
static const EventType event_type_table[] =
{
{TASK_ID_WATCH_HANDLER, watch_event_table},
{TASK_ID_BT, bt_event_table},
{TASK_ID_SENSOR, sensor_event_table},
{TASK_ID_ADC, adc_event_table},
{TASK_ID_KEY, key_event_table},
{TASK_ID_UI, ui_event_table},
};
void snd_msg2ui_task(task_message *msg)
{
if (pdPASS != xQueueSendToBack(ui_msg_queue, (void *) &msg, 0)) {
vPortFree(msg);
}
}
/*
* MsgType
*/
typedef struct __MsgType
{
uint8_t task_id;
void (*eventFunc)(task_message *);
} MsgType;
static const MsgType msg_type_table[] =
{
{TASK_ID_WATCH_HANDLER, snd_msg2watch_task},
{TASK_ID_BT, snd_msg2bt_task},
{TASK_ID_SENSOR, NULL},
{TASK_ID_ADC, NULL},
{TASK_ID_KEY, NULL},
{TASK_ID_UI, snd_msg2ui_task},
};
static const uint8_t TB_MSG_TYPE_SIZE = sizeof(msg_type_table) / sizeof(MsgType);
void dispatch_msg(task_message *msg)
{
void (*dispatch_msg_func)(task_message *);
for(int i = 0; i < TB_MSG_TYPE_SIZE; ++i) {
if (event_type_table[i].task_id == msg->task_id_dst) {
dispatch_msg_func = msg_type_table[msg->task_id_dst].eventFunc;
break;
}
}
dispatch_msg_func(msg);
}
void unit_test_switch_ui_mode(void)
{
task_message *snd_msg = construct_task_msg(false, TASK_ID_UI, TASK_ID_SENSOR, UI_SWITCH_UI_MODE);
dispatch_msg(snd_msg);
}
当你手上有一把锤子的时候,看所有的东西都是钉子;
当你手上有一个钉子的时候,看所有的东西都是锤子;
当你刚掌握了表驱动的时候,看所有的代码都想把他改成表驱动形式。
不得不说,撸主现在就是这种状态,大家别笑话哈~~
OK,厕所文写完啦,更多详情,请各位去拜读《代码大全》第十八章哈~~
注:重点关注查表的三种方式:直接访问,索引访问,阶梯访问~~