Mostrando postagens com marcador Padrões de Projeto. Mostrar todas as postagens
Mostrando postagens com marcador Padrões de Projeto. Mostrar todas as postagens

quinta-feira, 31 de março de 2016

Padrão Singleton "Double-checked" e Padrão Singleton "Instantâneo"

Padrão Singleton é bastante conhecido e usado como solução para diversas finalidades, onde por questão de controle, segurança e uso da memória desejamos ter apenas uma única instância de uma determinada classe, o que seria o exemplo de uma classe de configurações gerais de um sistema, não poderíamos ter um sistema estável sem garantir que existe apenas uma instancia com essas configurações.

Então abaixo vou mostrar um código de implementação de um singleton “Double-checked” que garante a unicidade da classe mesmo em um ambiente multithread e logo depois vou fazer algumas explicações.

public class MeuSingletonSincronizado{
     
      ... //outros atributos da classe

      private volatile static MeuSingletonSincronizado instance; //uso da palavra reservada volatile
     
      private MeuSingletonSincronizado (){
           
... //algo que preciso ser feito no construtor
     
}
     
      public static MeuSingletonSincronizado getInstance(){
           
            if(instance == null){ //primeira checagem
                 
                  synchronized (MeuSingletonSincronizado.class){
                       
                        if(instance == null){ //segunda checagem
                            
                             instance = new MeuSingletonSincronizado();
                       
                        }
                       
                  }
                 
            }
           
            return instance;
      }
     
      ... //outros métodos da classe

}

Vamos às considerações... Primeiro, o uso do modificador volatile na variável que guarda a instância do nosso singleton faz com que o java sinalize ao processador que este atributo sempre vai ser lido e escrito diretamente da memória principal ignorando o cache, evitando valores diferentes em ambientes multi-threads.


Porque usar a dupla checagem? Quando usamos esse modelo, observe que só sincronizamos a classe no método que retorna a instância enquanto houver a possibilidade de essa instância ser nula, depois disso, não há necessidade dessa sincronização. Isso faz com que ganhemos performance e segurança de que só haverá uma instância da classe.

Já na opção instantâneo, o que muda é que inicializamos a instância do singleton no momento da declaração da variável. O problema é que dependendo do que o seu singleton fizer e da quantidade de classes do tipo singleton que você codificar isso pode trazer um consumo maior de memória, pois o objeto será instanciado no momento que a classe for lida pela JVM mesmo que não venha a ser usada...

public class MeuSingletonSincronizado{
     
      ... //outros atributos da classe

      Private final volatile static MeuSingletonSincronizado instance = new MeuSingletonSincronizado();
     
      private MeuSingletonSincronizado(){}// construtor
     
     
      public static MeuSingletonSincronizado getInstance(){
                 
            return instance;

      }
     
      ... //outros métodos da classe

}

sexta-feira, 15 de agosto de 2014

Padrões de Projeto - Strategy

       Padrões de projeto servem para estruturar a forma como os sistemas são construídos de modo a facilitar tanto a própria construção quanto a manutenção. Os padrões de projeto baseiam-se nos princípios de programação e em boas práticas, e se tornaram padrões devido terem sido usados várias vezes e terem alcançado bons resultados. O padrão STRATEGY visa tornar a estrutura do projeto mais flexível, tornando-o mais receptível a mudanças. Ele se baseia em 3 princípios:
  • Programar para interface ao invés de programar para implementação;
  • Separar o que varia do que permanece igual, encapsulando o que varia;
  • Dar preferência a composição do que a herança.
       O livro Use a Cabeça - Padrões de projetos traz um exemplo de um "jogo" que ele categoriza como um simulador de patos, que trabalha com patos de diferentes tipos: patos de verdade, patos de borracha, patos de madeira... e está sujeito a trabalhar com mais tipos de patos diferentes no futuro. A questão é que eles variam seus comportamentos, afinal, patos de madeira não voam nem grasnam, os de borracha fazem barulho, que no entanto não é um grasnar de patos de verdade, e também não voam. E por fim, no futuro ainda podem entrar outros tipos de patos no sistema. Como lidar com a mudança?
       Podemos ver a solução logo abaixo:

       Os comportamentos que pertencem a todos os patos (mostrar o pato na tela e nadar) que pelo menos por enquanto não variam, são métodos comuns (display() e swin()) que não precisaram ser "encapsulados" por uma interface em grupos de algorítimos, podendo o desenvolvedor usar apenas a sobrescrita de métodos dada pela herança caso ache necessário, o que é uma verdade no caso de display(), afinal cada pato tem uma exibição.
       Já os métodos que setam o comportamento de voar e grasnar, como variam em cada tipo de pato, foram "encapsulados" através de uma interface criada para cada um deles (FlyBehavior e QuackBehavior respectivamente). Agora esses comportamentos que compõe o nosso objeto Duck deixaram de ser métodos e passaram a ser variáveis de instância para objetos que implementem a interface FlyBehavior e QuackBehavior.
       Qual a vantagem? Bem, digamos que eu queira criar um pato de plástico, que nada porém não faz barulho, o que eu preciso adicionar de extra? Nada, basta na hora de criar a classe PatoDePlastico fazer ela instanciar a classe FlyNoWay e MuteQuack. E se eu quiser um apito para chamar patos, não posso estender de pato, afinal, não é um pato, mas eu preciso do som de pato, o que fazer? É simples! Basta usar a interface QuackBehavior como fizemos na classe Duck. Ou seja, temos um sistema flexível e expansível.
       Agora um pouco de código para mostrar como essas classes se comunicam:
      
       Como seria o construtor de uma classe que herda de Duck?
public class MallardDuck extends Duck {
       public MallardDuck(FlyBehavior fb, QuackBehavior qb) {
              flyBehavior = fb;
              quackBehavior = qb;
       }...
       O método performFly() e performQuack() da classe Duck respectivamente...
       public void performFly(){
              flyBehavior.fly();
       }
       public void performQuack(){
             QuackBehavior.quack();
       }...
       Agora os métodos da classe Duck que deixam os comportamentos de voar e grasnar dinâmicos... eles devem receber um comportamento como parâmetro.
       public void setFlyBehavior(FlayBehavior fb) {
              flyBehavior = fb;
       }
       public void setQuackBehavior(QuackBehavior qb) {
              quackBehavior = qb;
       }... 
       Pronto, o PADRÃO STRATEGY foi aplicado com sucesso. Veja que nos códigos mostrados, não nos preocupamos com as classes que implementam as interfaces, isso porque abstraímos essas classes encapsulando-as através das interfaces.

Fonte: livro Use a Cabeça - Padrões de Projeto, 2a Edição.