Informações

Tipo: Artigo
Data de Publicação: 31/12/2005
Revisado em: 31/12/2005

Vote!

  • Currently 4,4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags Relacionadas

designpatterns poo

Comentários ( 11 )

Imprimir

Padrões de Projeto: O padrão Singleton

por:

David Pereira (david@jeebrasil.com.br)

Este é o primeiro de uma série de artigos sobre Padrões de Projeto, os Design Patterns. Neste artigo, será apresentado o padrão Singleton. O Singleton é um dos padrões de projeto mais simples e é usado quando for necessária a existência de apenas uma instância de uma classe.

1. Introdução

Este é o primeiro de uma série de artigos sobre Padrões de Projeto, os Design Patterns . Faz-se então necessária uma breve introdução sobre o assunto para que o leitor possa acompanhar este e os demais artigos consciente do que trata o seu objeto de estudo.

Considera-se como o início da história dos padrões de projeto a publicação da obra A Pattern Language: Towns, Buildings, Construction [1], de Christopher Alexander, em 1987. Entretanto, a sua popularização só veio oito anos depois, em 1995, com o livro Design Patterns – Elements of Reusable Object-Oriented Software [2], também conhecido como GoF, de Erich Gamma et al.

Um Padrão de Projeto pode ser definido como “a solução para um problema em um contexto” [3]. Isto significa que os padrões de projeto nos oferecem soluções prontas para utilizarmos em determinados problemas que podemos enfrentar quando desenvolvemos um software orientado a objetos.

Os padrões de projeto são observados através da experiência de um desenvolvedor com projetos de software, o que significa que os padrões são descobertos, e não inventados. Como eles fornecem soluções prontas para a solução de problemas, existem diversas vantagens no seu uso, como a reutilização de códigos, modelos e arquiteturas, a padronização de designs e boas práticas, a criação de uma linguagem comum entre desenvolvedores, entre outras.

Podemos classificar os padrões de projeto de várias maneiras, porém o mais comum é classificá-los de acordo com os tipos de problemas que eles resolvem. De acordo com esse critério, os padrões podem ser: de criação , que lidam com o problema da criação de objetos; estruturais , que lidam com os relacionamentos entre objetos; comportamentais , que lidam com a atribuição de responsabilidades aos objetos; e outros.

Ao descrever um padrão de projeto devemos especificar o seu nome, que o identifica e descreve; o contexto , ou seja, a situação na qual se deve aplicar o padrão; o problema , que é a meta que está se tentando atingir neste contexto; a solução proposta pelo padrão para o problema no contexto especificado e as conseqüências da aplicação do padrão, podendo serem elas boas ou ruins. Para compreender melhor esses conceitos, veja o exemplo abaixo, que não pode ser considerado um padrão de projeto, servindo apenas para ajudar a compreender o modo como um padrão de projeto deve ser definido.

•  Nome: Quebra-Janelas!

•  Problema : Como chegar cedo ao trabalho?

•  Contexto : Tranquei o meu carro com as chaves dentro!

•  Solução : Quebre a janela, entre no carro e dirija até o trabalho.

•  Conseqüências : Uma janela quebrada e a mão doendo.

Os padrões de projeto solucionam muitos dos problemas que os projetistas enfrentam no dia a dia, e de muitas maneiras diferentes [2]. Nesta série de artigos tentaremos mostrar alguns dos padrões mais comuns, explicando o contexto, o problema, a solução e suas conseqüências com exemplos simples e acessíveis. Todos os exemplos estarão escritos em Java, mas são aplicáveis em qualquer linguagem orientada a objetos.

<%-- PARTE 2 --%>

2 . O padrão Singleton

O Singleton é um dos padrões de projeto mais simples. Ele é usado quando for necessária a existência de apenas uma instância de uma classe. Foi apresentado no GoF [2] como um padrão de criação, por lidar com a criação de objetos.

