Refactoring a Switch Statement

本文介绍了一种通过重构状态切换逻辑来降低设备控制器类中开关语句的圈复杂度的方法。利用字典映射和委托调用,将复杂的开关语句简化为单一操作,有效减少代码复杂度。

Introduction

This article describes refactoring a switch statement in order to reduce Cyclomatic complexity.

Background

Many developers would have scratched their heads in order to keep their Cyclomatic complexity under 10. In some cases, it is really not possible at first site. In this article, I have provided a way to do that. Take the example of a Device State machine. You have a number of device states as below:

public
 enum
 DeviceStatesEnum
{
PowerUp,
Waiting,
StandBy,
Inactive,
Active,
Start,
Ready,
Equilibrating,
StartRunning,
Running,
ShoutingDown,
ShoutDown,
WarmingUp,
Error
}

Using the code

Just download the code and run it.

public
 enum
 DeviceStatesEnum
{
PowerUp,
Waiting,
StandBy,
Inactive,
Active,
Start,
Ready,
Equilibrating,
StartRunning,
Running,
ShoutingDown,
ShoutDown,
WarmingUp,
Error
}

You have come up with the following class in order to handle the various states:

public
 class
 DeviceController
{
private DeviceStatesEnum _currentDeviceState = DeviceStatesEnum.ShoutDown;

public void ChangeDeviceState(DeviceStatesEnum deviceState)
{
switch (deviceState)
{
case DeviceStatesEnum.Active:
SetDeviceStateToActive();
break ;
case DeviceStatesEnum.Equilibrating:
SetDeviceStateToEquilibrating();
break ;
case DeviceStatesEnum.Error:
SetDeviceStateToError();
break ;
case DeviceStatesEnum.Inactive:
SetDeviceStateToInactive();
break ;
case DeviceStatesEnum.PowerUp:
SetDeviceStateToPowerUp();
break ;
case DeviceStatesEnum.Ready:
SetDeviceStateToReady();
break ;
case DeviceStatesEnum.Running:
SetDeviceStateToRunning();
break ;
case DeviceStatesEnum.ShoutDown:
SetDeviceStateToShoutDown();
break ;
case DeviceStatesEnum.ShoutingDown:
SetDeviceStateToShoutingDown();
break ;
case DeviceStatesEnum.StartRunning:
SetDeviceStateToStartRunning();
break ;
}
}

public DeviceStatesEnum GetDeviceState()
{
return _currentDeviceState;
}

private void SetDeviceStateToStartRunning()
{
if (_currentDeviceState == DeviceStatesEnum.Ready)
_currentDeviceState = DeviceStatesEnum.StartRunning;
}

private void SetDeviceStateToShoutingDown()
{
_currentDeviceState = DeviceStatesEnum.ShoutingDown;
}

private void SetDeviceStateToShoutDown()
{
_currentDeviceState = DeviceStatesEnum.ShoutDown;
}

private void SetDeviceStateToRunning()
{
if (_currentDeviceState == DeviceStatesEnum.StartRunning )
{
_currentDeviceState = DeviceStatesEnum.Running;
}
}

private void SetDeviceStateToReady()
{
if (_currentDeviceState == DeviceStatesEnum.Equilibrating )
{
_currentDeviceState = DeviceStatesEnum.Ready;
}
}

private void SetDeviceStateToPowerUp()
{
if (_currentDeviceState != DeviceStatesEnum.Error)
_currentDeviceState = DeviceStatesEnum.PowerUp;
}

private void SetDeviceStateToInactive()
{
if (_currentDeviceState != DeviceStatesEnum.Error)
_currentDeviceState = DeviceStatesEnum.Inactive;
}

private void SetDeviceStateToError()
{
_currentDeviceState = DeviceStatesEnum.Error;
}

private void SetDeviceStateToEquilibrating()
{
if (_currentDeviceState == DeviceStatesEnum.Active)
{
_currentDeviceState = DeviceStatesEnum.Equilibrating;
}
}

private void SetDeviceStateToActive()
{
if (_currentDeviceState != DeviceStatesEnum.Error)
{
_currentDeviceState = DeviceStatesEnum.Active;
}
}
}

Since you have 14 states, you will end up having a Cyclomatic complexity more than 14. Here is the way to reduce this complexity to 1. Do the following changes in the above class DeviceController . Declare a Dictionary .

private
 Dictionary<DeviceStatesEnum, Action> _deviceStateHandler = 
new Dictionary<DeviceStatesEnum, Action>();

Add a constructor to create a mapping with the states.

public
 DeviceController()
{
_deviceStateHandler.Add(DeviceStatesEnum.Active, new Action(SetDeviceStateToActive));
_deviceStateHandler.Add(DeviceStatesEnum.Equilibrating,
new Action(SetDeviceStateToEquilibrating));
_deviceStateHandler.Add(DeviceStatesEnum.Error, new Action(SetDeviceStateToError));
_deviceStateHandler.Add(DeviceStatesEnum.Inactive,
new Action(SetDeviceStateToInactive));
_deviceStateHandler.Add(DeviceStatesEnum.PowerUp, new Action(SetDeviceStateToPowerUp));
_deviceStateHandler.Add(DeviceStatesEnum.Ready, new Action(SetDeviceStateToReady));
_deviceStateHandler.Add(DeviceStatesEnum.Running, new Action(SetDeviceStateToRunning));
_deviceStateHandler.Add(DeviceStatesEnum.ShoutDown,
new Action(SetDeviceStateToShoutDown));
_deviceStateHandler.Add(DeviceStatesEnum.ShoutingDown,
new Action(SetDeviceStateToShoutingDown));
_deviceStateHandler.Add(DeviceStatesEnum.StartRunning,
new Action(SetDeviceStateToActive));

// TODO
// Create mapping for all the states
}

