关键词:条件判断,多态,策略模式,哈希表,字典map

作者:码匠信龙

笔者在用python实现事件驱动后,发现python是没有提供switch语句,python官方推荐多用字典来代替switch来实现,这让我就觉得有点奇怪了。我们在编写多分支结构的程序,一般编程语言都有提供会选择if-else或者switch-case语句。条件少的时候还可以,当分支结构过分长,就会导致代码不美观且不容易维护。在笔者的从业工作经验中,多次看到项目在网络消息处理和gui层消息处理代码中,有超过20多条的if-else,switch-case语句,导致函数代码非常长。

例如下面这段类似windows消息处理的伪代码

  1. void  WndProc(hWnd, message, wParam, lParam) 
  2. {  
  3.     switch (message)   
  4.     {  
  5.     case WM_CREATE:  
  6.         {  
  7.             button1 = CreateWindow("button");  
  8.         }  
  9.         break;  
  10.     case WM_COMMAND:  
  11.         switch (cmdID)  
  12.         {  
  13.         case btn1:  
  14.             MessageBox("XXXX");  
  15.             break;  
  16.         case btn2:  
  17.             MessageBox("XXXX"); 
  18.             break;  
  19.         case IDM_TEST:  
  20.            MessageBox("XXXX");  
  21.             break;  
  22.         case IDM_ABOUT:  
  23.             DialogBox("XXXX");  
  24.             break;  
  25.         case IDM_EXIT:  
  26.             DestroyWindow(hWnd);  
  27.             break;  
  28.         default:  
  29.             return;
  30.         }  
  31.         break;  
  32.         case WM_PAINT:  
  33. dosomething();
  34.             break;  
  35.         case WM_DESTROY:  
  36.             PostQuitMessage(0);  
  37.             break;  
  38.         default:  
  39.             return;
  40.     }  
  41.     return 0;  
  42. }  

如果有100个消息ID,那就要写100个case的处理(经验不足的新手有时候甚至少写break关键字),整个WndProc函数就非常的长了。

而用python的字典实现的话,把消息处理函数映射到消息ID,伪代码如下

  1. messages = {}
  2. #绑定消息处理函数和消息ID
  3. messages[WM_CREATE] = fun1;
  4. messages[WM_PAINT] = fun2;
  5. ...
  6. def WndProc(self,message):                  
  7. if message.type in messages.keys():              
  8. listener = messages[message.type]                                
  9. listener(message)

读者可以看到,整个WndProc就变成几行代码,消息处理函数的定义和绑定可以在其它地方实现,不需要全部都堆在一块,使得分支判断逻辑和细节处理函数分离了,而且提高了代码可读性和扩展性。高内聚,低耦合,这是编程开发中很重要的一种思想,上面例子说明了如何解耦分支逻辑和处理函数。

在笔者也曾在一个开源UI编辑器的源码中看过在gui层,解析ui配置文件生成界面的实现上也有类似的实现。

在《重构》一书中,专门有一章是内容讲解“简化条件表达式”,里面就有讲到利用多态取代条件表达式。而多态应用场景正是当对象要根据不同的状态表现不同的行为时使用的。java经常讲很多设计模式中都有用到多态的特性,以前看java项目代码发现很少有用到很多if-else和switch-case的代码段,反而经常看到很多用多态实现的类,通过继承抽象类,重写抽象方法的方式,来避免使用了条件语句。

突然想起C++的多态实现,虚函数表,存的是虚函数的指针,也就是虚函数的地址,也是通过数组或哈希表来存储(数组其实也是一种哈希表)。冥冥之中好像它们之间有着某种联系。

读到这里,你会发现字典(哈希表)map是很神奇一种数据结构,再多考虑一步:

1.map的value中保存的不再是基本数据类型,而是对象。这样一来,通过不同的key可以拿到不同的对象,如果这些对象的类都实现同一个接口,那么这就是一个加强版的策略模式,就是多态性的体现,传统的策略模式传入的是实现类的对象,而通过map加强,只需传入一个数字或字符串即可实现多态。

2.map的value中保存的是函数,通过不同的key(消息类型)可以拿到不同的响应处理函数,则可以实现消息机制或事件驱动。

字典只是一种数据结构,但通过不同的变化,却可以用更简单的方式实现某些设计模式或面向对象的多态特性,以至于让笔者觉得如何锻炼抽象业务逻辑和解耦代码的能力,才是一种更简单自然的编程方式,没有一种固定的编程范式,学习某某设计模式反而固化了编程思维。

虽然if-else和switch很常见的关键字,但不知读者是否也能停下来思考一下。

版权声明:本文为博主原创,欢迎转载分享,只需注明作者与出处http://thinkingroom.me

