网络编程
位置:首页>> 网络编程>> JavaScript>> 从if else到switch case再到抽象(3)

从if else到switch case再到抽象(3)

作者:Cat Chen 来源:百度泛用户体验 发布时间:2010-11-05 18:30:00 

标签:分支,IF,编程

如何避免复杂分支

首先,复杂逻辑运算是不能避免的。重构得到的结果应该是等价的逻辑,我们能做的只是让代码变得更加容易阅读和管理。因此,我们的重点应该在于如何使得复杂逻辑运算变得易于阅读和管理。

抽象为类或者工厂

对于习惯于做面向对象设计的人来说,可能这意味着将复杂逻辑运算打散并分布到不同的类里面:


switch (json.result) {
  case "ok":
    var factory = commandFactories.getFactory(json.command);
    var command = factory.buildCommand(json);
    command.execute();
    break;
}


这看起来不错,至少分支变短了,代码变得容易阅读了。这个 switch case 只管状态码分支,对于 “ok” 这个状态码具体怎么处理,那是其他类管的事情。 getFactory 里面可能有一组分支,专注于创建这条指令应该选择哪一个工厂的选择。同时 buildCommand 可能又有另外一些琐碎的分支,决定如何构建这条指令。

这样做的好处是,分支之间的嵌套关系解除了,每一个分支只要在自己的上下文中保持正确就可以了。举个例子来说, getFactory 现在是一个具名函数,因此这个函数内的分支只要实现 getFactory 这个名字暗示的契约就可以了,无需关注实际调用 getFactory 的上下文。

抽象为模式匹配

另外一种做法,就是把这种复杂逻辑运算转述为模式匹配:


Network.listen({
  "result": "ok",
  "command": "message",
  "content": { "from": "", "content": "kicked" }
}, function(json) { /* disconnect */ });

Network.listen([{
  "result": "ok",
  "command": "message",
  "content": { "type": "sysmsg" }
}, {
  "result": "ok",
  "command": "systemmessage"
}], function(json) { /* render system message */ });

Network.listen({
  "result": "ok",
  "command": "message",
  "content": { "from$ne": "", "type$ne": "sysmsg" }
}, func  tion(json) { /* render chat message */ });


现在这样子是不是清晰多了?第一种情况,是被踢下线,必须匹配指定的 from 和 content 值。第二种情况,是显示系统消息,由于系统消息在两个版本的协议中略有不同,所以我们要捕捉两种不同的 JSON ,匹配任意一个都算是命中。第三种情况,是显示聊天消息,由于在老版本协议中系统消息和踢下线指令都属于特殊的聊天消息,为了兼容老版本协议,这两种情况要从显示聊天消息中排除出去,所以就使用了 “$ne” (表示 not equal )这样的后缀进行匹配。

由于 listen 方法是上下文无关的,每一个 listen 都独立声明自己匹配什么样的 JSON ,因此不存在任何隐含逻辑。例如说,要捕捉聊天消息,就必须显式声明排除 from == “” 以及 type == “sysmsg” 这两种情况,这不需要由上下文的 if else 推断得出。

使用模式匹配,可以大大提高代码的可读性和可维护性。由于我们要捕捉的是 JSON ,所以我们就使用 JSON 来描述每一个分支要捕捉什么,这比一个长长的逻辑运算表达式要清晰多了。同时在这个 JSON 上的每一处修改都是独立的,修改一个条件并不影响其他条件。

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com