.NET
- O padrão de projeto Command
![]() |
O padrão de projeto (Design Pattern) Command é um padrão comportamental cuja intenção é encapsular uma solicitação como um objeto e desta forma permitir que você parametrize clientes com diferentes solicitações, enfileire ou registre(log) solicitações e suporte operações que podem ser desfeitas.(GoF) |
Podemos dizer que o padrão Command tem como função principal encapsular a invocações a objetos.
Nota: Padrões de projeto comportamentais são padrões que tratam das interações e divisões de responsabilidades entre as classes ou objetos.
O diagrama de classes para o padrão Command é mostrado na figura abaixo:
Classes/Objetos
participantes do padrão:
|
|
|
O mesmo diagrama usando os nomes originais:
![]() |
Em tempo de execução o objeto Invoker(Chamador) chama o método execute() do objeto Command que delega ao método action() do objeto receiver que executará a operação.
![]() |
Vantagens em usar o padrão Command:
Quando usar o padrão Command ?
Implementando o padrão de projeto Command
Para implementar um Command temos que fazer o seguinte:
Para implementar o padrão Observer eu vou usar o seguinte cenário:
Imagine um robo sendo controlado à distância como o robo Curiosity que está em Marte.
Neste cenário os comandos ditam o movimento do robô e também são usados para realizar operações como recolher amostras da superfície de Marte.
Neste caso o Receptor seria o robô e o Chamador seria um sistema de software programado executado dentro do robô.
O Cliente seria controlado pelos engenheiros aqui na Terra que poderia criar uma fila de comandos. O robô também inclui uma função desfazer de forma a poder reverter alguns comandos conforme necessário.
Neste cenário iremos ter as seguintes classes:
O Diagrama de classes gerado é visto abaixo:
![]() |
Implementando o padrão Command
Vamos agora criar as classes e verificar o seu funcionamento.
Eu vou usar o Visual Studio 2012 Express Edition e criar uma aplicação Console chamada PadraoProjetoCommand;
Obs: Estou disponibilizando também o código para VB .NET criado no Visual Studio 2012 Express Edition
No menu Project clique em Add Class e informe o nome RoboCommand.cs/RoboCommand.vb e a seguir digite o código da classe conforme abaixo:
namespace PadraoProjetoCommand
{
public abstract class RoboCommand
{
protected Robo _robo;
public RoboCommand(Robo robo)
{
_robo = robo;
}
public abstract void Executar();
public abstract void Desfazer();
}
}
|
Public MustInherit Class RoboCommand
Protected _robo As Robo
Public Sub New(robo As Robo)
_robo = robo
End Sub
Public MustOverride Sub Executar()
Public MustOverride Sub Desfazer()
End Class
|
| C# | VB .NET |
Vamos agora criar três comandos que o robô será capaz de executar.
1- MoverCommand - O primeiro comando irá permitir
que o robô seja movido para a frente.Se o valor é negativo, o
robô se mover para trás.
2- RotacionarCommand - O segundo comando irá permitir
que o robô para ser rotacionado de um número de graus para a
esquerda ou para a direita quando o valor for negativo.
3- EscavarCommand - O terceiro comando move para cima
e para baixo a pá de coleta de amostra. Em cada comando, os
métodos Executar e Desfazer são implementadas. O método
Desfazer realiza a operação inversa do método Executar.
1- MoverCommand
namespace PadraoProjetoCommand
{
class MoverCommand : RoboCommand
{
public int ParaFrente { get; set; }
public MoverCommand(Robo robo) : base(robo) { }
public override void Executar()
{
_robo.Mover(ParaFrente);
}
public override void Desfazer()
{
_robo.Mover(-ParaFrente);
}
}
}
|
Class MoverCommand
Inherits RoboCommand
Public Property ParaFrente() As Integer
Get
Return m_ParaFrente
End Get
Set(value As Integer)
m_ParaFrente = Value
End Set
End Property
Private m_ParaFrente As Integer
Public Sub New(robo As Robo)
MyBase.New(robo)
End Sub
Public Overrides Sub Executar()
_robo.Mover(ParaFrente)
End Sub
Public Overrides Sub Desfazer()
_robo.Mover(-ParaFrente)
End Sub
End Class
|
| C# | VB .NET |
2 - RotacionarCommand
namespace PadraoProjetoCommand
{
class RotacionarCommand: RoboCommand
{
public double rotacionarParaEsquerda { get; set; }
public RotacionarCommand(Robo robo) : base(robo) { }
public override void Executar()
{
_robo.RotacionarParaEsquerda(rotacionarParaEsquerda);
}
public override void Desfazer()
{
_robo.RotacionarParaEsquerda(-rotacionarParaEsquerda);
}
}
}
|
Class RotacionarCommand
Inherits RoboCommand
Public Property rotacionarParaEsquerda() As Double
Get
Return m_rotacionarParaEsquerda
End Get
Set(value As Double)
m_rotacionarParaEsquerda = Value
End Set
End Property
Private m_rotacionarParaEsquerda As Double
Public Sub New(robo As Robo)
MyBase.New(robo)
End Sub
Public Overrides Sub Executar()
_robo.RotacionarParaEsquerda(rotacionarParaEsquerda)
End Sub
Public Overrides Sub Desfazer()
_robo.RotacionarParaEsquerda(-rotacionarParaEsquerda)
End Sub
End Class
|
| C# | VB .NET |
3- EscavarCommand
namespace PadraoProjetoCommand
{
class EscavarCommand : RoboCommand
{
public bool ColherMaterial { get; set; }
public EscavarCommand(Robo robo) : base(robo) { }
public override void Executar()
{
_robo.Escavar(ColherMaterial);
}
public override void Desfazer()
{
_robo.Escavar(!ColherMaterial);
}
}
}
|
Class EscavarCommand
Inherits RoboCommand
Public Property ColherMaterial() As Boolean
Get
Return m_ColherMaterial
End Get
Set(value As Boolean)
m_ColherMaterial = Value
End Set
End Property
Private m_ColherMaterial As Boolean
Public Sub New(robo As Robo)
MyBase.New(robo)
End Sub
Public Overrides Sub Executar()
_robo.Escavar(ColherMaterial)
End Sub
Public Overrides Sub Desfazer()
_robo.Escavar(Not ColherMaterial)
End Sub
End Class
|
| C# | VB .NET |
Vamos agora criar a classe Robo que será o Receptor único onde iremos definir as funcionalidades dos comandos. No exemplo estamos apenas emitindo mensagens relacionadas com cada comando.
using System;
namespace PadraoProjetoCommand
{
class Robo
{
public void Mover(int ParaFrente)
{
if (ParaFrente > 0)
Console.WriteLine("O Robo foi movimentado para frente {0}mm.", ParaFrente);
else
Console.WriteLine("O Robo foi movimentado para trás {0}mm.", -ParaFrente);
}
public void RotacionarParaEsquerda(double rotacionarParaEsquerda)
{
if (rotacionarParaEsquerda > 0)
Console.WriteLine("O Robo foi rotacionaod para esquerda {0} degrees.", rotacionarParaEsquerda);
else
Console.WriteLine("O Robo foi rotacionado para direita {0} degrees.", -rotacionarParaEsquerda);
}
public void Escavar(bool paraCima)
{
if (paraCima)
Console.WriteLine("O Robo colheu material do solo.");
else
Console.WriteLine("O Robo despejou o material colhido.");
}
}
}
|
|
| C# | |
Class Robo
Public Sub Mover(ParaFrente As Integer)
If ParaFrente > 0 Then
Console.WriteLine("O Robo foi movimentado para frente {0}mm.", ParaFrente)
Else
Console.WriteLine("O Robo foi movimentado para trás {0}mm.", -ParaFrente)
End If
End Sub
Public Sub RotacionarParaEsquerda(rotacionarParaEsquerda__1 As Double)
If rotacionarParaEsquerda__1 > 0 Then
Console.WriteLine("O Robo foi rotacionaod para esquerda {0} degrees.", rotacionarParaEsquerda__1)
Else
Console.WriteLine("O Robo foi rotacionado para direita {0} degrees.", -rotacionarParaEsquerda__1)
End If
End Sub
Public Sub Escavar(paraCima As Boolean)
If paraCima Then
Console.WriteLine("O Robo colheu material do solo.")
Else
Console.WriteLine("O Robo despejou o material colhido.")
End If
End Sub
End Class
|
|
| VB .NET | |
Para completar as classes do padrão vamos criar a classe RoboControle que faz o papel de Chamador.
Nesta classe podemos ter uma fila de comandos, em vez de uma única referência. Além disso, uma pilha de comandos será usada para manter um registro das atividades do robô. Esta pilha pode então ser usado para desfazer os comandos que foram executados com erro.
using System;
using System.Collections.Generic;
namespace PadraoProjetoCommand
{
class RoboControle
{
public Queue<RoboCommand> Comandos;
private Stack<RoboCommand> _desfazerPilha;
public RoboControle()
{
Comandos = new Queue<RoboCommand>();
_desfazerPilha = new Stack<RoboCommand>();
}
public void ExecutarComandos()
{
Console.WriteLine("EXECUTANDO COMANDO(S).");
while (Comandos.Count > 0)
{
RoboCommand comando = Comandos.Dequeue();
comando.Executar();
_desfazerPilha.Push(comando);
}
}
public void DesfazerComandos(int numComandosDesfazer)
{
Console.WriteLine("DESFAZENDO {0} COMANDO(S).", numComandosDesfazer);
while (numComandosDesfazer > 0 && _desfazerPilha.Count > 0)
{
RoboCommand comand = _desfazerPilha.Pop();
comand.Desfazer();
numComandosDesfazer--;
}
}
}
}
|
| C# |
Class RoboControle
Public Comandos As Queue(Of RoboCommand)
Private _desfazerPilha As Stack(Of RoboCommand)
Public Sub New()
Comandos = New Queue(Of RoboCommand)()
_desfazerPilha = New Stack(Of RoboCommand)()
End Sub
Public Sub ExecutarComandos()
Console.WriteLine("EXECUTANDO COMANDO(S).")
While Comandos.Count > 0
Dim comando As RoboCommand = Comandos.Dequeue()
comando.Executar()
_desfazerPilha.Push(comando)
End While
End Sub
Public Sub DesfazerComandos(numComandosDesfazer As Integer)
Console.WriteLine("DESFAZENDO {0} COMANDO(S).", numComandosDesfazer)
While numComandosDesfazer > 0 AndAlso _desfazerPilha.Count > 0
Dim comand As RoboCommand = _desfazerPilha.Pop()
comand.Desfazer()
numComandosDesfazer -= 1
End While
End Sub
End Class
|
| VB .NET |
Vamos agora definir o código que utiliza a implementação do padrão Comando digitando o código a seguir na classe/Modulo Program.cs/Module.vb
using System;
namespace PadraoProjetoCommand
{
class Program
{
static void Main(string[] args)
{
Robo robo = new Robo();
RoboControle controle = new RoboControle();
MoverCommand mover = new MoverCommand(robo);
mover.ParaFrente = 1000;
controle.Comandos.Enqueue(mover);
RotacionarCommand rotacionar = new RotacionarCommand(robo);
rotacionar.rotacionarParaEsquerda = 45;
controle.Comandos.Enqueue(rotacionar);
EscavarCommand escavar = new EscavarCommand(robo);
escavar.ColherMaterial = true;
controle.Comandos.Enqueue(escavar);
controle.ExecutarComandos();
controle.DesfazerComandos(3);
Console.ReadKey();
}
}
}
|
Module Module1
Sub Main()
Dim robo As New Robo()
Dim controle As New RoboControle()
Dim mover As New MoverCommand(robo)
mover.ParaFrente = 1000
controle.Comandos.Enqueue(mover)
Dim rotacionar As New RotacionarCommand(robo)
rotacionar.rotacionarParaEsquerda = 45
controle.Comandos.Enqueue(rotacionar)
Dim escavar As New EscavarCommand(robo)
escavar.ColherMaterial = True
controle.Comandos.Enqueue(escavar)
controle.ExecutarComandos()
controle.DesfazerComandos(3)
Console.ReadKey()
End Sub
End Module
|
| C# | VB .NET |
Executando projeto teremos como o seguinte resultado:
O resultado acima mostra a execução dos comandos implementados e a seguir o cancelamento das operações executadas.
Pegue a solução completa
aqui:
PadraoProjetoCommand.zip /
PadraoProjetoCommandVB.zip
1Pe 1:13
Portanto, cingindo os lombos do vosso entendimento, sede sóbrios, e esperai inteiramente na graça que se vos oferece na revelação de Jesus Cristo.Referências: