Путаница в шаблонах команд C #

#c# #design-patterns

#c# #шаблоны проектирования

Вопрос:

Я, неосознанно, использовал шаблон команд, в котором клиент и вызывающий являются одинаковыми, и они вызывают команды напрямую. Посмотрев определение на DoFactory, я немного смущен.

Существуют отдельные команды. Это не изменилось с моего наивного понимания. Я предполагаю, что вызывающий просто вызывает все команды. Но какова цель получателя? Этого я не понимаю.

Если возможно, может кто-нибудь привести мне пример с несколькими командами и как приступить к реализации?

Комментарии:

1. Что именно вам непонятно? Отдельные обработчики команд или … ?

2. Я получаю отдельные команды. Это отдельная задача. Я не уверен, как «Приемник» вписывается в картину.

3. В моем предыдущем комментарии я имел в виду, что вы не можете понять, как работают обработчики команд (получатели в вашей формулировке)? Или вы имеете в виду события, вызванные обработчиками команд??

4. да, это именно то, в чем заключается мое замешательство.

Ответ №1:

Основная цель шаблона команд — отделить базовую (наиболее важную) операцию некоторых классов (конкретных классов команд) от их реального потребителя (CommandHandler ).

Итак, мы используем обходной путь, основанный на полиморфизме. Мы определяем абстрактный класс Command, у которого есть вызываемый метод void excecute(){} , поэтому он не становится жестким с каким-либо параметром метода или типом возвращаемого значения. Таким образом, конкретные классы команд могут реализовывать свою специфичную для класса реализацию внутри этого метода, и обработчик команд может свободно вызывать someCommandObject.execute(); без необходимости знать, что именно этот конкретный класс (достаточно быть экземпляром Command class ). Таким образом, вызовы и реализации в значительной степени разделены. В будущем вы можете легко ввести другой конкретный командный класс, который реализует void execute(){} , но обработчик команд может управлять этим вызовом someCommandObject.execute(); . В этом прелесть шаблона команд.

Это то же самое, что мы имеем Thread.run() в потоках Java и Task.Run() в потоках C #.

Хотя вы можете использовать приемник в соответствии с вашим удобством, он немного выбивается из общей картины командного шаблона. В вашем примере калькулятора имеет смысл иметь приемник, поскольку все конкретные классы команд могут ссылаться на него для выполнения своей основной операции( execute() ).

Вы можете увидеть несколько примеров здесь и там, где Приемник не использовался. Более чем идеально использовать приемник там, где это имеет смысл. Но не путайте это с реальным шаблоном команд. :))

Комментарии:

1. Хорошая работа 1! Сначала я подумал о CQS … 🙂

Ответ №2:

Участие Receiver в этом шаблоне на самом деле не важно, это просто для того, чтобы подчеркнуть тот факт, что конкретный объект command, замаскированный за очень простым Command интерфейсом, может сделать важную вещь, и даже эта вещь фактически обрабатывается другим object ( Receiver ), а не самим объектом command .

Действительно, суть шаблона команд заключается в том, чтобы инкапсулировать сложную задачу в минимальный интерфейс (просто метод void — void execute() — который не требует никаких параметров), чтобы одна или несколько задач могли быть легко сохранены и переданы куда угодно для последующего вызова an Invoker . Это очень удобно для Invoker , поскольку Command интерфейс минимален.

Наглядным примером Command является хорошо известный Runnable интерфейс на Java.

Комментарии:

1. Я подумал, что приемник можно было бы настроить для связи с различными системами. Например, нам нужно создать новую учетную запись пользователя, но создание нового пользователя предполагает взаимодействие с двумя системами. В этом случае будут созданы две команды… один для связи с system1, а второй для system2. Также будут созданы два приемника, один для command1, а другой для command2. Теперь, от имени клиента, вы вызываете две команды, и они будут знать, как связаться с соответствующей системой и выполнить задание. Правильно ли я думаю об этом?

2. Да, правильно. Таким образом, если вы хотите, после создания двух команд вы можете отложить выполнение, просто сохранить или передать их куда-нибудь, чтобы где-нибудь в подходящее время были выполнены команды и создан новый пользователь.

Ответ №3:

Простой пример шаблона проектирования команд в C#:

 using System;

interface ICommand {
    void Execute();
}

class Rifle : ICommand
{
    public void Execute()
    {
        Console.WriteLine("Rifle is in action : Pif! Paf!");
    }
}

class Cannon : ICommand
{
    public void Execute()
    {
        Console.WriteLine("Cannon is in action : Bum! Bam!");
    }
}

class Invoker
{
    private ICommand _command;
    public void SetCommand(ICommand command)
    {
        this._command = command;
    }

    public void Action()
    {
        _command.Execute();
    }
}

class Client
{
    static void Main()
    {

        ICommand command0 = new Rifle();
        ICommand command1 = new Cannon();

        ///////////////////////////////
        Invoker invoker = new Invoker();

        invoker.SetCommand(command0);
        invoker.Action();

        invoker.SetCommand(command1);
        invoker.Action();

        Console.ReadKey();
    }
}
/*output :
Rifle is in action : Pif! Paf!
Cannon is in action : Bum! Bam!
*/
 

Комментарии:

1. Вы что-то упускаете Receiver . Шаблон команд