Verificando-se a defini¸c˜ao deste padr˜ao de projeto, o padr˜ao Command tem por ob- jetivo principal: “Encapsular uma requisi¸c˜ao como um objeto, permitindo que clientes parametrizem diferentes requisi¸c˜oes, filas ou requisi¸c˜oes de log, e suportar opera¸c˜oes rever- s´ıveis” [Gamma et al., 1994]. Desta forma ´e possivel utilizar v´arios comandos diferentes, de forma que exista um desacoplamento entre quem realiza a requisi¸c˜ao de uma a¸c˜ao e o objeto que, de fato, realiza a referida a¸c˜ao. Assim ´e poss´ıvel realizar um a¸c˜ao sem precisar saber a a¸c˜ao realizada nem o recebedor da a¸c˜ao.
Padrão Command 124
onde seja necess´ario parametrizar objetos em rela¸c˜ao a a¸c˜oes que precisem ser realizadas. Tamb´em pode ser aplicado a sistemas em que seja importante especificar listas de comandos e execut´a-los em momentos diferentes. Uma outra caracter´ıstica importante do padr˜ao Command ´e a possibilidade de suportar opera¸c˜oes revers´ıveis, de tal forma que uma a¸c˜ao realizada por ´ultimo possa ser desfeita, assim como suportar registro de a¸c˜oes, para que seja poss´ıvel recuperar um estado do sistema se houver uma s´ubita falha, por exemplo.
5.3.1
Exemplo utilizado para este padr˜ao
Para ilustrar a utiliza¸c˜ao do padr˜ao de projetos Command, ´e utilizado um exemplo retirado de [Freeman et al., 2004], no qual ´e implementado um controlador que automatiza diversos dispositivos de uma casa. E um controlador universal program´´ avel que pode gerenciar o funcionamento de equipamentos, assim como permitir opera¸c˜oes revers´ıveis, semelhante ao que ´e determinado pela defini¸c˜ao deste padr˜ao de projeto. Este controle de automa¸c˜ao residencial pode ser programado para que cada bot˜ao seja configurado a um tipo de a¸c˜ao, de acordo com a necessidade do cliente.
Neste exemplo simplificado, as a¸c˜oes do controle est˜ao voltadas para dois principais elementos control´aveis: As luzes do ambiente e o ventilador de teto da casa. Mas para cada um desses dispositivos existe uma s´erie de comandos, como por exemplo, ligar luz, desligar luz, etc. Cada diferente comando ´e modelado como sendo um objeto que passa a encapsular um m´etodo chamado execute(), respons´avel por executar o referido comando. A figura 5.4 mostra com mais detalhes um diagrama de classes para este exemplo. As classes sobrepostas possuem implementa¸c˜ao similar `as classes que as sobrep˜oem.
Verifica-se ao observar a figura 5.4 que nove (9) comandos foram implementados, ou seja, nove classes cujas instˆancias devem encapsular uma determinada a¸c˜ao foram modeladas. Dessas nove, quatro (4) comandos s˜ao espec´ıficos para as luzes da casa e quatro (4) outros destinam-se a controlar o ventilador de teto. O comando restante n˜ao realiza nenhuma a¸c˜ao. Todas as classes cujas instˆancias devem encapsular um comando est˜ao implementando uma interface em comum, de n´ıvel abstrato mais elevado, chamada Command, que possui os m´etodos para executar a a¸c˜ao e desfazer a ´ultima a¸c˜ao realizada.
Figura 5.4: Diagrama de classes do exemplo para o padr˜ao Command.
5.3.2
Compara¸c˜ao das implementa¸c˜oes em Java e ooErlang
Para cada um dos dispositivos comandados pelo controlador modelado no sistema ex- posto no presente exemplo, ´e implementada uma classe que armazena os dados referentes aos dispositivos. No caso das luzes da casa, a classe criada se chama Light, e no caso dos ventiladores de teto, chama-se CeilingFan. Assim sendo, cada uma das classes que imple- menta a interface Command, atua em um dos dispositivos controlados na casa, podendo estar relacionado a uma luz ambiente ou a um dos ventiladores de teto da residˆencia.
Padrão Command 126
mand, LightOffCommand, DimmerLightOnCommand, DimmerLightOffCommand. Em re- la¸c˜ao aos comandos que controlam os ventiladores de teto da casa, temos os comandos CeilingFanHighCommand, CeilingFanLowCommand, CeilingFanMediumCommand e Cei- lingFanOffCommand. O nome de cada classe est´a relacionado com o comando da mesma. Para as luzes os comandos s˜ao de ligar, desligar e controlar a intensidade de luz. Para os ventiladores de teto ´e poss´ıvel ajustar para intensidade alta, m´edia, baixa ou desligado.
A classe LightOnCommand, implementada em Java e ooErlang est´a mostrada nos c´o- digos 5.3.1 e 5.3.2 respectivamente. Esta classe possui dois atributos principais, light (re- ferente `a classe Light) e level, que armazena o n´ıvel de intensidade de luz. Como esta ´
e uma das classes que implementa a interface Command, s˜ao implementados os m´etodos execute() para realizar a execu¸c˜ao do comando ligar luz e o m´etodo undo que retorna ao n´ıvel anterior de intensidade de luz.
1 public class LightOnCommand implements Command { 2 Light light;
3 int level;
4 public LightOnCommand(Light light) { 5 this.light = light;
6 }
7
8 public void execute() { 9 level = light.getLevel(); 10 light.on();
11 } 12
13 public void undo() { 14 light.dim(level); 15 }
16 }
C´odigo 5.3.1: Classe LightOnCommand em Java
A utiliza¸c˜ao do m´etodo que possibilita opera¸c˜oes revers´ıveis (undo) ´e possivel pelo fato de que, sempre ao se utilizar o comando para ligar a luz de determinado ambiente na residˆencia, o n´ıvel atual de luz ´e armazenado no atributo level. Se, porventura, esse n´ıvel mudar na utiliza¸c˜ao de outro comando e, seja necess´ario retornar ao n´ıvel anterior, este n´ıvel (que j´a vai estar armazenado) poder´a ser recuperado. Todos os comandos implementados para este exemplo funcionam de forma semelhante. Em rela¸c˜ao aos comandos que tratam do ventilador de teto, o comando para desfazer uma opera¸c˜ao armazena a ´ultima intensidade
1 -class(lightOnCommand). 2 -implements(command).
3 -export([new/1, execute/0, undo/0]). 4 -constructor([new/1]). 5 6 attributes. 7 8 Light; 9 Level. 10 11 methods. 12 13 new(Light) -> 14 self::Light = Light. 15 16 execute() -> 17 Temp = self::Light, 18 self::Level = Temp::get_level(), 19 Temp::on(). 20 21 undo() -> 22 Temp = self::Light, 23 Temp::dim(self::Level).
C´odigo 5.3.2: Classe LightOnCommand em ooErlang de ventila¸c˜ao configurada.
A classe que armazena as caracter´ısticas dos dispositivos de luz da residˆencia est˜ao armazenadas na classe Light. ´E nesta classe que armazena-se o n´ıvel atual de luz confi- gurada. Nos objetos que funcionam como comando, o n´ıvel de luz utilizado ´e necessaria- mente recuperado da classe Light. Sempre que for feita uma nova instˆancia da classe Light, e for utilizado um comando de ligar luz, o n´ıvel de intensidade da luz j´a ´e inicializado automaticamente. Os c´odigos mostrados em 5.3.3 e 5.3.4 mostram, respectivamente, as implementa¸c˜oes em Java e ooErlang da classe Light
Conforme pode ser observado, a classe Light possui um construtor, um m´etodo que permite ligar a luz, outro m´etodo que permite desligar a luz, assim como um terceiro m´etodo que possibilita modificar a intensidade da luz. Estes m´etodos n˜ao s˜ao utilizados diretamente pelo usu´ario, e sim por meio do controle remoto. Este controle remoto pode ser configurado de acordo com os comandos implementados para controle de luz e circula¸c˜ao de ar. E ´e por meio dos objetos que funcionam como se fossem os pr´oprio comandos que os m´etodos na classe Light s˜ao utilizados.
Padrão Command 128
1 public class Light { 2 String location; 3 int level;
4
5 public Light(String location) { 6 this.location = location;
7 }
8
9 public void on() { 10 level = 100;
11 System.out.println("Light is on"); 12 }
13
14 public void off() { 15 level = 0;
16 System.out.println("Light is off"); 17 }
18
19 public void dim(int level) { 20 this.level = level; 21 if (level == 0) {
22 off();
23 }
24 else {
25 System.out.println("Light is dimmed to " + level + "%");
26 }
27 } 28
29 public int getLevel() { 30 return level; 31 }
32 }
C´odigo 5.3.3: Classe Light em Java
A classe RemoteControlWithUndo ´e a classe que implementa as caracter´ısticas pr´oprias do controle remoto que passa a possuir os comandos j´a definidos pelo usu´ario. A instˆancia de um objeto desta classe vai ser o controle remoto utilizado para, inicialmente configurar onde cada comando ´e utilizado e, posteriormente, ser a ferramenta que permite executar os comandos nele inseridos. Os c´odigos mostrados em 5.3.5 e 5.3.6 apresentam os detalhes principais das implementa¸c˜oes em Java e ooErlang, nesta ordem, da classe RemoteCon- trolWithUndo.
Observa-se que a classe RemoteControlWithUndo possui trˆes (3) atributos principais. Os dois primeiros s˜ao duas listas de sete (7) elementos. Cada lista pertence a uma classe de comandos. Uma lista para os comandos que ligam certo dispositivo e outra lista para os comandos que desligam. O terceiro atributo refere-se ao comando undo, ou desfazer.
1 -class(light).
2 -export([new/1, on/0, off/0, dim/1, get_level/0]). 3 -constructor([new/1]). 4 5 attributes. 6 7 Location; 8 Level. 9 10 methods. 11 12 new(Location) -> 13 self::Location = Location. 14 15 on() -> 16 self::Level = 100, 17 io:format("Light is on ~n"). 18 19 off() -> 20 self::Level = 0, 21 io:format("Light is off ~n"). 22 23 dim(Level) -> 24 self::Level = Level, 25 if 26 (Level == 0) -> 27 off(); 28 true ->
29 io:format("Light is dimmed to ~p % ~n", [Level]) 30 end.
31
32 get_level() ->
33 self::Level.
C´odigo 5.3.4: Classe Light em ooErlang
O construtor desta classe (RemoteControlWithUndo, n˜ao mostrado nas implementa¸c˜oes) inicializa todos os “slots” de mem´oria com o comando NoCommand. Isto simula um controle remoto com as configura¸c˜oes de f´abrica.
O m´etodo setCommand da classe RemoteControlWithUndo ´e abstra´ıdo dos fontes mos- trados em 5.3.5 e 5.3.6, e tˆem como objetivo, o de configurar cada slot do controle remoto com um comando espec´ıfico. Os m´etodos onButtonWasPushed e offButtonWasPushed rea- lizam a execu¸c˜ao do comando que foi previamente configurado para o correspondente slot (passado por parˆametro). Se n˜ao houver comando configurado, nenhuma a¸c˜ao ´e realizada, de acordo com a implementa¸c˜ao da classe NoCommand.
Padrão Command 130
1 public class RemoteControlWithUndo { 2 Command[] onCommands;
3 Command[] offCommands; 4 Command undoCommand; 5
6 public void onButtonWasPushed(int slot) { 7 onCommands[slot].execute();
8 undoCommand = onCommands[slot];
9 }
10
11 public void offButtonWasPushed(int slot) { 12 offCommands[slot].execute();
13 undoCommand = offCommands[slot]; 14 }
15
16 public void undoButtonWasPushed() { 17 undoCommand.undo();
18 }
C´odigo 5.3.5: Classe RemoteControlWithUndo em Java
1 -class(remoteControlWithUndo).
2 -export([new/0, set_command/3, on_button_was_pushed/1, off_button_was_pushed/1]). 3 -export([undo_button_was_pushed/0, to_string/0]). 4 -constructor([new/0]). 5 6 attributes. 7 8 OnCommands; 9 OffCommands; 10 UndoCommand. 11 12 methods. 13 14 on_button_was_pushed(Slot) ->
15 Temp = aux_get_element(Slot, self::OnCommands), 16 Temp::execute(),
17 self::UndoCommand = Temp. 18
19 off_button_was_pushed(Slot) ->
20 Temp = aux_get_element(Slot, self::OffCommands), 21 Temp::execute(), 22 self::UndoCommand = Temp. 23 24 undo_button_was_pushed() -> 25 Temp = self::UndoCommand, 26 Temp::undo().
C´odigo 5.3.6: Classe RemoteControlWithUndo em ooErlang
e 5.3.8 mostram os detalhes relevantes da implementa¸c˜ao da classe principal deste exemplo em Java e ooErlang, respectivamente.
1 public class RemoteLoader { 2
3 public static void main(String[] args) { 4 RemoteControlWithUndo remoteControl =
5 new RemoteControlWithUndo(); 6
7 Light livingRoomLight = new Light("Living Room"); 8 9 LightOnCommand livingRoomLightOn = 10 new LightOnCommand(livingRoomLight); 11 LightOffCommand livingRoomLightOff = 12 new LightOffCommand(livingRoomLight); 13 14 remoteControl.setCommand(0, livingRoomLightOn, 15 livingRoomLightOff); 16 17 remoteControl.onButtonWasPushed(0); 18 remoteControl.offButtonWasPushed(0); 19 System.out.println(remoteControl); 20 remoteControl.undoButtonWasPushed(); 21 remoteControl.offButtonWasPushed(0); 22 remoteControl.onButtonWasPushed(0); 23 System.out.println(remoteControl); 24 remoteControl.undoButtonWasPushed(); 25 } 26 }
C´odigo 5.3.7: Classe principal RemoteLoader em Java
O m´etodo principal da classe RemoteLoader (main), inicialmente instancia um objeto da classe RemoteControlWithUndo, para ser o objeto representante do controle remoto em si. Depois ´e instanciado um objeto do tipo Light, para que possa haver controle das luzes de determinado ambiente. Em seguida s˜ao instanciados dois objetos que funcionam como comandos de controle das luzes (LightOnCommand e LightOffCommand). Por ´ultimo estes dois comandos s˜ao configurados nas posi¸c˜oes iniciais do controle.
Ap´os as configura¸c˜oes, os bot˜oes s˜ao testados, e entre os testes dos bot˜oes, tamb´em ´e impresso o status atual do controle remoto, ou seja, quais comados est˜ao configurados em quais bot˜oes. O bot˜ao respons´avel por desfazer uma a¸c˜ao (undo) tamb´em ´e testado, para verificar se sua execu¸c˜ao ocorre de acordo com o esperado. As figuras mostradas em 5.5 e 5.6 mostram com detalhes o resultado dos testes realizados em Java e ooErlang, nesta sequˆencia.
Padrão Command 132 1 -class(remoteLoader). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 RemoteControl = remoteControlWithUndo::new(), 8
9 LivingRoomLight = light::new("Living Room"), 10
11 LivingRoomLightOn = lightOnCommand::new(LivingRoomLight), 12
13 LivingRoomLightOff = lightOffCommand::new(LivingRoomLight), 14
15 RemoteControl::set_command(0, LivingRoomLightOn, LivingRoomLightOff), 16 17 RemoteControl::on_button_was_pushed(0), 18 RemoteControl::off_button_was_pushed(0), 19 RemoteControl::to_string(), 20 RemoteControl::undo_button_was_pushed(), 21 RemoteControl::off_button_was_pushed(0), 22 RemoteControl::on_button_was_pushed(0), 23 RemoteControl::to_string(), 24 RemoteControl::undo_button_was_pushed().
C´odigo 5.3.8: Classe principal RemoteLoader em ooErlang
Verifica-se que, ao serem pressionados os bot˜oes relacionados com a a¸c˜ao de ligar e desligar as luzes de determinado ambiente da residˆencia, as mensagens de retorno esperadas s˜ao mostradas, comprovando que a execu¸c˜ao realizou-se da forma como estava prevista. Assim, de acordo com a defini¸c˜ao do padr˜ao de projetos Command, tamb´em ´e possivel verificar quais s˜ao os comandos atualmente configurados no controle remoto, em todas as posi¸c˜oes v´alidas, e tamb´em na posi¸c˜ao referente ao comando de desfazer uma a¸c˜ao (undo). Comprovou-se, utilizando-se de uma aplica¸c˜ao implementada em Java que uma imple- menta¸c˜ao desta mesma aplica¸c˜ao em ooErlang resulta no mesmo comportamento de sa´ıda. A extens˜ao do Erlang para orienta¸c˜ao a objetos permite que sejam utilizados sistemas com as principais caracter´ısticas da utiliza¸c˜ao do padr˜ao de projetos Command. Isto significa dizer que o ooErlang permite que objetos sejam utilizados para encapsular a¸c˜oes em um sistema, de tal forma que exista um conjunto de objetos funcionando como m´etodos de comando para determinada situa¸c˜ao.
No exemplo pr´atico demonstrado, ´e modelado um sistema de automa¸c˜ao residencial. As a¸c˜oes de comando de todo o sistema s˜ao implementadas por meio de um controle
Figura 5.5: Execu¸c˜ao do exemplo para o padr˜ao Command em Java.
residencial. Este controle possui dois pares de bot˜oes para cada dispositivo da casa, um para ligar e outro para desligar. Al´em disso, existe um bot˜ao geral com o simples objetivo de desfazer uma ´ultima a¸c˜ao realizada. Desta forma todas as caracter´ısticas do padr˜ao Command foram de fato implementadas.
Verifica-se que, com a utiliza¸c˜ao do padr˜ao de projetos Command, ´e possivel desacoplar o objeto que invoca um comando do objeto que realiza a a¸c˜ao especificada. Como cada comando ´e modelado de forma a ser um objeto, os comandos podem ser manipulados e estendidos como qualquer outro objeto. Em situa¸c˜oes onde seja necess´ario incluir novos comandos, o padr˜ao Command mostra-se bastante vers´atil e flex´ıvel, pois n˜ao ´e necess´ario modificar nenhum c´odigo-fonte j´a existente para relizar esta a¸c˜ao, sendo necess´ario apenas criar um novo objeto com esta finalidade.
Padrão Interpreter 134
Figura 5.6: Execu¸c˜ao do exemplo para o padr˜ao Command em ooErlang.