O GoF nos diz que para uma classe ser um singleton, deve-se garantir que haverá apenas uma instância na aplicação e que deve-se fornecer um ponto de acesso à mesma. Mas como garantir que haverá apenas uma instância? É de conhecimento comum que, para criar uma instância de uma classe, devemos chamar o seu construtor. Assim, para resolvermos o problema, devemos restringir o acesso ao construtor, tornando-o um método privado. Em seguida, deve-se utilizar um método público que faça o controle da instanciação, de modo que ela só possa ser feita uma vez. A Figura 1 mostra o diagrama de classes do singleton:

Figura 1: Diagrama de Classes do Singleton.

A implementação mais comum do singleton pode ser vista no código apresentado na Listagem 1.

public class Singleton {


   private static Singleton instance;

   private Singleton() {

   }

   public static Singleton getInstance() {
      if (instance == null)
         instance = new Singleton();
      return instance;
   }
}

Listagem 1 : Implementação do Singleton .

O diagrama de classes da Figura 1 e o código da Listagem 1 mostram apenas o necessário para a instanciação do singleton. Obviamente, a classe deve conter outros atributos e métodos.

A Figura 2 mostra um diagrama de seqüências que representa o processo de criação de um singleton. Quando um objeto chama o singleton pela primeira vez, é realizada a instanciação da classe. Os demais acessos irão utilizar a instância já criada.

Figura 2: Diagrama de Seqüências de um Singleton.

O código da Listagem 1 pode ser problemático em ambientes multi-threaded, ou seja, ele não é uma solução thread-safe. Se uma thread chamar o método getInstance() e for interrompida antes de realizar a instanciação, uma outra thread poderá chamar o método e realizar a instanciação. Neste caso, duas instâncias serão construídas, o que fere os requisitos do singleton . Uma solução para este problema seria utilizar o atributo synchronized em getInstance(), como visto na Listagem 2 , para que uma outra thread não possa acessá-lo até que a thread que o acessou pela primeira vez tenha terminado de fazê-lo.

public class Singleton {


   private static Singleton instance;

   private Singleton() {

   }

   public static synchronized Singleton getInstance() {
      if (instance == null)
         instance = new Singleton();
      return instance;
   }
}

Listagem 2 : Implementação thread-safe com synchronized./p>

O problema com o synchronized é que a sincronização é bastante custosa. Estima-se que métodos sincronizados sejam cerca de cem vezes mais lentos que métodos não sincronizados [3]. Uma alternativa simples, rápida e thread-safe é a instanciação do singleton assim que ele for declarado. Veja a Listagem 3 .

public class Singleton {


   private static Singleton instance = new Singleton();

   private Singleton() {

   }

   public static Singleton getInstance() {
      return instance;
   }
}

Listagem 3 : Implementação thread-safe com instanciação estática.

3. Conclusões

Além de ser um dos padrões mais simples, o singleton é também um dos mais criticados e mal usados. Uma situação em que realmente é necessário que exista apenas uma instância de uma classe é difícil e o seu uso pode levar a muitos problemas. O uso abusivo de singletons leva a soluções onde a dependência entre objetos é muito forte e a testabilidade é fraca. Adicionalmente, os singletons são difíceis de escalar, pois é difícil garantir uma única instância de um singleton em um cluster, onde existem várias JVMs. Um outro problema é que os singletons dificultam o hot redeploy por permanecerem em cache, bloqueando mudanças de configuração. Por esses e outros problemas, deve-se ter cuidado com o uso abusivo de singletons.

4. Referências

[1] Alexander, Christopher. A Pattern Language: Towns, Buildings, Construction . Oxford University Press, 1987.

[2] Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John. Padrões de Projeto – Soluções reutilizáveis de Software Orientado a Objetos . Bookman, 2004.

[3] Freeman, Eric; Freeman, Elisabeth. Head First Design Patterns . O'Reilly, 2004.

 

