关键词:条件判断,多态,策略模式,哈希表,字典map
作者:码匠信龙
笔者在用python实现事件驱动后,发现python是没有提供switch语句,python官方推荐多用字典来代替switch来实现,这让我就觉得有点奇怪了。我们在编写多分支结构的程序,一般编程语言都有提供会选择if-else或者switch-case语句。条件少的时候还可以,当分支结构过分长,就会导致代码不美观且不容易维护。在笔者的从业工作经验中,多次看到项目在网络消息处理和gui层消息处理代码中,有超过20多条的if-else,switch-case语句,导致函数代码非常长。
例如下面这段类似windows消息处理的伪代码
void WndProc(hWnd, message, wParam, lParam)
{
switch (message)
{
case WM_CREATE:
{
button1 = CreateWindow("button");
}
break;
case WM_COMMAND:
switch (cmdID)
{
case btn1:
MessageBox("XXXX");
break;
case btn2:
MessageBox("XXXX");
break;
case IDM_TEST:
MessageBox("XXXX");
break;
case IDM_ABOUT:
DialogBox("XXXX");
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return;
}
break;
case WM_PAINT:
dosomething();
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return;
}
return 0;
}
如果有100个消息ID,那就要写100个case的处理(经验不足的新手有时候甚至少写break关键字),整个WndProc函数就非常的长了。
而用python的字典实现的话,把消息处理函数映射到消息ID,伪代码如下
messages = {}
#绑定消息处理函数和消息ID
messages[WM_CREATE] = fun1;
messages[WM_PAINT] = fun2;
...
def WndProc(self,message):
if message.type in messages.keys():
listener = messages[message.type]
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
网友评论
calculation = {'+':lambda:add(x,y),
'*':lambda:multi(x,y),
'-':lambda:sub(x,y),
'/':lambd
return calculation[type]()
calc('+',3,6)
==========
lambda可以达到类似于switch效果