| Por Rafael Godinho rafa.god@gmail.com Rafael Godinho é consultor em desenvolvimento. Tem atuado utilizando as tecnologias XML, Web Services, ASP.NET, C#, Visual Basic e C++. Possui as certificações MCP, MCSD, MCSE, MCDBA, MCT e MSF Practitioner. Atualmente se esforça o máximo possível para terminar o último ano de Engenharia da Computação na faculdade. Pode ser contatado através do email rafa.god@gmail.com |
|
|
|
|
| Abstract Factory com C# | |
|
|
|
Resumo: Este artigo explica conceitos teóricos e demonstra com exemplo prático utilizando MSMQ e MQSeries a utilização do Pattern Abstract Factory na linguagem C#.
Vamos supor que você está projetando uma aplicação comercial que precisa se comunicar com outros sistemas de maneira assincrona através de um serviço de filas de mensagens. Sua aplicação precisa ter suporte a dois padrões de mercado, o MSMQ da Microsoft e o WebSphere MQ (mais conhecido como MQSeries) da IBM. Para ser portátil entre os serviços de mensagem, a aplicação não pode ser codificada rigidamente para um determinado padrão, instanciando classes específicas de cada iria dificultar as alterações no futuro.
Exitem também subclasses concretas de AbsctractMessagingFactory que implementam as operações para criar os objetos baseados na sua família. O programa cliente, por sua vez, chama essas operações para obter instâncias dos objetos sem necessidade de conhecimento das classes concretas sendo utilizadas, somente precisa ter conhecimento da fábrica.
Aplicações
·
Precisar abstrair detalhes da implementação de produtos, fazendo o sistema independente de como os objetos são instanciados;
·
Necessidade de suportar múltiplas famílias de produtos, o sistema deve ser configurado com uma de múltiplas famílias;
·
Garantir a restrição de que objetos da mesma família sejam utilizados em conjunto;
·
Necessitar revelar somente a interface dos produtos e não suas implementações.
Estrutura do padrão
As classes do Abstract Factory se relacionam da seguinte maneira:
Exemplo de código
Maiores detalhes de implementação específica de cada tecnologia podem ser obtidos na bibliografia. Para informações sobre a configuração do ambiente consulte os apêndices no final do artigo.
Classes abstratas utilizadas pelo cliente:
abstract class AbsctractMessage
{
public abstract string Body
{
get;
set;
}
}
abstract class AbsctractQueue
{
protected string _name;
public virtual string Name
{
get { return _name; }
set { _name = value; }
}
public abstract void Send(AbsctractMessage msg);
public abstract AbsctractMessage Receive();
}
Definição da interface da Abstract Factory:
abstract class AbsctractMessagingFactory
{
public abstract AbsctractMessage CreateMessage();
public abstract AbsctractMessage CreateMessage(string body);
public abstract AbsctractQueue CreateQueue();
public abstract AbsctractQueue CreateQueue(string path);
}
Classes concretas da família do MSMQ:
class MSMQMessage : AbsctractMessage
{
Message _msmqMsg;
public MSMQMessage() : this("")
{
}
public MSMQMessage(string body)
{
_msmqMsg = new Message(body, new BinaryMessageFormatter());
}
public MSMQMessage(Message msmqMsg)
{
_msmqMsg = msmqMsg;
_msmqMsg.Formatter = new BinaryMessageFormatter();
}
public override string Body
{
get
{
return _msmqMsg.Body.ToString();
}
set
{
_msmqMsg.Body = value;
}
}
public Message Message
{
get
{
return _msmqMsg;
}
set
{
_msmqMsg = value;
}
}
}
class MSMQQueue : AbsctractQueue
{
public MSMQQueue()
{
}
public MSMQQueue(string name)
{
_name = name;
}
public override void Send(AbsctractMessage msg)
{
MessageQueue msmqQueue = new MessageQueue(GetPath());
msmqQueue.Send(((MSMQMessage)msg).Message);
msmqQueue.Close();
}
public override AbsctractMessage Receive()
{
MessageQueue msmqQueue = new MessageQueue(GetPath());
Message msmqMsg = msmqQueue.Receive();
msmqQueue.Close();
return new MSMQMessage(msmqMsg);
}
private string GetPath()
{
// Aqui irá o código para obter o caminho completo para a fila do MSMQ
return String.Format(".\\Private$\\{0}", _name);
}
}
Fábrica concreta para a fábrica de objetos do MSMQ:
class MSMQFactory : AbsctractMessagingFactory
{
public override AbsctractMessage CreateMessage()
{
return CreateMessage("");
}
public override AbsctractMessage CreateMessage(string body)
{
return new MSMQMessage(body);
}
public override AbsctractQueue CreateQueue()
{
return CreateQueue("");
}
public override AbsctractQueue CreateQueue(string name)
{
return new MSMQQueue(name);
}
}
Classes concretas para a família do MQSeries:
class MQSeriesMessage : AbsctractMessage
{
MQMessage _message;
public MQSeriesMessage() : this("")
{
}
public MQSeriesMessage(string body)
{
_message = new MQMessage();
_message.Format = MQC.MQFMT_STRING;
this.Body = body;
}
public MQSeriesMessage(MQMessage mqMessage)
{
_message = mqMessage;
}
public override string Body
{
get
{
return _message.ReadString(_message.MessageLength);
}
set
{
_message.WriteString(value);
}
}
public MQMessage Message
{
get
{
return _message;
}
set
{
_message = value;
}
}
}
class MQSeriesQueue : AbsctractQueue
{
public MQSeriesQueue()
{
}
public MQSeriesQueue(string name)
{
_name = name;
}
public override void Send(AbsctractMessage msg)
{
string queueManagerName = GetQueueManager();
MQQueueManager queueManager = new MQQueueManager(queueManagerName);
MQQueue queue = queueManager.AccessQueue(_name, MQC.MQOO_OUTPUT + MQC.MQOO_FAIL_IF_QUIESCING);
MQPutMessageOptions queuePutMessageOptions = new MQPutMessageOptions();
queue.Put(((MQSeriesMessage)msg).Message, queuePutMessageOptions);
}
public override AbsctractMessage Receive()
{
string queueManagerName = GetQueueManager();
MQQueueManager queueManager = new MQQueueManager(queueManagerName);
MQQueue queue = queueManager.AccessQueue(_name, MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_FAIL_IF_QUIESCING);
MQGetMessageOptions queueGetMessageOptions = new MQGetMessageOptions();
MQMessage queueMessage = new MQMessage();
queue.Get(queueMessage, queueGetMessageOptions);
return new MQSeriesMessage(queueMessage);
}
private string GetQueueManager()
{
// Aqui vai o código para buscar o Queue Manager do MQSeries,
// se deixar em branco conecta no Default
return "";
}
}
Fábrica concreta para a família de objetos do MQSeries:
class MQSeriesFactory : AbsctractMessagingFactory
{
public override AbsctractMessage CreateMessage()
{
return CreateMessage("");
}
public override AbsctractMessage CreateMessage(string body)
{
return new MQSeriesMessage(body);
}
public override AbsctractQueue CreateQueue()
{
return CreateQueue("");
}
public override AbsctractQueue CreateQueue(string name)
{
return new MQSeriesQueue(name);
}
}
Utilização das fábricas
No trecho de código abaixo, temos uma aplicação utilizando a fábrica do MQSeries:
AbsctractMessagingFactory factory = new MQSeriesFactory();
AbsctractMessage msg;
AbsctractQueue queue;
msg = factory.CreateMessage("MyMessage");
queue = factory.CreateQueue("MyQueue");
queue.Send(msg);
msg = queue.Receive();
System.Console.WriteLine("Mensagem recebida do MQSeries: {0}", msg.Body);
Após o envio da mensagem pelo método Send vemos no WebSphere MQ Explorer que a mensagem realmente se encontra na fila:
E após a chamada do método Receive notamos que a mensagem saiu da fila, conforme o esperado:
Agora, para a aplicação passar a utilizar o MSMQ, somente é necessário alterar a classe concreta utilizada para a fábrica. O código do cliente ficaria assim:
AbsctractMessagingFactory factory = new MSMQFactory(); // Essa linha mudou AbsctractMessage msg;
AbsctractQueue queue;
msg = factory.CreateMessage("MyMessage");
queue = factory.CreateQueue("MyQueue");
queue.Send(msg);
msg = queue.Receive();
System.Console.WriteLine("Mensagem recebida do MSMQ: {0}", msg.Body);
No retorno do método Send notamos que a mensagem se encontra na fila
E quando o método Receive retorna a mensagem saiu da fila
Conclusões
Com o que vimos podemos citar as seguintes características do Pattern Abstract Factory:
Uma versão Trial do produto pode ser encontrada no site do seu fabricante http://www14.software.ibm.com/webapp/download/preconfig.jsp?id=2004-02-26+15%3A37%3A22.703396R&cat=&fam=&s=p&S_TACT=104AH%20W42&S_CMP, o arquivo tem 128 MB.
A instalação do MQSeries é basicamente um Wizard Next/Next/Finish. Segue uma lista com as principais dificuldades que podem ocorrer durante a instalação. Atenção: muitos passos foram omitidos por serem auto-explicativos.
Após extrair o arquivo clique em Sim para instalar
Os itens 1 e 2 são os pré-requisitos, é bom verificar. Após isso vá para o item 3
No item 3 clique em "Launch WebSphere MQ Installer"