Then, change the ChangeDeviceState as below:

public
 void
 ChangeDeviceState(DeviceStatesEnum deviceState)
{
_deviceStateHandler[deviceState].Invoke();
}

Now the Cyclomatic complexity of the method ChangeDeviceState is one.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

rajeshjj

修改函数,参考以下格式:@cppcheck.checker def check_control_block_braces(cfg, data): """ 检查所有控制语句的代码块是否使用了花括号,且左花括号要相对于条件判断另起一行。 规则: 1. if, while, for 等分支的代码块必须使用花括号"{}"括起来,即使只有一行代码 不符合规范: if (condition) doSomething(); 符合规范: if (condition) { doSomething(); } """ # 需要检查的控制语句关键字 control_keywords = ['if', 'else', 'for', 'while', 'do'] for token in cfg.tokenlist: #for token in data.rawTokens: # 检查是否是控制语句关键字 if token.str not in control_keywords: continue # 特殊处理 else if if token.str == 'else': current = token.next while current and current.column == 0: # 跳过自动生成的{ current = current.next if current and current.str == 'if': # 跳过 else,让 if 部分进行检查 continue if token.previous and token.previous.str == '#': # 如果是宏定义,则跳过 continue # 找到控制语句的条件部分的右括号(对于if, for, while, switch)或者直接找do语句 condition_end = None if token.str == 'do': # 对于do-while语句,直接查找左花括号 brace_token = token.next if brace_token: # 检查是否有左花括号 while brace_token and brace_token.column == 0: brace_token = brace_token.next if brace_token.str != '{': statement_parts = [] t = token while t and t.linenr == token.linenr and t.column != 0: statement_parts.append(t.str) t = t.next statement = ' '.join(statement_parts) error_message = f"Statement '{statement}' should use curly braces" error_key = (token.linenr, error_message) if error_key not in reported_errors: cppcheck.reportError( token, 'severity:warning', error_message ) reported_errors.add(error_key) continue elif token.str == 'else': # 对于单独的else,检查后面是否直接跟着左花括号 current = token.next while current and current.column == 0: current = current.next if not current or current.str != '{': statement_parts = [] t = token while t and t.linenr == token.linenr and t.column != 0: statement_parts.append(t.str) t = t.next statement = ' '.join(statement_parts) error_message = f"Statement '{statement}' should use curly braces" error_key = (token.linenr, error_message) if error_key not in reported_errors: cppcheck.reportError( token, 'severity:warning', error_message ) reported_errors.add(error_key) continue else: # 排除do-while语句 if token.str == 'while' and token.previous and token.previous.str == '}': continue # 对于if, for, while, switch,找到条件部分的结束位置 if token.next and token.next.str == '(': # 找到对应的右括号 condition_end = token.next.link # 如果找不到条件结束位置,跳过 if not condition_end: continue # 检查条件后面是否跟着左花括号 next_token = condition_end.next # 跳过空白和注释 while next_token and (next_token.str.isspace() or next_token.column == 0): next_token = next_token.next # 如果下一个token不是左花括号,报告错误 if not next_token or next_token.str != '{': statement_parts = [] t = token while t and t.linenr == token.linenr: t = t.previous t = t.next while t and t.linenr == token.linenr: if t.column != 0: statement_parts.append(t.str) t = t.next statement = ' '.join(statement_parts) error_message = f"Statement '{statement}' should use curly braces" error_key = (token.linenr, error_message) if error_key not in reported_errors: cppcheck.reportError( token, 'severity:warning', error_message ) reported_errors.add(error_key)
10-16
先展示下效果 https://pan.quark.cn/s/a4b39357ea24 遗传算法 - 简书 遗传算法的理论是根据达尔文进化论而设计出来的算法: 人类是朝着好的方向(最优解)进化,进化过程中,会自动选择优良基因,淘汰劣等基因。 遗传算法(英语:genetic algorithm (GA) )是计算数学中用于解决最佳化的搜索算法,是进化算法的一种。 进化算法最初是借鉴了进化生物学中的一些现象而发展起来的,这些现象包括遗传、突变、自然选择、杂交等。 搜索算法的共同特征为: 首先组成一组候选解 依据某些适应性条件测算这些候选解的适应度 根据适应度保留某些候选解,放弃其他候选解 对保留的候选解进行某些操作,生成新的候选解 遗传算法流程 遗传算法的一般步骤 my_fitness函数 评估每条染色体所对应个体的适应度 升序排列适应度评估值,选出 前 parent_number 个 个体作为 待选 parent 种群(适应度函数的值越小越好) 从 待选 parent 种群 中随机选择 2 个个体作为父方和母方。 抽取父母双方的染色体,进行交叉,产生 2 个子代。 (交叉概率) 对子代(parent + 生成的 child)的染色体进行变异。 (变异概率) 重复3,4,5步骤,直到新种群(parentnumber + childnumber)的产生。 循环以上步骤直至找到满意的解。 名词解释 交叉概率:两个个体进行交配的概率。 例如,交配概率为0.8,则80%的“夫妻”会生育后代。 变异概率:所有的基因中发生变异的占总体的比例。 GA函数 适应度函数 适应度函数由解决的问题决定。 举一个平方和的例子。 简单的平方和问题 求函数的最小值,其中每个变量的取值区间都是 [-1, ...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值