Comentários (11)

Bastante interessante, mas ficou faltando um exemplo onde esse Padrão seja realmente necessário.
postado por Pedro Zatta em 05/10/2006 às 23:21

É verdade, Pedro. Ficou faltando. Vou tentar então complementar aqui. É comum o uso de singletons em classes que servem para fornecer recursos, como por exemplo uma classe que pega conexões do banco de dados ou uma classe Factory (Factory é um padrão de projeto que iremos ver em um artigo futuro).

Nesses casos, usa-se o singleton para termos apenas uma classe cuidando das conexões (ou da criação de instâncias, no caso do factory) e podermos ter mais controle sobre essa criação de conexões. Quando usa-se o singleton aqui é porque quer-se centralizar em apenas uma instância a criação das conexões.

Claro que essa não é a única abordagem possível para resolver esse problema, mas é um exemplo comum da utilização do singleton.

postado por David Pereira em 07/10/2006 às 23:21
Olá David, Parabéns pela matéria, sou programador Delphi e estou iniciando com Patterns em Java, seria possível mostrar mais aplicações práticas e com exemplos bem didáticos para que pessoas como eu, que também estão iniciando possam melhor compreender sobre o Singleton ? Abraços e obrigado
postado por Gilson em 13/10/2006 às 23:21
Ola, Primeiramente, parabens pela didatica, muito bem explicado. Estava aplicando este padrao em uma aplicacao web, no que tange a aproveitar a conexao JDBC com o BD Mysql. Estou com duvida será que se um usuario der o commit enquando outro der o rollback, como os dois usam a mesma conexao pelo tomcat, nao vai dar problema ? Grato, Helder
postado por Helder em 28/10/2006 às 23:21
Helder, os dois não aproveitariam a mesma conexão não. O que eu falei que é comum ver gente fazendo é deixar um singleton fazendo a criação de novas conexões, mas as conexões não seriam singletons.
postado por David Pereira em 31/10/2006 às 23:21
De todos os artigos que achei sobre Singleton, este é o mais simples de se entender. Parabéns.
postado por Fernanda Angelo em 05/12/2006 às 23:21
Utlizei esse pattern na minha classe ConnectionFactory em minha aplicação. Dessa maneira, haverá apenas uma conexão válida, para a aplicação inteira.
postado por Muito Boa Essa Matéria em 12/01/2007 às 23:21
Olá.. parebéns pela matéria..bom.. há uma boa prática que foi esquecida nesta classe Singleton.. se você não colocar a classe como final será possivel clonar a classe. Ou seja, todos os objetos comuns estendem de Object, e object implementa cloneable.. no caso se a sua classe singleton não for final o método clone poderá ser acessado quebrará a segurança proposta pelo singleton..
postado por Luciano Rafael em 12/02/2007 às 23:21
Gosto muito dos artigos e tutoriais aqui apresentados. Sua linguagem e exemplos são bem esplicativos e de fácil entendimento. Mas não entendo por que não disponibilizar em PDF. Por que não ?
postado por Alessandro Bezerra Moreira em 17/05/2007 às 23:21
Olá David, gostei muito desse tutorial, e simples e objetivo. Por favor me tire uma dúvida, com base nos conceitos que vc passou a listagem 3 não apresentaria problemas? Da forma que foi implementado sempre que o construtor da chamado e criará uma nova instância. Não seria necessário utilizar a mesma estratégia de criação que vc utilizou nas listagem 1 e 2? Abraço.
postado por Cirismar Coutinho em 06/06/2007 às 23:21
Muito bom o artigo. Sugiro que sejam colocados exemplos corretos e incorretos.
postado por Luciano em 12/07/2007 às 23:21
Comente!

Observações

Os campos em negrito são obrigatórios.

Para evitar problemas, este espaço é moderado. Após o envio do comentário será necessário aguardar pela sua aprovação.