Refactor long switch statement

前端 未结 6 1437
我寻月下人不归
我寻月下人不归 2020-12-06 06:09

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         


        
6条回答
  •  旧时难觅i
    2020-12-06 06:27

    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 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 rules;
        public WindowRuleBuilder(IList rules = null) =>
            rules = rules ?? new List();
    
        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.

提交回复
热议问题