建议104:用多态代替条件语句

假设要开发一个自动驾驶系统。在设计之初,此自动驾驶系统拥有一个驾驶系统命令的枚举类型:

    enum DriveCommand
{
Start,
Stop
}

当前该枚举存在两个命令:开始、停止。又假设有一个驾驶方法可以处理车辆接收到的指令。一开始我们可能像下面这样编码:

        static void Main(string[] args)
{
DriveCommand command = DriveCommand.Start;
Drive(command);
command = DriveCommand.Stop;
Drive(command); } static void Drive(DriveCommand command)
{
if (command == DriveCommand.Start)
{
//车辆启动
}
else if (command == DriveCommand.Stop)
{
//车辆停止
}
}

有些人可能喜欢用switch语句(当然,switch本质上也是if语句)。

        static void Drive(DriveCommand command)
{
switch (command)
{
case DriveCommand.Start:
//车辆启动
break;
case DriveCommand.Stop:
//车辆停止
break;
default:
break;
}
}

随着更多的系统功能不断地被开发出来,我们考虑为车辆加入的命令也越来越多,如下所示:

    enum DriveCommand
{
Start,
Stop,
Pause,
TurnLeft,
TurnRight
}

随着DriveCommand元素的增加,采用if或switch语句将带来可怕的混乱状态是显而易见的。在一个复杂的控制系统中,命令可能会多达上百条。每增加一条命,我们首先要修改Drive方法。Drive方法将会及其膨胀,而且每行代码几乎是一模一样的:

if 命令

  then 行动

这种情况,我们不得不考虑重构原来的代码。原来的设计理念也是欠妥当的,它不遵守设计模式中的“开闭原则”。开闭原则是指:对扩展开发,对修改关闭。遵从开闭原则的一次重构是,使用多态来规避不断膨胀的条件语句。首先,设计一个抽象类Commander:

    abstract class Commander
{
public abstract void Execute();
}

所有的Start或者Stop之类的命令,全部继承自这个抽象类:

    class StartCommander : Commander
{ public override void Execute()
{
//启动
}
} class StopCommander : Commander
{ public override void Execute()
{
//停止
}
}

在使用多态后,调用方法的代码应该如下所示:

        static void Main(string[] args)
{
Commander commander = new StartCommander();
Drive(commander);
commander = new StopCommander();
Drive(commander);
} static void Drive(Commander commander)
{
commander.Execute();
}

可见,代码简洁了不少,而且,可扩展性增强了。即使未来还需要增加命令,扩展相应的子类就可以了。而且我们关闭了修改,即对Drive方法,即使增加再多的命令,也不需要对其进行修改。

转自:《编写高质量代码改善C#程序的157个建议》陆敏技

最新文章

  1. Jekyll 安装权限问题 ERROR: While executing gem ... (Errno::EPERM) Operation not permitted - /usr/bin/jekyll
  2. django表单
  3. LAMP理论整理
  4. 进阶篇:以IL为剑,直指async/await
  5. iBoxDB for .NET v1.5发布, 移动NoSQL数据库
  6. VS2013打开项目提示此版本的应用程序不支持其项目类型(.csproj)
  7. SoapUI中Groovy的实用方法
  8. php header示例代码(推荐)
  9. Core Foundation框架介绍
  10. Signing key has not been configured
  11. PHP配置xdebug
  12. VB.NET的反射机制
  13. lintcode.66 二叉树前序遍历
  14. Markdown编辑器 简单使用
  15. linux系统 initrd.img中init启动脚本分析
  16. 强化学习(二)马尔科夫决策过程(MDP)
  17. 自定义Cordova插件(基础篇)
  18. Spark 实践——音乐推荐和 Audioscrobbler 数据集
  19. Spark的word count
  20. STL查找序列中处于某一大小范围内的元素个数

热门文章

  1. MVC、MVP、MVVM架构模式
  2. Tkinter PanedWindow
  3. OpenLayers 3 之 地图控件(control)
  4. 接触C# 反射
  5. dbf 命令 及数据类型
  6. 10分钟.Net Core 简单入门教程
  7. @RestController使用 接收jso参数 将参数转换为对象
  8. effective javascript 学习心得
  9. 发生在阿里云 SLB 4 层的一次故障记录
  10. 【300】◀▶ IDL - ENVI API