分解大量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 ...
随机推荐
- mysql 通过cmd 在命令行创建数据库
一.连接MYSQL 格式: mysql -h主机地址 -u用户名 -p用户密码 1. 连接到本机上的MYSQL. 首先打开DOS窗口,然后进入目录mysql\bin,再键入命令mysql -u roo ...
- 2017-2018-1 JAVA实验站 第六、七周作业
2017-2018-1 JAVA实验站 第六.七周作业 详情请见团队博客
- hdu 4435 第37届ACM/ICPC天津现场赛E题
转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove 题目:给出N个城市,从1开始需要遍历所有点,选择一 ...
- hdu 3864 素数分解
题意:求n是否只有4个因子,如果是就输出除1外的所有因子. 模板题,就不排版了 #include<cstdio> #include<iostream> #include< ...
- 使用 Nokia Imaging SDK 开发有滤镜功能的 Windows Phone 8 应用
说到滤镜应用,相信很多数开发者都对照片特效的经验都十分有限,通常都是去找一些三方的类库进行学习或移植,今天在这里给大家介绍下 Nokia 的 Imaging SDK, 相信大家对Nokia的自家图像软 ...
- python循环与判断
学习一门新的语言最重要的就是练习. 一.脚本需求: 编写登陆接口 输入用户名密码 认证成功后显示欢迎信息 输错三次后锁定 二.脚本流程图: 写代码之前画个流程图总是好的,可以让你理清思路,避免写着写着 ...
- JDK环境变量的配置说明
一.Linux下的JDK安装及配置: 1. 使用命令uname –a查看系统的版本确定系统的位数,然后去JDK官网下载相应位数的安装程序,进行安装. 2. 使用rz命令将下载的JDK上传至Linux ...
- mysql数据库cup飙升处理思路
1.先top查看是那一个进程,哪个端口占用CPU多. 2.show processeslist查看是否由于大量并发,锁引起的负载问题. 3.否则,查看慢查询,找出执行时间长的sql:explain分析 ...
- Python的静态方法和类成员方法
http://www.cnblogs.com/2gua/archive/2012/09/03/2668125.html Python的静态方法和类成员方法都可以被类或实例访问,两者概念不容易理清,但还 ...
- 在Hadoop中重写FileInputFormat类以处理二进制格式存储的整数
近期開始使用MapReduce,发现网上大部分样例都是对文本数据进行处理的,也就是说在读取输入数据时直接使用默认的TextInputFormat进行处理就可以.对于文本数据处理,这个类还是能满足一部分 ...