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