Rodrigo Allemand

Tag: Singleton

DDD – Fabricando e Encontrando Objetos

por Rodrigo Allemand em Aug.17, 2009, em DDD

Antes de mais nada, este post não é – como nenhumk dos outros desta série – focado extritamente em DDD. Leia o primeiro post da séries para entender melhor…

Em qualquer sistema OO, vc trabalha com….. objetos (ohhhhhhhh)

Qualquer objeto ‘precisa’ ser….. criado antes de ser utilizado…. (ohhhhhhh)

Qual a melhor maneira de se criar objeto? (errr…. humm….. bem…….)

Muitas são as maneiras… usando um construtor, por DI (Dependency Injection), por fábricas, etc.

O mais utilizado são as fábricas, ou Factories conforme catalogado pelo GoF, ou Gang of Four.

Resumidamente, “o padrão Factory fornece uma interface para a criação de famílias de objetos correlatos ou dependentes sem a necessidade de especificar a classe concreta destes objetos”.

Diversos exemplos de fábricas existem espalhados pela internet, e eu não vou colocar mais um aqui. Procure, rs!

A motivação inicial do padrão era a criação de objetos complexos, fazendo com que a lógica estivesse toda em um unico lugar… princípio de DRY nos promórdios da Arquitetura de Software!

Porém, certos objetos alem de serem complexos, precisavam de um processo de construção demorado. Algumas tecnicas para a sulução deste problema era ‘reter’ o objeto contruido e utilizá-lo como um ponto de acesso único, otimizando assim o processo de construção.

Com isso, por muitas vezes os desenvolvedores juntavam dois padrões de projetos para sanar o problema de contrução complexa e demorada, utilizando Factory e ‘Singletons’ para colocar objetos a disposição do ‘domínio’.

Colocar fábricas a disposição dos desenvolvedores, por muitas vezes, mascarava onde realmente estes objetos deveriam ser criados. Poderiam existir inúmeras fábricas em um único projeto, como eu já presenciei num passado não muito distante. Era DaoFactory pra cá, AbstractDaoFactory pra lá, ReportFactory aqui e ServiceFactory acolá! Uma verdadeira macarronada de factories!

Então, como manter um ponto único de acesso para ‘encontrar’ os objetos?

Fowler resolveu colocar tudo em um unico padrão e o nomeou de Registry, ou Registro.

De acordo com Fowler, Registry é

Um objeto conhecido que outros objetos podem usar para encontrar objetos e serviços comuns.

A função do Registro é:

  1. Criar objetos
  2. Encapsular complexidades de criação
  3. Reter objetos criados
  4. Funcionar como ‘local dos objetos’

Com isso, se você quizer saber ou precisar de um objeto e o seu sistems tem um Registro, pergunte a ele!

Normalmente os Registros são factories e singletons mesclados, conforme o exemplo abaixo:

public MyDomainRegistry{
    private static MyDomainRegistry INSTANCE = null;

    private MyDomainRegistry(){
        loadVariables();
    }

    private static MyDomainRegistry instance(){
        //Coloque aqui a sua implementação de Singleton
        return INSTANCE;
    }

    //Posso usar SubDomains
    private ConsultarSubDomain consultarSubDomain;
    //Posso usar Services Services
    private ConversaoService conversaoService;
    //Qualquer objeto que eu queira localizar!
    private MyRepository myRepository;

    private void loadVariables(){
        //Aqui vc deve criar os seua objetos como achar melhor
        this.consultarSubDomain = new ConsultarSubDomain();
    }

    //Aqui vc coloca os métodos estáticos para retornar
    //os objetos que o registro precisa controlar
    public static ConsultarSubDomain consultarSubDomain() {
        return instance().consultarSubDomain;
    }
}

Bem simples, não?

Agora, para você utilizar um objeto, basta solicitar ao registro, assim.

public class FachadaDoDominio {

    private FachadaDoDominio() {
    }

    public static ConsultarSubDomain consultar(){
        return MyDomainRegistry.consultarSubDomain();
    }
}

Comente e Recomende!

5 Comentários :, , , , mais...

Padrões de Projeto e Expressividade de Código

por Rodrigo Allemand em Mar.02, 2009, em Desenvolvimento

Quando eu comecei a vida de desenvolvedor, a minha idéia era que o divisor de águas era quem soubesse escrever “padrões de projeto”. Eu não estava completamente errado. Onde eu errei? Vamos lá…

Christopher Alexander, um renomado arquiteto italiano, uma vez citou:

Cadas padrão descreve um problema no nosso ambiente e o núcleo da sua solução, de tal forma que vc possa utilizar usar esta solução mais de um milhão de vezes, sem nunca faze-lo da mesma maneira.

Christopher Alexander não construia sistemas. Ele construia prédios, casas e cidades. Mas a citação acima se encaixa perfeitamente na definição de padrão de projeto para construção de sistemas! São soluções para um problema conhecido! Não adianta saber “fazer” um padrão de projeto. Vc precisa identificar o problema e achar a melhor solução para este problema, seja ela conforme o criador do padrão de projeto citou ou como você achar melhor. Basta que a definição do padrão seja seguida na sua implementação. Portanto, não grave como a sua classe deve ser para atender um determinado padrão, grave o que o padrão prega, o que ele se propõe a solucionar e os principios de design do padrão.

