O padrão Command é um bicho estranho no contexto da programação orientada a objeto. Diferentemente da maioria dos objetos, um objeto command representa um verbo, em vez de um substantivo. Isso é um pouco menos estranho em uma linguagem como JavaScript, na qual as funções são realmente um tipo de objeto, mas o sentido clássico do padrão Command é ainda diferente de uma função.
Outro padrão de projeto
Este artigo segue uma série sobre padrões de projeto em JavaScript. Para ver os outros que já foram destacados e os esperados no futuros, confira a lista logo abaixo.
Série padrão de projeto de software – JavaScript
- Padrão Singleton
- Padrão Bridge
- Padrão Composite
- Padrão Facade
- Padrão Adapter
- Padrão Decorator
- Padrão Factory – Parte 01
- Padrão Factory – Parte 02
- Padrão Proxy
- Padrão Observer
O que é o padrão Command?
Como eu disse, um objeto command é de fato representativo de um verbo, em vez de um substantivo como a maioria dos objetos é. Outra maneira de dizer é que o padrão Command é uma maneira de encapsular a invocação de um método. É simplesmente uma camada de abstração entre o objeto que implementa um método e o objeto que deseja invocar esse método. Isso é muito poderoso no mundo da interface do usuário. Como de costume, isso irá provavelmente fazer um pouco mais de sentido com um exemplo de código.
Vamos supor que estamos fazendo um aplicativo de despertador, provavelmente muito semelhante ao do seu celular. Ele lista vários alarmes que você pode ter, e, no caso desse aplicativo, esse número pode estar em qualquer lugar entre zero e infinito, ao contrário dos meros 4 alarmes que meu pequeno telefone me oferece. Para esse aplicativo, nós iremos precisar de um objeto [code]Alarm que contém o status e as configurações do alarme. Neste momento, estamos apenas preocupados com alguns métodos específicos que ele implementa: [code]enable, [code]disable, [code]reset, e [code]set.
Para cada um desses métodos, vamos criar um objeto command para encapsulá-lo:
var EnableAlarm = function(alarm) {
this.alarm = alarm;
}
EnableAlarm.prototype.execute = function () {
this.alarm.enable();
}
var DisableAlarm = function(alarm) {
this.alarm = alarm;
}
DisableAlarm.prototype.execute = function () {
this.alarm.disable();
}
var ResetAlarm = function(alarm) {
this.alarm = alarm;
}
ResetAlarm.prototype.execute = function () {
this.alarm.reset();
}
var SetAlarm = function(alarm) {
this.alarm = alarm;
}
SetAlarm.prototype.execute = function () {
this.alarm.set();
}
Observe que cada objeto Command acompanha uma interface. Neste exemplo, a interface define apenas um método e cada um desses métodos chama apenas uma função. Se esse for o caso, você provavelmente pode ignorar fazer coisas como essas e usar apenas funções de callback, o que é, essencialmente, utilizar as funções como os objetos Command próprios, no caso de você ainda estar usando o padrão Command, mas você não percebe porque ela sempre tem sido chamada de função callback.
Agora vamos precisar usar os objetos Command. Estaremos os entregando para um objeto de interface do usuário que adiciona um botão na tela e, quando o botão é clicado, ele executa o método [code]execute no objeto Command que foi passado para ele. Claro que ele sabe quais métodos invocar, pois todos os comandos usam a mesma interface.
var alarms = [/* array of alarms */],
i = 0, len = alarms.length;
for (; i < len; i++) {
var enable_alarm = new EnableAlarm(alarms[i]),
disable_alarm = new DisableAlarm(alarms[i]),
reset_alarm = new ResetAlarm(alarms[i]),
set_alarm = new SetAlarm;
new Button('enable', enable_alarm);
new Button('disable', disable_alarm);
new Button('reset', reset_alarm);
new Button('set', set_alarm);
}
As quatro partes do padrão Command
O padrão Command tem quatro partes principais que o compõem. A primeira e mais óbvia é o objeto Command. Agora você sabe o que é isso. As outras três partes são o client, invoker, e receiver. O client é o código que cria o objeto Command e passa para o Invoker. Isso significaria que no trecho de código anterior, o código dentro do [code]for loop é o client. O invoker é o objeto que utiliza o objeto Command e chama seu(s) método(s). Finalmente, o receptor é o objeto no qual o comando está fazendo chamadas, que nesse caso são os [code]Alarme.
Sem todos essas quatro partes, não é o padrão Command. Sabendo disso, você pode pensar que o que eu disse sobre uma função de callback sendo considerada para o padrão Command está errado, certo? Bem, eu discordo um pouco. Acredito que o JavaScript seja simplesmente fantástico o suficiente para ter feito funções serem capazes de operar como seus próprios objetos Command. Todas as quatro partes estão lá, acontece que o objeto Command está contido dentro do receptor. O único argumento que eu poderia ver como válido é que não há mais outro nível de abstração. Veja só, o cliente agora tem que saber o que é o nome da função no receptor, ao passo que, anteriormente, o cliente não precisava saber disso, no entanto, eles precisavam conhecer os objetos Command. Você perde a abstração e, portanto, um pouco de modularidade, mas ganha mais simplicidade de entender e código mais rápido.
Se você gostaria de ver um exemplo de algo que é um acordo entre o exemplo acima do objeto Command e apenas usando callbacks, então dê uma olhada abaixo:
var makeEnableCommand = function (alarm) {
return function() {
alarm.enable();
}
}
var makeDisableCommand = function (alarm) {
return function() {
alarm.disable();
}
}
var makeResetCommand = function (alarm) {
return function() {
alarm.reset();
}
}
var makeSetCommand = function (alarm) {
return function() {
alarm.set();
}
}
Em vez de criar um objeto que tem um método a ser chamado, só crie uma função que seja usada como um callback. É, acima de tudo, inútil, a menos que ele vá realmente fazer mais do que apenas chamar uma função específica. Também pode ser utilizada como um meio para tornar o seu código um pouco mais seguro. Assumindo que o invoker seja um código de terceiro, poderia, eventualmente, fazer alterações ao método do receptor por adicionar, alterar ou anular as suas propriedades. Isso é, no entanto, extremamente improvável.
Eu te ordeno terminar isto
Isso é tudo que eu tenho. Eu não mencionei que o padrão Command também pode ser usado como um meio para criar a capacidade de desfazer as ações, mas eu não quero prolongar muito isso aqui, por isso não vou mostrar te mostrar como fazer isso. Além de usar callbacks simples, o padrão Command tem uso bastante limitado. Há momentos em que ele pode vir a ser muito útil, e você vai se sentir muito especial por ter utilizado um padrão de projeto de software.
?
Texto original disponível em http://www.joezimjs.com/javascript/javascript-design-patterns-command/







