分解大量switch-case分支的两种方法
项目经过长期多人的维护,所谓人多手杂,出现不少过多过长的switch-case分支,或者多重switch-case嵌套。每每添加功能,我都会紧皱眉头,然后带着罪恶感向已经成百上千行的函数里再添上一个case分支,然后纠结地收工了事。
于是乎,在我的内心深处,switch-case俨然成了代码坏味道的代名词,写代码时总小心翼翼地避开它们,可往往又事与愿违。
事实上,switch-case语句并不是代码坏味道的根源,坏味道来自糟糕的结构设计,过多的switch-case分支,多重switch-case嵌套,这些都将导致代码可读性下降,维护困难易出错。
对于分支有多又长的switch-case分支,可是使用表驱动方法或者在特定情况下可以采用表驱动方法结合事件机制进行分解。
对于表驱动方法,可用数组或std::map将case判定常量映射到相应的处理函数。核心代码实现类似如下:
// 分支判定枚举
enum CASE
{
_CASE_A,
...
_CASE_X,
_CASE_AMOUNT // 分支总数
};
// 处理函数类型
typedef void (*HANDLER)(void);
// 映射
HANDLE handlers[_CASE_AMOUNT] =
{
&HandlerA,
...
&HandlerX
};
bool handler(UINT uEvent)
{
if (uEvent < _CASE_AMOUNT)
{
(*handlers[uEvent])();
return true;
}
return false;
}
优点:条理清晰易于阅读。
缺点:要增添很多处理函数,且不便于跟踪调试。
对于在一个公共对象里使用switch-case分支集中处理大量与该对象无紧密逻辑关联事件的情况。可通过在公共基类中使用事件处理机制,实现事件与监听器(与事件相关的对象,如窗口)的映射,事件的分配处理。相关代码如下:
class CBase
{
...
public:
// 添加事件监听器
static bool AddEventListener(UINT uEvent, CBase* pListener);
// 移除事件监听器
static bool RemoveEventListener(UINT uEvent, CBase* pListener);
// 将事件给相应监听器处理
static void DispatchEvent(UINT uEvent);
// 处理事件,该虚函数由监听器实现
virtual void OnEvent(UINT uEvent, int nParam) {}
...
private:
// 事件与监听器的映射,多个监听器可监听同一个事件
static std::multimap<UINT, CBase*> m_mmapEventListener;
...
}
对于事件处理机制,在Java等语言中有大量使用,这里就不贴一大段代码了。
优点:逻辑性强,耦合度低,符合开放封闭原则。
缺点:事件分配时效率较switch-case分支低。
分解大量switch-case分支的两种方法的更多相关文章
- CircleCi 不更新某个分支的两种方法
概述 今天我发现我的所有项目的 CircleCi 部署全部都会更新 gh-pages 分支.找了好久,终于找到了不更新的方法.于是我总结了一下,记录下来,供以后开发时参考,相信对其他人也有用. onl ...
- 【2017-2-23】C#switch case分支语句,for循环语句
switch case分支语句 switch(一个变量值) { case 值:要执行的代码段;break; case 值:要执行的代码段;break; … default:代码段;break;(def ...
- CASE WHEN的两种格式
CASE WHEN的两种格式 1.简单Case函数 CASE sex WHEN '1' THEN '男' WHEN '2' THEN '女' ELSE '其他' END 2.Case搜索函数 CASE ...
- 在sql中case子句的两种形式
case子句,在select后面可以进行逻辑判断. 两种形式:判断相等.判断不等 一.判断相等的语法: case 列名 when ... then ... when ... then ... el ...
- windows下获取IP地址的两种方法
windows下获取IP地址的两种方法: 一种可以获取IPv4和IPv6,但是需要WSAStartup: 一种只能取到IPv4,但是不需要WSAStartup: 如下: 方法一:(可以获取IPv4和I ...
- android 之 启动画面的两种方法
现在,当我们打开任意的一个app时,其中的大部分都会显示一个启动界面,展示本公司的logo和当前的版本,有的则直接把广告放到了上面.启动画面的可以分为两种设置方式:一种是两个Activity实现,和一 ...
- Linux 下操作GPIO(两种方法,驱动和mmap)(转载)
目前我所知道的在Linux下操作GPIO有两种方法: 1.编写驱动,这当然要熟悉Linux下驱动的编写方法和技巧,在驱动里可以使用ioremap函数获得GPIO物理基地址指针,然后使用这个指针根据io ...
- Linux 下操作gpio(两种方法,驱动和mmap)
目前我所知道的在linux下操作GPIO有两种方法: 1. 编写驱动,这当然要熟悉linux下驱动的编写方法和技巧,在驱动里可以使用ioremap函数获得GPIO物理基地址指针,然后使用这个指针根据 ...
- QT中获取选中的radioButton的两种方法(动态取得控件的objectName之后,对名字进行比较)
QT中获取选中的radioButton的两种方法 QT中要获取radioButton组中被选中的那个按钮,可以采用两种如下两种办法进行: 方法一:采用对象名称进行获取 代码: 1 QRadioBu ...
随机推荐
- 决策树算法(Bagging与随机森林)
Bagging算法: 将训练数据集进行N次Bootstrap采样得到N个训练数据子集,对每个子集使用相同的算法分别建立决策树,最终的分类(或回归)结果是N个决策树的结果的多数投票(或平均). 其中,B ...
- LOJ P1155 双栈排序 二分图染色 图论
https://www.luogu.org/problem/show?pid=P1155 题解: https://www.byvoid.com/zhs/blog/noip2008-twostack 开 ...
- 2016 UESTC Training for Data Structures 题解
题解在下已经写过一次了,所以就不再写了,下面只有代码 题解下载(1):http://pan.baidu.com/s/1hsAUjMs 题解下载(2):http://pan.baidu.com/s/1m ...
- 该死的Ubuntu 16.04不自动续租DHCP的IP
BUG,这是一个BUG,参考:https://bugs.launchpad.net/ubuntu/+source/isc-dhcp/+bug/1551351,如果不自动续租IP,导致的问题就是网线灯还 ...
- [Dynamic Language] Python3.7 源码安装 ModuleNotFoundError: No module named '_ctypes' 解决记录
Python3.7 源码安装 ModuleNotFoundError: No module named '_ctypes' 解决记录 源码安装时报错 File "/home/abeenser ...
- Tomcat篇
安装tomcat 先从tomcat官网找到最新的版本下载地址,我找的是Core下的安装包,下载到本地: wget http://mirror.bit.edu.cn/apache/tomcat/tomc ...
- Polly简介 — 1. 故障处理策略
Polly 是 .Net 下的一套瞬时故障处理及恢复的函式库,可让开发者以fluent及线程安全的方式来应用诸如Retry.Circuit Breaker.Timeout.Bulkhead Isola ...
- 利用.bat文件快速设置IE代理与清除IE代理
http://www.duoluodeyu.com/2009/17.html 设置IE代理.bat文件原文:将下面红色文字复制保存为.bat文件即可. 复制后将蓝色字体部分改成你要设置的代理服务器地址 ...
- USB PIC Programmer (Brenner8)
http://uzzors2k.4hv.org/index.php?page=usbpicprog My Tait Serial programmer works alright, but not e ...
- both, either, neither的用法
http://www.yywords.com/Article/200806/347.html 1. 这三个词都用来谈论两者:both 意为“(两者)都”,either意为“(两者中)任意一个”,ne ...