目录
1, 用委托字典代替 switch...case;
2, 利用反射替代 switch...case;
3, 比较两种方案
4, 其他方案
5, 说明
6, 参考
在开发 ASP.NET 项目中, 通常使用一般处理程序 (ashx) 处理前端发送过来的请求, 因为一个 handler 会处理多个请求, 故 Ajax 请求中一般都会加一个 action 的参数, 在 handler 里根据这个 action 做相应的处理或返回相应的数据, 这里大多数人都会想到用 switch...case 做判断, 一开始我也是用的 switch, 但渐渐地发现, 每个 case 不像一个代码块, 不能为其中的变量提供一个独立的作用域! 而且, 如果 case 的情况比较多的话, 代码看上去也比较臃肿难维护;
那如何替换掉 switch...case 呢, 我想到了如下两个方案:
1, 用委托字典代替 switch...case;
首先在 handler 里声明一个私有的静态委托字典, key 为 action 字符串, value 为 Func 委托; 然后把 action 和对应的方法添加到字典中即可;
完整示例代码:
- namespace webApplication1
- {
- public class Handler1 : IHttpHandler
- {
- static Dictionary<string, Action<HttpContext>> MapActions = new Dictionary<string, Action<HttpContext>>(StringComparer.OrdinalIgnoreCase)
- {
- {"Add", Add},
- {"Sub", Sub}
- };
- public void ProcessRequest(HttpContext context)
- {
- context.Response.ContentType = "text/plain";
- try
- {
- var action = context.Request["Action"];
- if (string.IsNullOrEmpty(action))
- {
- context.Response.StatusCode = (int) HttpStatusCode.BadRequest;
- }
- if (MapActions.ContainsKey(action))
- {
- var actionFun = MapActions[action];
- if (actionFun != null)
- {
- actionFun(context);
- // 或
- //actionFun.Invoke(context);
- }
- else
- {
- context.Response.StatusCode = (int) HttpStatusCode.NotImplemented;
- }
- }
- else
- {
- context.Response.StatusCode = (int) HttpStatusCode.NotFound;
- }
- }
- catch (Exception e)
- {
- context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
- }
- finally
- {
- context.Response.End();
- }
- }
- public static void Add(HttpContext context)
- {
- int num1 = int.Parse(context.Request["Num1"]);
- int num2 = int.Parse(context.Request["Num2"]);
- int result = num1 + num2;
- context.Response.Write(result);
- }
- public static void Sub(HttpContext context)
- {
- int num1 = int.Parse(context.Request["Num1"]);
- int num2 = int.Parse(context.Request["Num2"]);
- int result = num1 - num2;
- context.Response.Write(result);
- }
- public bool IsReusable
- {
- get
- {
- return false;
- }
- }
- }
- }
2, 利用反射替代 switch...case;
利用反射, 将 action 的值与具体的方法对应上;
完整示例代码:
- namespace WebApplication1
- {
- public class Handler2 : IHttpHandler
- {
- static readonly Type[] SearchParamType = new[] { typeof(HttpContext) };
- public void ProcessRequest(HttpContext context)
- {
- var result = ActionInvoke(context);
- context.Response.ContentType = "text/plain";
- context.Response.Write(result);
- }
- private object ActionInvoke(HttpContext ctx)
- {
- var actionFun = this.GetType().GetMethod("ProcessAction_" + ctx.Request["action"] ?? "",
- BindingFlags.NonPublic |
- BindingFlags.IgnoreCase |
- BindingFlags.Instance |
- BindingFlags.Public,
- null,
- SearchParamType,
- null);
- if (null == actionFun)
- {
- return "UnknowAction";
- }
- return actionFun.Invoke(this, new[] { ctx });
- }
- public int ProcessAction_Add(HttpContext context)
- {
- int num1 = int.Parse(context.Request["Num1"]);
- int num2 = int.Parse(context.Request["Num2"]);
- int result = num1 + num2;
- return result;
- }
- public int ProcessAction_Sub(HttpContext context)
- {
- int num1 = int.Parse(context.Request["Num1"]);
- int num2 = int.Parse(context.Request["Num2"]);
- int result = num1 - num2;
- return result;
- }
- public bool IsReusable
- {
- get
- {
- return false;
- }
- }
- }
- }
3, 比较两种方案
反射会造成一定的性能损耗; 所以使用委托字典方案更加靠谱;
4, 其他方案
可以使用设计模式实现, 比如工厂模式, 状态模式, 中介模式等, 但用在上述这个场景, 那么就有杀鸡用牛刀的 感觉了;
5, 说明
在简单的逻辑中, case 分支少, 很少扩展, 那么应该用 switch 语句, 因为简单明了, 易于阅读.
如果在复杂的逻辑中, 复杂而且混乱的 case, 而且经常扩展什么的, 就应该用委托和反射, 使用缓存机制.
6, 参考
重构: switch 语句改成策略模式还是状态模式:
中介模式: https://www.cnblogs.com/insus/p/4134383.html
来源: https://www.cnblogs.com/willingtolove/p/11285680.html