C# - Обработка команд бота

285
12 ноября 2017, 14:15

Всем привет. Не могу понять. Как обработать команду? Допустим в string command у меня есть слово с командой. Допустим, что command = "скажи". У меня есть 100 классов, каждый из которых отвечает за нужную команду. Как вызвать код, который относится именно к этой команде т.е именно класс Say? Я думаю, что использовать switch или if else if неправильно. Что можно придумать в таком случае?

Answer 1

Для начала определимся с тем, какие структуры данных нам могут понадобится. Очвидно, у нас должны быть интерфейсы для команды и для оработчика команды.

// Команда и прямая реализация
public interface ICommand
{
    string CommandName { get;}
}
public class Command : ICommand
{
    public Command(string name)
    {
        CommandName = name;
    }
    public string CommandName { get; private set; }
}
// Обработчик команды
public interface ICommandProcessor
{
    void ProcessCommand(ICommand command);
    bool CanProcess(ICommand command);
}

Далее, нам нужны 2 простых обработчика. Вот они:

public class PrintCommandProc : ICommandProcessor
{
    public bool CanProcess(ICommand command)
    {
        return command.CommandName == "print";
    }
    public void ProcessCommand(ICommand command)
    {
        if (!CanProcess(command)) throw new ArgumentException(nameof(command));
        Console.WriteLine($"{command.CommandName} command processed");
    }
}
public class ReadCommandProc : ICommandProcessor
{
    public bool CanProcess(ICommand command)
    {
        return command.CommandName == "read";
    }
    public void ProcessCommand(ICommand command)
    {
        if (!CanProcess(command)) throw new ArgumentException(nameof(command));
        Console.WriteLine($"{command.CommandName} command processed");
    }
}

Что делать дальше: так как вы не уточнили, могут ли одну и ту же команду обрабатывать несколько обработчиков, я покажу 2 подхода, которые немного отличаются. Причем вы в любой момент сможете заменить один подход другом.

Итак, вариант 1, случай, когда несколько обработчиков МОГУТ обрабатывать одну и ту же команду. Для этого создадим композитный обработчик, который будет держать список всех доступых обработчиков:

public class CompositeCommandProcessor : ICommandProcessor
{
    ICommandProcessor[] _commandProcs;
    public CompositeCommandProcessor(params ICommandProcessor[] commandProcs)
    {
        _commandProcs = commandProcs;
    }
    public bool CanProcess(ICommand command)
    {
        return _commandProcs.Any(c=>c.CanProcess(command));
    }
    public void ProcessCommand(ICommand command)
    {
        if (!CanProcess(command)) throw new ArgumentException(nameof(command));
        foreach (var cp in _commandProcs.Where(c=>c.CanProcess(command)))
            cp.ProcessCommand(command);
    }
}

Как видите, эту команду можно инициализировать любым набором обработчиков, а также каждая команда проходит через каждый обработчик. Таким образом, для одной и той же команды можно зарегистрировать несколько обработчиков.

Использование:

var commandProc = new CompositeCommandProcessor(new PrintCommandProc(), new ReadCommandProc());
var printCommand = new Command("print");
var readCommand = new Command("read");
if (commandProc.CanProcess(printCommand)) commandProc.ProcessCommand(printCommand);
if (commandProc.CanProcess(readCommand)) commandProc.ProcessCommand(readCommand);

Вариант 2. Если для 1 команды возможен только 1 обработчик. Все, что надо сделать - это написать другой вариант композитного обработчика.

public class CompositeCommandProcessorDictionary : ICommandProcessor
{
    Dictionary<string, ICommandProcessor> _processors = new Dictionary<string, ICommandProcessor>();
    public void Register(string commandName, ICommandProcessor processor)
    {
        _processors.Add(commandName, processor);
    }
    public bool CanProcess(ICommand command)
    {
        return _processors.ContainsKey(command.CommandName);
    }
    public void ProcessCommand(ICommand command)
    {
        if (!CanProcess(command)) throw new ArgumentException(nameof(command));
        _processors[command.CommandName].ProcessCommand(command);
    }
}

Этот вариант основан на словаре, потому не получится заркгистрировать 2 обработчика на команду. Как использовать:

var commandProcDict = new CompositeCommandProcessorDictionary();
commandProcDict.Register("print", new PrintCommandProc());
commandProcDict.Register("read", new ReadCommandProc());
var printCommand = new Command("print");
var readCommand = new Command("read");
if (commandProcDict.CanProcess(printCommand)) commandProcDict.ProcessCommand(printCommand);
if (commandProcDict.CanProcess(readCommand)) commandProcDict.ProcessCommand(readCommand);   
READ ALSO
Почему не парсится ajax-ответ?

Почему не парсится ajax-ответ?

Помогите пожалуйста понять почему такой скрипт выводит результат в консоль:

397
js. Поиск элементов по name

js. Поиск элементов по name

Есть обычная html форма, типа

337
Сложный слайдер slick

Сложный слайдер slick

Есть задание сделать слайдерВот такого типа

312