如何解耦模式切换和命令

发布于 2024-11-26 12:23:00 字数 176 浏览 1 评论 0原文

如何将模式(通常由枚举表示)与其在命令中的实现及其关系解耦? 它们是描述模式开关(int、enum、string...)及其命令调用之间松散绑定的良好模式吗?我想通过配置添加模式,因此这必须(动态)易于扩展(无需编程)。我已经知道命令模式(C#/.Net 中的 ICommand)。它可能是命令词典及其相关模式编号,但是切换逻辑又如何呢?

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 a mode switch (int, enum, string, ...) and its command calls? I want to add modes via config, so this must be (dynamically) easy extendable (without programming). I already know the command pattern (ICommand in C#/.Net). It could be an Dictionary of Commands and their related mode number, but what about the switching logic?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

鸩远一方 2024-12-03 12:23:00

可以将上下文(切换决策、参数)与策略解耦
解决请求(输入)及其响应(输出)。

您可以使用例如泛型来通过一个代码库针对不同情况解决此问题。
例如,策略是由其输入和输出的类型以及评估条件来定义的:

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);
    }
}

上下文有不同的策略并询问策略的责任
(给定条件可以,可以计算出请求的结果)。

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;
    }
}

让我们举一个简单的例子,其中输入字符串需要解析为输出字符串
(如开关盒)。

1.定义您的操作(为了简化,这是一个(如您所见,每个方法都有自己的逻辑和关注点):

    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.定义一个条件来运行评估(类似于 CanExecute 的an ICommand):

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

...您甚至可以定义更多条件(例如,每个策略一个条件评估函数)
但我们这里只使用一个。

3.创建上下文所需的策略对象(这些对象象征着切换的不同路径,并为我们提供结果):

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

2。初始化您的上下文(代表带有输入的开关主体):

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

3.将它们连接到代码中(例如通过单击按钮执行“切换”):

    private void ButtonClick(object sender, RoutedEventArgs e)
    {
        var message = context.Evaluate(textBox1.Text);

        if (message != null) MessageBox.Show(message); // display result
    }

...就是这样。

上下文为您提供了正确的策略(可以执行正确的操作或给出正确的策略) “工具”你需要执行一些操作(例如ICommand)。

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文