How to decouple mode switching and commands

后端 未结 1 1138
伪装坚强ぢ
伪装坚强ぢ 2021-01-07 08:15

How to decouple a Mode (normally expressed by enums) from its implementation in commands and their relationship? Is their a good pattern describing the loose binding between

相关标签:
1条回答
  • 2021-01-07 08:33

    It is possible to decouple context (switching descission, parameters) from the strategy to solve the request (input) and its response (output).

    You could use e.g. generics to solve this problem for different cases with one code base. For example the strategy is defined by its kind of input and output and a condition to evaluate:

    public class Strategy<TInput, TOutput>
    {
        public Predicate<TInput> Condition { get; private set; }
        public Func<TInput, TOutput> Result { get; private set; }
    
        public Strategy(Predicate<TInput> condition, Func<TInput, TOutput> result)
        {
            Condition = condition;
            Result = result;
        }
    
        public TOutput Evaluate(TInput input)
        {
            return Condition(input) ? Result(input) : default(TOutput);
        }
    }
    

    The context has different strategies and asks the strategies for their responsibility (given conditions are ok, can calculate the result for an request).

    public class Context<TInput, TOutput>
    {
        private List<Strategy<TInput, TOutput>> Strategies { get; set; }
    
        public Context(params Strategy<TInput, TOutput>[] strategies)
        {
            Strategies = strategies.ToList();
        }
    
        public TOutput Evaluate(TInput input)
        {
            var result = default(TOutput);
            foreach (var strategy in Strategies)
            {
                result = strategy.Evaluate(input);
    
                if (!Equals(result, default(TOutput)))
                    break;
            }
    
            return result;
        }
    }
    

    Let's take a simple example where an input string needs to be resolved to an output string (like a switch case).

    1. Define your actions (for simplification this is an (as you can see, every Method has its own logic and concern):

        private static string Move(string s)
        {
            if (s == "move")
                return "doMove"; // here could be some more action...
            return null;
        }
    
        private static string Query(string s)
        {
            if (s == "point")
                return "queryPoint"; // here could be some more action...
            return null;
        }
    

    2. Define a condition to run the evaluation (lika a CanExecute of an ICommand):

        private static bool Condition(string s)
        {
            return !string.IsNullOrEmpty(s); // could eval different states, values
        }
    

    ... you could even define more conditions (e.g. one condition eval function per strategy) but we use only one here.

    3. Create strategy objects required by the context (these symbolize the different paths of the switch and they give us the result):

     var navigate = new Strategy<string, string>(Condition, Move);
     var query = new Strategy<string, string>(Condition, Query);
    

    2. Initialize your context (represents the switch body with the input):

     var strategies = new List<Strategy<string, string>> {navigate, query};
     var context = new Context<string, string>(strategies.ToArray());
    

    3. Wire them into the code (e.g. execute "switch" by a button click):

        private void ButtonClick(object sender, RoutedEventArgs e)
        {
            var message = context.Evaluate(textBox1.Text);
    
            if (message != null) MessageBox.Show(message); // display result
        }
    

    ... that's it.

    The context gives you the right strategy (can do the right actions or give the "tools" you need to do some actions (e.g. an ICommand).

    0 讨论(0)
提交回复
热议问题