Как да отделите превключването на режими и командите

Как да отделя режим (обикновено изразен чрез enums) от неговото изпълнение в команди и тяхната връзка? Дали това е добър модел, описващ разхлабеното свързване между превключвател на режим (int, enum, string, ...) и неговите командни извиквания? Искам да добавя режими чрез config, така че това трябва да бъде (динамично) лесно разширимо (без програмиране). Вече знам модела на командите (ICommand в C#/.Net). Може да е речник на командите и свързания с тях номер на режим, но какво да кажем за логиката на превключване?


person Beachwalker    schedule 25.07.2011    source източник


Отговори (1)


Възможно е да се отдели контекстът (решение за превключване, параметри) от стратегията за решаване на заявката (вход) и нейния отговор (изход).

Можете да използвате напр. генерични средства за решаване на този проблем за различни случаи с една кодова база. Например стратегията се определя от нейния вид вход и изход и условие за оценка:

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

person Beachwalker    schedule 27.07.2011