Outro grande problema encontrado é quanto a nomeção de classes. Quando se nomeia uma classe, deve-se deixar bem claro (porem sem termos um texto como nome) o que a classe faz e como ela foi idealizada. Não só com comentários, mas com os nomes claros, deixando-os entendíveis a primeira vista.

Essa é outra motivação dos padrões. A nomeação é tão importante como a sua implementação. Não adianta vc definir um padrão extremamente bem se uma pessoa que vai desenvolver utilizando essa classe, não conseguir enchergar o que ela realmente faz.

Imagine que vc está entrando em um projeto agora e ao abrir o seu workspace, se depara com uma Classe chamada ConfiguracaoSingleton. Automaticamente vc saberá que se trata de uma instância única da configuração da aplicação.

Ter expressividade no seu código é 80% de um código bem feito! Se alguem entende o que vc se propoz a fazer, as possiveis correções e manutenções (ou até mesmo, usar o seu código como exemplo) fica muito mais facil.

Portanto nomeie bem seu código e saiba o-que-resolve-o-que.

Obs: Vale a pena entender o que é um Anti-pattern tambem!

Para exemplificar melhor, vamos descrever um dos padrões mais conhecidos, mais e mais exemplificados e mais mal-entendidos da história do desenvolvimento orientado a objeto: o Singleton!

O Singleton foi originalmente criado pelo renomado grupo Gang Of Four [GoF], formado por Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides.  Sua definição é:

Garantir que uma classe tenha somente uma instância e fornecer um ponto global de acesso para a mesma.

Resumidamente, a motivação do Singleton é ter um ponto de acesso a uma intancia que seja unica para todo o sistema. As aplicações para este patterns são inúmeras: configuração, tratamento de informação compartilhada, parametrização, manter estado de um objeto, manter instancias de outros objetos que sejam statefull, etc. O qua vai guiar como contruir este objeto é a sua necessidade.

ATENÇÃO: Os códigos utilizados nestes exemplos são meramente ilustrativos.

Vamos ao exemplo mais conhecido de todos:

public class Singleton {

    private static Singleton instance = null;

    private Singleton() {
    }

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

}

Este sem dúvidas é o código mais conhecido como Singleton. Mas ai começam os problemas…

Se eu tiver em um sistema muito concorrido, pode acontecer de duas instancias serem criadas ao mesmo tempo. Se isso for realmente um problema, refatorando o código poderemos ter algo como:

public class Singleton {

	private static Singleton instance = null;

	private Singleton() {
	}

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

}

Sincronizando o método, podemos garantir que apenas uma chamada será processada a cada momento. Mas isso torna o código muito ruim, já que até mesmo depois da criação, todas as chamadas deverão ser sincronizadas e, conforme dito no problema 1, a sua concorrência é grande, o que implica em muitos acessos e uma baixa performance desse método.

Se isso for realmente um problema, para solucionar podemos fazer coisas do tipo:

public class Singleton {

    private static Singleton instance = null;

    private Singleton() {
    }

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

}

Beleza! com isso conseguimos garantir concorrência e performance, correto? Não, não não… sendo bem purista, ainda há uma possibilidade de haver uma concorrencia na linha 09 do último exemplo. Sim, é possível sim (Calma, são apenas exemplos, rs)! Se isso for um problema, refatorando um pouco mais, podemos ter um código assim:

public class Singleton {

    private static Singleton instance = null;

    private Singleton() {
    }

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

}

Pronto! Temos um singleton!!!

Mas ainda temos um probleminha… E se o sistema tiver rolando em Cluster?! Se vc tiver mais de uma JVM, vão existir mais e uma instância do seu singleton, o que deixa de ser singleton!

Bem, perceberam que a ligação entre problema e solução não diz respeito a como codificar. Eu tenho vários exemplos de Singleton acima e até o momento eu não resolvi o meu problema, que é ter uma instância, que suporte concorrência, com performance e em um ambiente distribuido. E eu poderia fazer milhões de implementações diferentes para conseguir chegar ao meu objetivo!

Mas e se eu não me importasse de ter mais de uma instancia no Cluster? E se a minha concorrência fosse muito pequena a ponto de não atrapalhar a minha performance? Isso cabe a você!!! Como eu disse, conhecer o problema e dar a melhor solução possivel!

Existem todos os tipos de pessoas! Existem aqueles que pensam em uma solução, implementam um ou mais padrões sem ao menos conhecer o que está fazendo; como tambem existem aqueles que implementam vários padrões de projeto para um simples Hello World e mesmo assim, a implementação está errada!

Só para termos ideia, vou colocar mais um exemplo de Singleton. Neste eu utilizo o contexto de uma aplicação Web para individualizar a minha instancia.

public class Singleton {

    private static final String KEY = "singleton";

    private Singleton() {
    }

    public Singleton getInstance(ServletContext context){
        Object obj = null;
        obj = context.getAttribute(KEY);
        if(obj == null){
            synchronized (Singleton.class) {
                Singleton singleton = new Singleton();
                context.setAttribute(KEY, singleton);
                return singleton;
            }
        }
        return Singleton.class.cast(obj);
    }

}

Portanto, entender o seu problema, saber qual padrão de projeto aplicar e nomea-lo corretamente é o divisor de aguas.

Até!

Comente e Recomende!

3 Comentários :, , , , mais...

Procurando por algo?

Use o campo abaixo para procurar por todo o site:

Ainda não achou? Deixe um comentário ou me mande um email que eu cuido disso!

Minhas indicações!

Alguns blogs que eu recomendo...