Chegamos ao quinto e último artigo de Design Patterns. Por cinco meses estamos aprofundando as melhores práticas de desenvolvimento de software. Vimos os seguintes padrões:

  1. Strategy (edição 47 da .Net Magazine)
  2. Decorator e Template Method (edição 48 da .Net Magazine)
  3. Factory Method (edição 49 da .Net Magazine)
  4. Abstract Factory (edição 50 da .Net Magazine)
  5. Singleton e Composite (esta edição)

Abordarei neste último artigo o padrão Singleton, que vai nos mostrar como criar um objeto único, sem outras instâncias do mesmo tipo no mesmo domínio de aplicação. Veremos também o padrão Composite, que permitirá a utilização de árvores de objeto, tratando as partes e o todo uniformemente, o que simplifica bastante o modelo de programação.

São padrões simples, mas que resolvem grandes problemas. Muitas vezes acabamos por achar soluções intermediárias, que simulam ou se parecem com estes padrões, mas não atendem completamente às mesmas necessidades. Veremos, como nos outros artigos, exemplos de aplicação dos padrões no próprio .Net Framework assim como veremos um caso de interligação do padrão Singleton com o padrão de Factory.

O problema de um objeto único

Frequentemente nos deparamos com a necessidade de limitar a criação de um determinado tipo a um único objeto. Existem vários tipos de objetos dos quais precisamos um só, e não mais que um. Alguns exemplos são:

  • Um gerenciador de cache;
  • Um gerenciador de uploads ou downloads;
  • Um controlador de configuração;

Em todos esses exemplos, você vai querer ter apenas um destes objetos em sua aplicação. De que adianta, por exemplo, um gerenciador de cache, do qual você pode ter mais de um? Se você está precisando de um dado que pode existir em cache, você quer requisitar o dado sempre ao mesmo gerenciador de cache. Da mesma forma, porque sua aplicação teria mais de um gerenciador de upload? Se ela está gerenciando uploads, é bom que isso seja feito por um único objeto, para que, ao solicitar a fila de uploads, a mesma lista seja retornada.

Configuração é outro exemplo interessante e com bastante aplicação. Já vi algumas vezes arquiteturas que concentram em um único objeto as responsabilidades de configuração, como por exemplo, caminho e porta de SMTP para envio de mensagens, políticas de tratamento de erro, entre outras informações. Da mesma forma, ter um único objeto instanciado desta classe de configuração é uma boa idéia, o que evita o risco de estar entrando em contato com configurações desatualizadas.

Como possibilitar a criação de um único objeto? A palavra-chave “new”, parte integrante de grande parte das linguagens orientadas a objeto (C#, VB, Java, C++, entre diversas outras), permite criar quantos objetos você quiser de qualquer tipo. Códigos como o da Listagem 1 mostram como é fácil criar quantos objetos quisermos de um determinado tipo.

  
 'classe de gerenciador de downloads
 'queremos uma só desta
 Public Class GerenciadorDeDownloads
    Public Function ObterDownloads() As List(Of Download)
    End Function
    Public Function SubmeterNovoDownload(ByVal d As Download) As Boolean
    End Function
 End Class
 Public Class Download
    Public Sub New(ByVal strUrl As String)
    End Sub
 End Class
 
 Public Class Cliente
  Public Sub Funcao()
    'criação de vários gerenciadores, e agora?
    Dim g1 As New GerenciadorDeDownloads
    Dim g2 As New GerenciadorDeDownloads
    Dim g3 As New GerenciadorDeDownloads
    g1.SubmeterNovoDownload(New Download("http://www..."))
    g2.SubmeterNovoDownload(New Download("http://www.outro..."))
    g3.SubmeterNovoDownload(New Download("http://www.maisoutro..."))
    'temos agora 2 listas de gerenciadores...
    Dim l1 As List(Of Download) = g1.ObterDownloads()
    Dim l2 As List(Of Download) = g2.ObterDownloads()
  End Sub
 End Class
Listagem 1. Como fazer para controlar a instanciação do objeto

O padrão Singleton

É para atender esse cenário que o padrão Singleton foi compilado. Este padrão serve unicamente para nos ajudar a criar um único objeto de um determinado tipo, dentro do contexto de uma aplicação.

O padrão Singleton utiliza uma construção muito peculiar para resolver o “problema do new”. Veja o seguinte código:


Public Class GerenciadorDeDownloads
    Private Sub New()
    End Sub
  End Class

Muitas pessoas não sabem que essa construção é possível, mas ela é perfeitamente legal no .Net e na OO em geral. Parece estranho declarar um construtor privado, afinal, é ele quem permite instanciar a classe, e isso significaria que a classe não pode ser instanciada. Se a classe só pode ser instanciada por ela mesma (o construtor é privado) e não existe nenhuma classe instanciada, essa função não vai rodar nunca, e será impossível criar o objeto. Acabamos de criar um paradoxo, um problema sem solução, certo? Errado. “Privado” quer dizer que nenhum outro objeto pode chamar este método, mas nada impede do próprio tipo chamar o construtor através de um método estático (“static” ou “shared”), e métodos estáticos não dependem de objetos instanciados, logo, não há dependência do construtor.

Assim, utilizando um método estático, podemos criar o objeto:


Public Class GerenciadorDeDownloads
    Private Sub New()
    End Sub
    Public Shared Function Cria() As GerenciadorDeDownloads
    Return New GerenciadorDeDownloads()
    End Function
    End Class

O problema, no entanto, não está resolvido. Qualquer classe externa pode chamar o método “Cria” e criar quantos objetos gerenciadores de download quiser. Precisamos então resolver este problema. Veja a próxima solução (o construtor privado está oculto):

...

Quer ler esse conteúdo completo? Tenha acesso completo