分解大量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 事物的隔离级别(简要)
事务的隔离级别 为什么 引入了 事务隔离级别?? 在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别. 更新丢失两个事务都同时更新一行数据,一个事务对数据的更新把另一个事务对数据的 ...
- django 动态url 可变
首先在urls里面改,name=让一个映射敷个名字. 然后到books——list页面让编辑按钮改成这种可变的映射模式.
- [BZOJ5125]小Q的书架(决策单调性+分治DP+树状数组)
显然有决策单调性,但由于逆序对不容易计算,考虑分治DP. solve(k,x,y,l,r)表示当前需要选k段,待更新的位置为[l,r],这些位置的可能决策点区间为[x,y].暴力计算出(l+r)/2的 ...
- Spring Boot 运作原理
Spring Boot 运作原理 1.Spring Boot 简介 SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了 ...
- Windows Server 2008 R2下将JBoss安装成windows系统服务
JBoss版本是jboss-4.2.3.GA-jdk6.zip,操作系统是Windows Server 2008 R2. 1.系统已安装好java环境,JAVA_HOME已配置好: 2.下载所需文件. ...
- hdu 3879 方案选择
每日一水--- #include <cstdio> #include <cstring> #include <vector> #define oo 0x3f3f3f ...
- Codeforces Round #297 (Div. 2)C. Ilya and Sticks 贪心
Codeforces Round #297 (Div. 2)C. Ilya and Sticks Time Limit: 2 Sec Memory Limit: 256 MBSubmit: xxx ...
- 解决IE11下载文件 文件名乱码问题
1.Win + R输入gpedit.msc打开组策略编辑器:(不会请看下图) 2.定位到计算机配置→管理模板→windows组件→Internet Explorer→自定义用户代理字符串(有些系统用的 ...
- chrome --headless --disable-gpu --dump-dom http://www.python.org
Driving Headless Chrome with Python:Python chrome --headless --disable-gpu --dump-dom http://www.pyt ...
- HDU 4730 We Love MOE Girls (2013成都网络赛,签到水题)
We Love MOE Girls Time Limit: 1000/500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...