条件语句的作用是更改控制流,任何程序都离不开条件判断。但条件判断会增加程序的复杂度,过多的条件判断会导致循环复杂度(Cyclomatic Complexity)。
这种复杂度取决于3个因素:

  • 分支变量数
  • 分支数
  • 条件嵌套深度
ifelse ifelse ifelse ifswitchcase 1:...case 2:...end switch......end ifend ifend if
end if

这种形状也叫 Arrow Anti Pattern。它不仅降低程序的可读性,难以扩展和重用,还会轻易地隐藏许多bug。是我们必须避免的代码。

设计模式注重于软件的重用性和扩展性,但大多数模式都可以用来降低循环复杂度。设计模式可以让不同参与者分担这些条件语句,每个参与者解决一部分问题,这样控制流程就更简单,从而降低他们的循环复杂性。

这里介绍一个用策略(Strategy)设计模式来降低循环复杂度的例子。

假设现在我们可以用 C# 写一个简单的计算器,代码如下:

using System;public class Calculator
{public double Calculate(double operand1, double operand2, char operater){double result = 0.0;switch (operater){case '+':result = operand1 + operand2;break;case '-':result = operand1 - operand2;break;case '*':result = operand1 * operand2;break;case '/':if (Math.Abs(operand2) > 0.0){result = operand1 / operand2;}else{throw new ArithmeticException("分母为零。");}break;default:throw new ArgumentException("未知运算符: " + operater);}return result;}public static void Main(String[] args){args = new[] { "2", "*", "3" };double operand1 = Double.Parse(args[0]);double operand2 = Double.Parse(args[2]);char operater = args[1][0];double result = new Calculator().Calculate(operand1, operand2, operater);Console.WriteLine(operand1 + args[1] + operand2 + " = " + result);Console.ReadKey();}
}

现在用策略模式来重构这段代码:

模式角色:
Strategy: IProcessor
ConcreteStrategy: Adder, Subtractor, Multiplier, Divider
Context: Calculator

using System;
using System.Collections.Generic;public interface IProcessor
{double Process(double operand1, double operand2);
}public class Adder : IProcessor
{public double Process(double operand1, double operand2){return operand1 + operand2;}
}public class Subtractor : IProcessor
{public double Process(double operand1, double operand2){return operand1 - operand2;}
}public class Multiplier : IProcessor
{public double Process(double operand1, double operand2){return operand1 * operand2;}
}public class Divider : IProcessor
{public double Process(double operand1, double operand2){double result;if (Math.Abs(operand2) > 0.0){result = operand1 / operand2;}else{throw new ArithmeticException("分母为零。");}return result;}
}public class Calculator
{private Dictionary<string, IProcessor> processors;public Calculator(){processors = new Dictionary<string, IProcessor>();processors.Add("+", new Adder());processors.Add("-", new Subtractor());processors.Add("*", new Multiplier());processors.Add("/", new Divider());}public double Calculate(double operand1, double operand2, string operater){double result;if (processors.ContainsKey(operater)){result = processors[operater].Process(operand1, operand2);}else{throw new ArgumentException("未知运算符: " + operater);}return result; }public static void Main(string[] args){args = new[] { "2", "*", "3" };if (args.Length != 3){Console.WriteLine("Usage: Calculator < operand1 > <operater> < operand2 > ");}else{double operand1 = Double.Parse(args[0]);double operand2 = Double.Parse(args[2]);Calculator calculator = new Calculator();try{double result = calculator.Calculate(operand1, operand2, args[1]);Console.WriteLine(operand1 + args[1] + operand2 + "=" + result);}catch (Exception exp){Console.WriteLine(exp.ToString());}}Console.ReadKey();}
}

这里针对不同的运算符使用相应的 Processor 策略进行处理以实现计算目标,避免了循环嵌套( if / else ),也避免了最简单的开关判断(switch)。

本文讨论了使用设计模式来降低循环复杂性的方法。通过使用设计模式重构具有更高循环复杂性的代码可以带来灵活,可配置和可扩展的系统。但是,由于需要更多的类相互协同工作,他们之间存在耦合,因此这种重构增加了解决方案的结构复杂性。因此,这些例子的应用可能更适合在条件语句可以从若干复杂分支中进行选择的时候使用,而这些分支可能会随时间而发生变化。这种变化可以是这些分支的数量以及每个分支内的功能。一个典型的例子可能是数据通信应用程序中的消息接收器,它传递许多不同类型的消息。每种消息类型都可以由单独的消息处理程序处理。这些消息处理程序可以按策略或责任链进行安排。不仅每个消息处理程序的内聚性都更高,而且生成的应用程序还可以扩展以处理较新的消息类型。

