Pergunta

A minha pergunta está relacionada com o padrão de comando, onde temos o seguinte abstração (código C #):

public interface ICommand
{
    void Execute();
}

Vamos dar um comando de concreto simples, que visa excluir uma entidade de nosso aplicativo. Um exemplo Person, por exemplo.

Eu vou ter uma DeletePersonCommand, que implementa ICommand. Este comando precisa da Person para apagar como um parâmetro, a fim de excluí-lo quando o método Execute é chamado.

Qual é a melhor maneira de gerenciar os comandos parametrizados? Como passar parâmetros para os comandos, antes de executá-los?

Foi útil?

Solução

Você precisa associar os parâmetros com o objeto de comando, seja por construtor ou injeção setter (ou equivalente). Talvez algo como isto:

public class DeletePersonCommand: ICommand
{
     private Person personToDelete;
     public DeletePersonCommand(Person personToDelete)
     {
         this.personToDelete = personToDelete;
     }

     public void Execute()
     {
        doSomethingWith(personToDelete);
     }
}

Outras dicas

Passar os dados através de um construtor ou obras setter, mas requer o criador do comando de saber os dados do comando precisa ...

A idéia "contexto" é realmente bom, e eu estava trabalhando (um interno) estrutura que alavancou isso há algum tempo.

Se você configurar seu controlador (componentes de interface do usuário que interagem com o usuário, os comandos do usuário interpretar CLI, servlet interpretação parâmetros de entrada e dados de sessão, etc) para fornecer acesso chamada com os dados disponíveis, os comandos podem perguntar diretamente para os dados que quiser.

Eu realmente gosto da separação de uma configuração como esta permite. Pense em camadas da seguinte forma:

User Interface (GUI controls, CLI, etc)
    |
[syncs with/gets data]
    V
Controller / Presentation Model
    |                    ^
[executes]               |
    V                    |
Commands --------> [gets data by name]
    |
[updates]
    V
Domain Model

Se você fizer isso os mesmos comandos e modelo de apresentação "direito", pode ser usado com qualquer tipo de interface do usuário.

Tendo este um passo adiante, o "controlador" no exemplo acima é bastante genérico. Os controles de interface do usuário só precisa saber o nome do comando que vai chamar - eles (ou controlador) não precisa ter nenhum conhecimento de como criar esse comando ou quais dados esse comando precisa. Essa é a vantagem real aqui.

Por exemplo, você poderia manter o nome do comando a ser executado em um mapa. Sempre que o componente é "disparado" (geralmente um actionPerformed), o controlador procura o nome do comando, instancia-lo, chamadas de executar, e empurra-o sobre a pilha de desfazer (se você usar um).

Existem algumas opções:

Você poderia passar parâmetros por propriedades ou construtor.

Outra opção poderia ser:

interface ICommand<T>
{
    void Execute(T args);
}

E encapsular todos os parâmetros de comando em um objeto de valor.

Passe a pessoa quando você cria o objeto de comando:

ICommand command = new DeletePersonCommand(person);

para que quando você executar o comando, ele já sabe tudo o que ele precisa saber.

class DeletePersonCommand : ICommand
{
   private Person person;
   public DeletePersonCommand(Person person)
   {
      this.person = person;
   }

   public void Execute()
   {
      RealDelete(person);
   }
}

Meu implementação seria isso (usando o ICommand proposto por Juanma):

public class DeletePersonCommand: ICommand<Person>
{
    public DeletePersonCommand(IPersonService personService)
    {  
        this.personService = personService;
    }

    public void Execute(Person person)
    {
        this.personService.DeletePerson(person);
    }
}

IPersonService poderia ser uma IPersonRepository, depende em que "camada" seu comando é.

Neste caso, o que temos feito com objetos nosso comando é criar um objeto de contexto que é essencialmente um mapa. O mapa contém pares de valores de nomes onde as chaves são constantes e os valores são parâmetros que são usados ??pelas implementações de comando. Especialmente útil se você tem uma série de comandos em que os comandos posteriores dependem de mudanças de contexto de comandos anteriores.

Assim, o método real torna-se

void execute(Context ctx);

No construtor e armazenados como campos.

Você também vai querer eventualmente fazer suas ICommands serializável para a pilha ou arquivo persistência de desfazer.

Com base no padrão em C # / WPF a interface ICommand (System.Windows.Input.ICommand) é definido para ter um objecto como um parâmetro no executar, bem como o método CanExecute.

interface ICommand
            {
                bool CanExecute(object parameter);
                void Execute(object parameter);
            }

Isso permite que você defina o seu comando como um campo público estático, que é uma instância de seu objeto de comando personalizado que implementa ICommand.

public static ICommand DeleteCommand = new DeleteCommandInstance();

Desta forma, o objeto relevante, no seu caso uma pessoa, é passado quando executar é chamado. O método de execução pode, em seguida, converter o objeto e chamar o método Delete ().

public void Execute(object parameter)
            {
                person target = (person)parameter;
                target.Delete();
            } 

Você deve criar um CommandArgs objeto para conter os parâmetros que você deseja usar. Inject os CommandArgs objeto usando o construtor do objeto de comando.

DeletePersonCommand pode ter parâmetro em seu construtor ou métodos. DeletePersonCommand terá o Execute () e na execução pode verificar atributo que será passado por Getter / Setter anteriormente a chamada do Execute ().

Gostaria de acrescentar quaisquer argumentos necessários para o construtor de DeletePersonCommand. Então, quando Execute() é chamado, os parâmetros passados ??para o objeto em tempo de construção são utilizados.

Have "Pessoa" implementar algum tipo de interface de IDeletable, em seguida, fazer o comando tomar qualquer classe base ou interface suas entidades usar. Dessa forma, você pode fazer uma DeleteCommand, que tenta lançar a entidade a um IDeletable, e se isso funciona, chame .Delete

public class DeleteCommand : ICommand
{
   public void Execute(Entity entity)
   {
      IDeletable del = entity as IDeletable;
      if (del != null) del.Delete();
   }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top