由if-else,switch代替方案引起的思考的更多相关文章

  1. MapReduce源码分析之Task中关于对应TaskAttempt存储Map方案的一些思考

    我们知道,MapReduce有三层调度模型,即Job——>Task——>TaskAttempt,并且: 1.通常一个Job存在多个Task,这些Task总共有Map Task和Redcue ...

  2. 构建iOS稳定应用架构时方案选择的思考,主要涉及工程结构,数据流思想和代码规范

    工程结构架构,减少耦合混乱以及防治需求大改造成结构重构,如何构建稳定可扩展可变换的工程结构的思考 我打算采用Information flow的方式自上而下,两大层分为基础层和展现层的结构.基础层分为多 ...

  3. Dataguard配置总结

    Dataguard配置总结 本例情形 在主库存在运行的情况下,增加配置dataguard备库,实现双机热备,高可用性. 主库要求,归档模式,强制归档. 主库idty 备库idty_st 1.密码文件 ...

  4. python 基础部分重点复习整理--从意识那天开始进阶--已结

    pythonic 风格编码 入门python好博客 进阶大纲 有趣的灵魂 老齐的教程 老齐还整理了很多精华 听说 fluent python + pro python 这两本书还不错! 元组三种遍历, ...

  5. 提升代码幸福度,五个技巧减少js开发中的if else语句

     壹 ❀ 引 在JavaScript开发中,条件判断语句的使用频率是极高的,而对于条件判断简单易读的if else应该都是大家的首选.可是代码写的久了,我们总是希望自己的代码看着能更为简洁规范(逼格更 ...

  6. 【译】Redux 还是 Mobx,让我来解决你的困惑!

    原文地址:Redux or MobX: An attempt to dissolve the Confusion 原文作者:rwieruch 我在去年大量的使用了 Redux,但我最近都在使用 Mob ...

  7. You must use the Role Management Tool to install or configure Microsoft .NET Framework 3.5 SP1

    今天在Windows Server 2008 下安装SQL SERVER 2008时,碰到如下错误: You must use the Role Management Tool to install ...

  8. 【腾讯Bugly干货分享】微信终端跨平台组件 mars 系列(一) - 高性能日志模块xlog

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57ff5932cde42f1f03de29b1 本文来源: 微信客户端开发团队 ...

  9. 如何撰写PRD

    PRD(Product-Requirement-Document,产品需求文档),这对于任何一个产品经理来说都不会陌生的一个文档,一个PRD是衡量一个产品经理整体思维的标准,一个PRD可以看出一个产品 ...

随机推荐

  1. JavaScript基础——兼容性、错误处理

    JavaScript基础-错误处理Throw.Try.Catch try语句执行可能出错的代码 catch语句处理捕捉到的错误 throw语句创建自定义错误语句 发生的常见的错误类型 可能是语法错误, ...

  2. ERP实施规范化及示例——邮件沟通

    上门服务前 上门服务计划,要详细,提前发给客户,反复确定双方的行程 上门服务所需的常规文档(培训SOP,培训记录) 项目组内反复确认本次上门要完成的事项 …… 上门服务中 先跟老板沟通项目进展,本次上 ...

  3. MyBatis 使用Generator自动生成Model , Dao, mapper

    最近   我新建了一 个maven 项目,使用的是spring + springmvc + mybatis框架. 听说Mybatis可以自动生成model和mapper以及dao层,我就从网上查了查资 ...

  4. Extjs中创建Tree菜单【一】

    此篇treepanel的描写是很简单,没有太大的难度,在学习时,可以先熟悉tree的一些配置信息.属性.方法和事件. 然后先写一个简单的例子,慢慢了解从中如何实现的,然后在慢慢的深入了解,实现一些复杂 ...

  5. C#泛型编程

    1.泛型的概念     C#中的泛型与C++中的模板类似,泛型是实例化过程中提供的类型或类建立的.泛型并不限于类,还可以创建泛型接口.泛型方法,甚至泛型委托.这将极大提高代码的灵活性,正确使用泛型可以 ...

  6. 使用es6特性封装async-mysql

    node.js的mysql模块本身没有提供返回promise的函数,即是说都是用的回调函数,那么对于我们使用async函数是很不方便的一件事.node.js有一个mysql封装库叫mysql-prom ...

  7. 关于js模拟c#的Delegate(委托)实现

    这是我的第一篇博文,想来讲一讲js的函数.我的标题是js模拟c#的Delegate. 一.什么是Delegate(委托) 在jquery中有delegate函数,作用是将某个dom元素的标签的事件委托 ...

  8. jenkins gradle 编译遇到tomcat异常

    使用gradle在jenkins 上构建的时候遇到 进行构建的时候报"Could not load Logmanager org.apache.juli.ClassLoaderLogMana ...

  9. webStorm Linux Ubuntu 中文搜狗输入问题

    1 打开安装路径下bin/webstorm.sh vim ~/WebStorm-145.597.6/bin/webstorm.sh 2.在打开文件的最前面加入如下代码: export XMODIFIE ...

  10. H5表单

    H5表单 HTML5 新的 Input 类型 HTML5 拥有多个新的表单输入类型.这些新特性提供了更好的输入控制和验证. 本章全面介绍这些新的输入类型: email url number range ...