用设计模式降低循环复杂性相关推荐

  1. 急需降低系统复杂性,我们从 Kafka 迁移到了 Pulsar

    要点总结 分布式消息系统支持流和队列两种语义,这两种语义最适合使用的场景有所不同. Pulsar 的独特之处在于它同时支持流和队列使用场景. Pulsar 采用多层架构,可以轻松扩展 topic 的数 ...

  2. 降低软件复杂性一般原则和方法

    一.前言 斯坦福教授.Tcl语言发明者John Ousterhout 的著作<A Philosophy of Software Design>[1],自出版以来,好评如潮.按照IT图书出版 ...

  3. 美团技术:降低软件复杂性的原则和方法!

    本文是作者阅读John Ousterhout的<A Philosophy of Software Design>之后,结合自己的工作经验,对"降低复杂性"做了详细总结, ...

  4. 【转】降低软件复杂性的一般原则和方法

    写在最前 本文转载自美团技术团队文章,个人阅读后有些感触,且认为值得再读,决定转载,转载已获得授权.后面再次阅读及查阅相关材料后再做一遍总结. 一.前言 斯坦福教授.Tcl语言发明者John Oust ...

  5. 案例故事丨老虎国际 x TiDB ,降低架构复杂性,保障全球用户安全可靠投资

    券商是一个古老的行业,发展至今已经历了三个时代:第一代券商为传统券商,在线下交易大厅进行买卖:第二代券商开始了电子化进程,从线下到线上进行了浅层服务的转移,改善了用户体验,提高了金融服务的效率:第三代 ...

  6. java 圈复杂度_关于Java:降低Switch语句的循环复杂度-Sonar

    我想减少开关盒的圈复杂度 我的代码是: public String getCalenderName() { switch (type) { case COUNTRY: return country = ...

  7. FreeCodeCamp和JavaScript纹身

    by Andrea Goulet 通过安德烈·古莱特(Andrea Goulet) FreeCodeCamp和JavaScript纹身 (FreeCodeCamp and the JavaScript ...

  8. 二 需求工程和设计模式

    目录 一.需求工程 1.需求开发 1.1需求获取 1.2需求分析 1.2.1 SA 结构式需求分析 1.2.2 面向对象OOA分析.UML 1.3需求定义 1.4需求验证 2.需求管理 二.系统设计 ...

  9. 总结下我所学 设计模式

    ╮(╯▽╰)╭,,,.... 未必正确. 初学者慎重,本文系个人看法. 勿轻易接受. 从听说-接触-学习.快半年了吧.... 自己感觉设计模式精华在于 一个解耦合的过程,不必强记,..尽管当时我通读完 ...

最新文章

  1. suse linux ssh connerc failed
  2. cisco路由器设置telnet口令的问题
  3. 通过flask构建自己的代理池
  4. 西瓜书学习记录-模型评估与选择(第二章)
  5. MFC添加自定义消息及处理函数
  6. 求二叉树中以x为根的子树的深度_还在玩耍的你,该总结啦!(本周小结之二叉树)...
  7. Compressor 4.6.1 for Mac(视频转码工具)
  8. ITerm2的安装和配置
  9. gjb150.16a-2009振动试验标准及介绍
  10. Zookeeper + ActiveMQ 集群整合
  11. cesium 漫游飞行_cesium之三维漫游飞行效果实现篇
  12. 初中英语语法(019)-连词
  13. java计算机毕业设计健康生活网站源程序+mysql+系统+lw文档+远程调试
  14. 深入solidity内部 -以太坊EVN插槽存储关系
  15. c1语言水平要多久,「西班牙留学」零基础到西班牙读语言,多久能到C1?
  16. 如何将 Django 服务器单独部署到 heroku 上
  17. C语言实现二叉平衡树
  18. jaffe 数据库百度网盘下载
  19. php采集淘宝店的评论,php采集淘宝店铺的所有评论的实现
  20. Maven下载、安装与配置

热门文章

  1. JS运算符% 和 /
  2. android app 素材下载地址,素材空间app下载-素材空间 安卓版v3.4.7-PC6安卓网
  3. SELinux 宽容模式(permissive) 强制模式(enforcing) 关闭(disabled) 几种模式之间的转换
  4. 全外连接、左外连接和右外连接区别(含举例)
  5. 采购申请及订单审批策略
  6. 模拟手写手抄字体程序
  7. Google play谷歌商店发布应用2021
  8. crosswalk cordova
  9. 关于高维空间的个人理解
  10. 单片机中进制转换与应用