Padrões de Projeto em Java
Introdução
Este artigo apresenta as formas que são utilizadas ao escrever classes em java, basicamente como se comporta o programa na instanciação de uma classe através de seus construtores.
Construtores em Java
A maneira padrão de construir objetos em Java é através de construtores:
- Toda classe tem um construtor: operação declarada com o mesmo nome da classe, que não retorna valor e só pode ser usada na inicialização;
- O construtor é uma tarefa de classe (estática);
- Se um construtor não é explicitamente declarado em uma classe, o sistema cria um construtor default para a classe;
- Todo construtor inicializa a hierarquia de classes do objeto antes de executar;
- Todo construtor sempre contém ou uma referência à superclasse (implícita ou explícita) ou uma referência a outro construtor da classe como primeira ou única instrução;
Escrever:
public class Coisa {}
É o mesmo que:
public class Coisa extends java.lang.Object {
public Coisa() {
super();
}
}
Onde:
super(); Chama construtor default da superclasse
extends java.lang.Object e super(); são inseridos automaticamente pelo sistema!
Construtores Invisíveis
Implicações
public class OutraCoisa extends Coisa {} funciona enquanto Coisa não tiver construtor explícito:
public class Coisa {} se um construtor for adicionado explicitamente a Coisa:
public class Coisa extends java.lang.Object {
private String nome;
public Coisa(String nome) {
this.nome = nome;
}
}
A subclasse OutraCoisa não compila mais, pois tem um construtor implícito que chama o construtor default da superclasse (identificado pela assinatura).
public class OutraCoisa extends Coisa {
public OutraCoisa() {
super();
}
}
Na nova versão de Coisa, o construtor default não existe mais, pois foi substituído pelo construtor que requer um argumento: Coisa(String).
Sobrecarga de Construtores
Duas maneiras de construir uma coisa:
Coisa c = new Coisa(); cria uma Coisa Sem Sentido e
Coisa d = new Coisa("Algo Útil"); cria uma Coisa que guarda “Algo Útil”.
Apenas o segundo construtor faz chamada via super() à superclasse.
Além dos Construtores
Construtores em Java definem maneiras padrão de construir objetos. Sobrecarga permite ampla flexibilidade.
Alguns problemas em depender de construtores:
- Cliente pode não ter todos os dados necessários para instanciar um objeto;
- Cliente fica acoplado a uma implementação concreta (precisa saber a classe concreta para usar new com o construtor);
- Cliente de herança pode criar construtor que chama métodos que dependem de valores ainda não inicializados (vide processo de construção);
- Objeto complexo pode necessitar da criação de objetos menores previamente, com certo controle difícil de implementar com construtores;
- Não há como limitar o número de instâncias criadas;
O Factory Method
Uma alternativa muito utilizada à criação de objetos é o Factory Method que adia a decisão sobre qual classe concreta instanciar.
"Definir uma interface para criar um objeto mas deixar que subclasses decidam que classe instanciar. Factory Method permite que uma classe delegue a responsabilidade de instanciamento às subclasses."
O acesso a um objeto concreto será através da interface conhecida, através de sua superclasse, mas sem saber qual implementação concreta está sendo usada.
Um Factory Method define uma interface comum para criar objetos, onde a informação de qual objeto concreto será utilizado pode ser fornecida de diversas maneiras, via parâmetro, arquivo de configuração, etc.
public static Thing createThing(int type) {
if (type == 1) {
creator = new ConcreteThingCreator();
return creator.createThing();
}
...
}
Vantagens
- Criação de objetos é desacoplada do conhecimento do tipo concreto do objeto;
- Conecta hierarquias de classe paralelas;
- Facilita a extensibilidade;
Desvantagens
Ainda é preciso saber a classe concreta do criador de instâncias.
Conclusão
Em projetos onde o isolamento de objetos é uma necessidade, o uso de interfaces bem definidas e um mecanismo como o Factory Method apresentam-se como uma poderosa ferrmenta de auxílio na sua construção.