How to decouple mode switching and commands

隐身守侯 提交于 2019-12-01 01:32:03

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).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!