Description
A switch statements internally behaves like a set of conditioned jumps. It’s an expression and the nature of the it doesn’t take advantage of OOP concept.
The readability and complexity of a switch statements are unarguably on the low side and need improvements.
Consider the following example:
enum Status { Active = 1, Inactive = 2, AccessGranted = 4, AccessNotAllowed = 8 }
This enum defines a set of flags that may describe the access of a certain individual to a set of data. For this example let’s assume that a user can access data only if it’s Active and has Access.
Then on the client side you would have to deal with states like this:
Status guyStatus = Status.AccessGranted | Status.Active; switch (guyStatus) { case Status.AccessGranted | Status.Active: Console.WriteLine("Guy is active and access is granted - Allowed"); Console.WriteLine("Some operations on status active and allowed"); break; case Status.AccessGranted | Status.Inactive: Console.WriteLine("Guy is inactive and access is granted - NotAllowed"); break; case Status.AccessNotAllowed | Status.Active: Console.WriteLine("Guy is active and access is not granted - NotAllowed"); break; case Status.AccessNotAllowed | Status.Inactive: Console.WriteLine("Guy is inactive and access is not granted - NotAllowed"); break; default: Console.WriteLine("Not Allowed"); break; }
Problem
Well, it’s obvious that the more flags you define, the more the complexity increases and also the readability decreases.
Solution
Well, it’s obvious that the more flags you define, the more the complexity increases and also the readability decreases.
Strategy Pattern is used to refactor this example, to turn the instructions into objects, but this is adapted for switch statements.
Classical Strategy Pattern implies defining a base class / interface upon which child strategies inherit. For this kind of problem we do not define more classes, but a dictionary of strategies:
We define a class that incorporates the functionality of the access. In the end, it’s the object’s responsibility of choosing strategy based on the status
class GuyStatus { //Status is private - who should care of this representation? It's a matter of this object [Flags] private enum StatusRepresentation { Active = 1, Inactive = 2, AccessGranted = 4, AccessNotAllowed = 8 } private StatusRepresentation status; protected Dictionary<int, Action> strategies = new Dictionary<int, Action>(); public GuyStatus() { strategies.Add((int)(StatusRepresentation.Active | StatusRepresentation.AccessGranted), () => { Console.WriteLine("Guy is active and access is granted - Allowed"); }); strategies.Add((int)(StatusRepresentation.Active | StatusRepresentation.AccessNotAllowed), () => { Console.WriteLine("Guy is active and access is not granted - NotAllowed"); }); strategies.Add((int)(StatusRepresentation.Inactive | StatusRepresentation.AccessGranted), () => { Console.WriteLine("Guy is inactive and access is granted - NotAllowed"); }); strategies.Add((int)(StatusRepresentation.Inactive | StatusRepresentation.AccessNotAllowed), () => { Console.WriteLine("Guy is inactive and access is not granted - NotAllowed"); }); } public static GuyStatus ActiveAllowed() => new GuyStatus { status = StatusRepresentation.Active | StatusRepresentation.AccessGranted }; public static GuyStatus ActiveNotAllowed() => new GuyStatus { status = StatusRepresentation.Active | StatusRepresentation.AccessNotAllowed }; public virtual void Execute(Action action) { if (status == (StatusRepresentation.AccessGranted | StatusRepresentation.Active) && this.strategies.Keys.Any(x => x == (int)this.status)) { this.strategies[(int)this.status].Invoke(); action(); } else Console.WriteLine("Not Allowed"); } }
And the client usage:
GuyStatus guyStat = GuyStatus.ActiveAllowed(); guyStat.Execute(() => { Console.WriteLine("Some operations on status active and allowed"); });