I\'m program in c# which you controlling by dictating command so now i have a long switch statement. Something like
switch (command)
{
case \"Show comma
I much prefer the Strategy Pattern for extending switch case statements. First, I create an interface that defines what each rule should look like:
public interface IWindowRule
{
string Command { get; }
void Invoke();
}
Then create a class that implements the interface for each possible case:
public class ShowAllWindowRule : IWindowRule
{
public string Command => "Show commands";
private ProgramCommands _progCommands;
public ShowAllWindowRule(ProgramCommands programCommands) =>
_progCommands = programCommands;
public void Invoke() => _progCommands.ShowAllCommands();
}
public class CloseWindowRule : IWindowRule
{
private ControlCommands _ctrlCommands;
public string Command => "Close window";
public CloseWindowRule(ControlCommands ctrlCommands) =>
_ctrlCommands = ctrlCommands;
public void Invoke() =>
_ctrlCommands.CloseWindow();
}
public class SwitchWindowRule : IWindowRule
{
private ControlCommands _ctrlCommands;
public string Command => "Switch window";
public SwitchWindowRule(ControlCommands ctrlCommands) =>
_ctrlCommands = ctrlCommands;
public void Invoke() =>
_ctrlCommands.SwitchWindow();
}
Then your switch statement turns into this:
public void RunWindowRule(IList<IWindowRule> rules, string command)
{
foreach (IWindowRule rule in rules)
{
if (rule.Command == command) rule.Invoke();
}
}
Now you can pass the function any set of rules you wish and run them making the function adhere to the Open/Closed principle.
I realize this may appear to be a bit of over engineering, and I do think there are more functional solutions that require a bit less work, however this has the added benefit of allowing you to extend this function by creating classes that inject the list of rules for a myriad of circumstances or even make a builder class that give you a fluent API.
public class WindowRuleBuilder
{
private IList<IWindowRule> rules;
public WindowRuleBuilder(IList<IWindowRule> rules = null) =>
rules = rules ?? new List<IWindowRule>();
public WindowRuleBuilder AddRule(IWindowRule newRule)
{
rules.Add(newRule);
return this;
}
public void Run(string command)
{
foreach (IWindowRule rule in rules)
{
if (rule.Command == command) rule.Invoke();
}
}
}
Now you have something like this:
public static void Main(string[] args)
{
WindowRuleBuilder ruleBuilder = new WindowRuleBuilder()
.AddRule(new CloseWindowRule(conrolCommands))
.AddRule(new ShowAllWindowRule(programCommands))
.AddRule(new SwitchWindowRule(controlCommands));
ruleBuilder.Run(args[0]);
}
This is highly extendable as for ever new rule you simply create the class and add it to the rule builder with the AddRule() method. It also doesn't take much reading to understand what's going on here. It's a much more compositional approach. Though I again admit, it does take a bit of work to implement but the code adheres to SOLID and is finely decoupled.
I realize this is an old post, but in these situations I find attributes and a factory very handy.
The following code uses a custom attribute (Command
) to allow you to attribute your methods, providing a string value of how they should respond to you.
The factory method uses reflection to generate a dictionary of these methods and calls it whenever you call CommandFactory
.
Things could get cleaned up a bit, calling invoke is a little ugly, but it just depends on how you want to execute the code.
using System.Collections.Generic;
using System.Linq;
namespace MyApp
{
using System.Reflection;
using MyApp.Commands;
class Program
{
static void Main(string[] args)
{
var methods = new MyCommands();
MethodInfo myMethod;
myMethod = CommandFactory.GetCommandMethod("Show Commands");
myMethod.Invoke(methods, null);
myMethod = CommandFactory.GetCommandMethod("Close window");
myMethod.Invoke(methods, null);
myMethod = CommandFactory.GetCommandMethod("Switch window");
myMethod.Invoke(methods, null);
}
}
public static class CommandFactory
{
private static Dictionary<string, MethodInfo> speechMethods = new Dictionary<string, MethodInfo>();
public static MethodInfo GetCommandMethod(string commandText)
{
MethodInfo methodInfo;
var commands = new MyCommands();
if (speechMethods.Count == 0)
{
var methodNames =
typeof(MyCommands).GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
var speechAttributeMethods = methodNames.Where(y => y.GetCustomAttributes().OfType<CommandAttribute>().Any());
foreach (var speechAttributeMethod in speechAttributeMethods)
{
foreach (var attribute in speechAttributeMethod.GetCustomAttributes(true))
{
speechMethods.Add(((CommandAttribute)attribute).Command, speechAttributeMethod);
}
}
methodInfo = speechMethods[commandText];
}
else
{
methodInfo = speechMethods[commandText];
}
return methodInfo;
}
}
}
namespace MyApp.Commands
{
class MyCommands
{
[Command("Show All")]
[Command("Show All Commands")]
[Command("Show commands")]
public void ShowAll()
{
ProgramCommands.ShowAllCommands();
}
[Command("Close Window")]
public void CloseWindow()
{
ControlCommands.CloseWindow();
}
[Command("Switch Window")]
public void SwitchWindow()
{
ControlCommands.SwitchWindow();
}
}
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple = true)]
public class CommandAttribute : System.Attribute
{
public string Command
{
get;
set;
}
public CommandAttribute(string textValue)
{
this.Command = textValue;
}
}
}
I know the answer is a bit late, to not abuse the SOLID principle, you may use interface or inheritance. In this example, I use inheritance because u may have other usages of "command" string.
public abstract class commandRepository {
string command ; // if there is no usage in other function class, you can get rid of it
public abstract void DoCommands();
}
public class ShowCommands:commandRepository
{
public ShowCommands (){
command ="Show commands"; // if there is no usage in other function class, you can get rid of it
}
public override void DoCommands(){
ProgramCommans.ShowAllCommands();
}
}
public class CloseWindow:commandRepository
{
public CloseWindow (){
command ="Close window"; // if there is no usage in other function class, you can get rid of it
}
public override void DoCommands(){
ProgramCommans.CloseWindow();
}
}
public class SwitchWindow:commandRepository
{
public SwitchWindow (){
command ="Switch window"; // if there is no usage in other function class, you can get rid of it
}
public override void DoCommands(){
ProgramCommans.SwitchWindow();
}
}
You can do this to refactor your switch statement:
var commands = new Dictionary<string, Action>()
{
{ "Show commands", () => ProgramCommans.ShowAllCommands() },
{ "Close window", () => ControlCommands.CloseWindow() },
{ "Switch window", () => ControlCommands.SwitchWindow() },
};
if (commands.ContainsKey(command))
{
commands[command].Invoke();
}
The main advantage to this approach is that you can change the "switch" at run-time.
Here's what you can do here. You can create an interface [ICommand] where you can place a common function [eg: Execute].
Then you just needs to initiate that member with appropriate type and call the Execute function. This might include more functions in the future and is thus extended.
Also, you can create a factory method where you can pass the parameter and get the appropriate class to work with.
Hope that helps.
If all the functions get the same parameters and return the same value, you can use a Dictionary along with delegates to map a string to a function(s). This method will allow you also to change in run time the switch - allowing external programs to extend the functionality of the program.
If the functions aren't the same, you could write wrappers - a proxy function that will get parameters as all other functions, and call the functions you want.