Neste artigo, vou mostrar como aplicar boas práticas ao projeto de envio de SMS usando o padrão Strategy.
No artigo anterior eu mostrei como enviar mensagens SMS usando o serviço da ViaNett com a linguagem VB .NET.
Criamos uma conta na ViaNett. Em seguida, criamos uma aplicação Windows Forms, referenciamos o web service e enviamos mensagens SMS para um celular. Como o objetivo era apenas mostrar como enviar mensagens SMS, podemos dizer que a aplicação funciona.
Se a aplicação for vista como apenas um protótipo de testes tudo bem. Mas se desejarmos criar uma aplicação mais robusta e aderente às boas práticas de programação, não está aderente aos princípios SOLID, e, para contotnar isso, vamos ter que alterar muita coisa em nosso código.
O que há de errado com o nosso projeto?
- O projeto fere princípio da responsabilidade única ou SRP, pois apresenta muitas responsabilidades reunidas na camada de interface do usuário;
- O nosso código não esta aderente ao príncipio Aberto-Fechado ou Open Close, pois qualquer nova implementação vai requerer alteração no código;
- Não estamos programando para uma interface e sim para uma implementação;
- Não estamos usando a injeção de dependência para termos um baixo acoplamento entre os objetos usados.
Esses são alguns dos problemas que podemos identificar no código usado.
Imagine que agora precisamos enviar mensagens SMS usando o serviço de outra empresa. Como faríamos? Basta colocar um if no código e pronto? Pensando e agindo assim, o seu código vai requerer uma constante manutenção e pode apresentar diversos problemas no futuro. Vamos, então, mostrar como melhorar o nosso projeto.
Analisando o problema e se antecipando a mudanças
Para não tornar o problema muito abrangente, vou focar apenas na tarefa de enviar mensagens SMS.
Focando nisso, podemos antever que temos diversos opções para realizar essa tarefa e cada opção vai ter, assim, a sua implementação no código. Podemos enviar SMS usando um modem 3G ou o serviço da ViaNett, da Twilio, da Ipipi, da LocaSMS (Brasil), da Zenia (Brasil) etc.
Então, vamos ter algoritmos diferentes para cada implementação. Pensando nisso, podemos usar o padrão de projeto Estratégia ou Strategy. Eu já apresentei esse padrão neste artigo: Strategy – Macoratti.net.
Apenas para constar: “O padrão Strategy define uma familia de algoritmos intercambiáveis de forma que estes sejam independentes dos clientes que os utilizam”.
Resumindo:
- Objetivo: Encapsular um algoritmo em um objeto;
- Fornecer interfaces genéricas o suficiente para suportar uma variedade de algorítmos;
- Facilitar a escolha e troca (intercâmbio) de algoritmos criados com uma mesma função.
Implementando o padrão Strategy
Vamos abrir o projeto criado no artigo anterior e criar uma pasta chamada Service no projeto.
A seguir, vamos criar uma interface chamada IEnviaSMS onde vamos definir o método EnviarSMS conforme mostrado a seguir:
Public Interface IEnviaSMS
Sub EnviaSMS(telefone As Long, mensagem As String)
End Interface
Estamos agora programando para um interface e veremos que isso vai desacoplar os objetos usados em nossa aplicação.
Vamos agora criar na pasta Service a classe EnviaSMSViaNett que vai implementar essa interface:
Public Class EnviaSMSViaNett
Implements IEnviaSMS
Public Sub EnviaSMS(telefone As Long, mensagem As String) Implements IEnviaSMS.EnviaSMS
Try
Dim usuario As String = ""
Dim senha As String = ""
Using ViaNettClient = New ViaNett.CPAWebServiceSoapClient("CPAWebServiceSoap12")
Dim Resultado = ViaNettClient.SendSMS_Simple1(usuario, senha, telefone, mensagem)
End Using
Catch
Throw
End Try
End Sub
End Class
Neste código, estamos isolando a implementação específica da ViaNett em uma classe encapsulando, assim, o nosso código. Qualquer alteração na metodologia da ViaNett vai afetar somente esta classe.
Se no futuro você precisar enviar SMS usando outro serviço, como o da LocaSMS que veremos no próximo artigo, basta criar uma nova classe e implementar a mesma interface. Assim, nosso código ficou aderente ao princípio Open-Closed, pois agora podemos estender o comportamento do nossa aplicação sem ter que modificar código.
Além disso, isso vai facilitar os testes unitários da nossa aplicação.
Vamos criar no projeto uma classe chamada Comunicacao, que fara o papel da Strategy com o seguinte código:
Public Class Comunicacao
Dim _enviaSMS As IEnviaSMS
Sub New(enviaSMS As IEnviaSMS)
_enviaSMS = enviaSMS
End Sub
Public Sub EnviaMensagemSMS(fone As Long, msg As String)
_enviaSMS.EnviaSMS(fone, msg)
End Sub
End Class
Observe que não temos nenhum acoplamento forte no código desta classe, pois no construtor da classe estamos injetando uma instância do serviço para enviar SMS definido na interface IEnviaSMS.
Agora, só falta definir o código no formulário Form1.vb que é a nossa interface com o usuário. Nossa interface agora não sabe como enviar SMS, ela apenas usa a classe Comunica que é responsável por realizar essa tarefa. Qualquer alteração na metodologia de enviar SMS não vai afetar nossa interface.
Veja como ficou o código:
Imports System.Text.RegularExpressions
Public Class Form1
Private Sub btnEnviarSMS_Click(sender As Object, e As EventArgs) Handles btnEnviarSMS.Click
Dim fone As Long = 0
Dim msg As String = ""
If Not ValidaTelefone(txtTelefone.Text) Then
MessageBox.Show("Número de telefone inválido. Use o formato 55XX999999999.")
txtTelefone.Text = ""
txtTelefone.Focus()
Return
Else
fone = Convert.ToInt64(txtTelefone.Text.Replace("+", String.Empty))
End If
If String.IsNullOrEmpty(txtMensagem.Text) Then
MessageBox.Show("Informe a mensagem a ser enviada ")
txtMensagem.Focus()
Return
Else
msg = txtMensagem.Text
End If
Try
Dim comunica As Comunicacao
comunica = New Comunicacao(New EnviaSMSViaNett)
comunica.EnviaMensagemSMS(fone, msg)
MessageBox.Show("Mensagem enviada para : " & txtTelefone.Text)
Catch ex As Exception
MessageBox.Show("Erro : " & ex.Message)
End Try
End Sub
Function ValidaTelefone(fone As String) As Boolean
Dim pattern As String = "^[0-9]*quot;
'cria o objeto regex
Dim check As New Regex(pattern)
Dim valid As Boolean = False
'verifica se um valor foi fornecido e se é maior que 8 caracteres
If Not String.IsNullOrEmpty(fone) And fone.Length > 8 Then
valid = check.IsMatch(fone)
Else
valid = False
End If
Return valid
End Function
End Class
É claro que poderíamos continuar a aplicar outros padrões (como a injeção de dependência), mas com apenas essas alterações nosso projeto ficou muito melhor
Na próxima parte do artigo vou mostrar como enviar SMS usando o serviço da LocaSMS que é uma empresa localizada no Brasil.




