Ao modelar classes, qual é a maneira preferida de inicializar:
- Construtores ou
- Métodos de fábrica
E quais seriam as considerações para usar qualquer um deles?
Em certas situações, prefiro ter um método de fábrica que retorne nulo se o objeto não puder ser construído. Isso torna o código limpo. Posso simplesmente verificar se o valor retornado não é nulo antes de executar uma ação alternativa, em contraste com a exceção de um construtor. (Eu pessoalmente não gosto de exceções)
Digamos, eu tenho um construtor em uma classe que espera um valor de ID. O construtor usa esse valor para preencher a classe do banco de dados. No caso em que não existe um registro com o ID especificado, o construtor lança um RecordNotFoundException. Nesse caso, terei de incluir a construção de todas essas classes dentro de um bloco try..catch.
Em contraste com isso, posso ter um método de fábrica estático nessas classes que retornará nulo se o registro não for encontrado.
Qual abordagem é melhor nesse caso, construtor ou método de fábrica?
Pergunte a si mesmo o que são e por que as temos. Ambos estão lá para criar a instância de um objeto.
Nenhuma diferença até agora. Agora imagine que temos vários tipos de escola e queremos passar do ElementarySchool para o HighSchool (que é derivado de um ElementarySchool ou implementa a mesma interface ISchool que o ElementarySchool). A alteração do código seria:
No caso de uma interface, teríamos:
Agora, se você tiver esse código em vários locais, poderá ver que o uso do método factory pode ser bem barato, porque uma vez que você altera o método factory (se usarmos o segundo exemplo com interfaces).
E esta é a principal diferença e vantagem. Quando você começa a lidar com hierarquias de classe complexas e deseja criar dinamicamente uma instância de uma classe a partir dessa hierarquia, obtém o código a seguir. Os métodos de fábrica podem usar um parâmetro que diz ao método qual instância concreta instanciar. Digamos que você tenha uma classe MyStudent e precise instanciar o objeto ISchool correspondente para que seu aluno seja membro dessa escola.
Agora você tem um lugar no aplicativo que contém a lógica comercial que determina qual objeto ISchool instanciar para diferentes objetos IStudent.
Portanto - para classes simples (objetos de valor, etc.), o construtor é bom (você não deseja sobrecarregar seu aplicativo), mas para hierarquias de classes complexas o método de fábrica é a maneira preferida.
Dessa forma, você segue o primeiro princípio de design da turma dos quatro livros "Programa para uma interface, não uma implementação".
fonte
IFood sandwich = new Sandwich(Cheese chz, Meat meat);
eIFood soup = new Soup(Broth broth, Vegetable veg);
Como a fábrica e / ou o construtor podem ajudar aqui?Você precisa ler (se tiver acesso a) Java Efetivo 2 Item 1: Considere métodos estáticos de fábrica em vez de construtores .
Métodos de fábrica estática vantagens:
Métodos estáticos de fábrica desvantagens:
fonte
( factory methods are better than Constructors. ( Item-1 ) ) Effective java
Por padrão, os construtores devem ser preferidos, porque são mais simples de entender e escrever. No entanto, se você precisar especificamente dissociar as sutilezas de construção de um objeto de seu significado semântico, conforme entendido pelo código do cliente, seria melhor usar fábricas.
A diferença entre construtores e fábricas é análoga a, digamos, uma variável e um ponteiro para uma variável. Há outro nível de indireção, que é uma desvantagem; mas também há outro nível de flexibilidade, o que é uma vantagem. Portanto, ao fazer uma escolha, você deve fazer essa análise de custo versus benefício.
fonte
Use uma fábrica somente quando precisar de controle extra com a criação de objetos, de uma maneira que não poderia ser feita com construtores.
As fábricas têm a possibilidade de armazenar em cache, por exemplo.
Outra maneira de usar fábricas é em um cenário em que você não sabe o tipo que deseja construir. Muitas vezes, você vê esse tipo de uso nos cenários de fábrica de plug-ins, nos quais cada plug-in deve derivar de uma classe base ou implementar algum tipo de interface. A fábrica cria instâncias de classes derivadas da classe básica ou que implementam a interface.
fonte
Uma citação de "Java Efetivo", 2ª ed., Item 1: Considere métodos estáticos de fábrica em vez de construtores, p. 5:
"Observe que um método de fábrica estático não é o mesmo que o padrão de Método de Fábrica dos Padrões de Design [Gamma95, p. 107]. O método de fábrica estático descrito neste item não tem equivalente direto nos Padrões de Design."
fonte
Além de "java eficaz" (como mencionado em outra resposta), outro livro clássico também sugere:
Por exemplo. não escreva
mas escreva
O livro chega ao ponto de sugerir tornar o
Complex(float)
construtor privado, para forçar o usuário a chamar o método de fábrica estática.fonte
from…
,to…
,parse…
,with…
, e assim por diante. Lembre-se de que as classes java.time são criadas para serem imutáveis, mas algumas dessas convenções de nomenclatura também podem ser úteis para as classes mutáveis.Um exemplo concreto de um aplicativo CAD / CAM.
Um caminho de corte seria feito usando um construtor. É uma série de linhas e arcos que definem um caminho a ser cortado. Embora a série de linhas e arcos possa ser diferente e ter coordenadas diferentes, ela é facilmente manipulada passando uma lista para um construtor.
Uma forma seria feita usando uma fábrica. Porque, enquanto houver uma classe de forma, cada forma será configurada de maneira diferente, dependendo do tipo de forma. Não sabemos que formato vamos inicializar até que o usuário faça uma seleção.
fonte
Esse processo definitivamente deve estar fora de um construtor.
O construtor não deve acessar o banco de dados.
A tarefa e o motivo de um construtor é inicializar membros de dados e estabelecer invariantes de classe usando valores passados para o construtor.
Para todo o resto, uma abordagem melhor é usar o método de fábrica estática ou, em casos mais complexos, uma fábrica ou classe de construtor separada .
Algumas linhas de guia do construtor da Microsoft :
E
fonte
Às vezes, você precisa verificar / calcular alguns valores / condições ao criar um objeto. E se ele pode lançar uma exceção - o constructro é uma maneira muito ruim. Então, você precisa fazer algo assim:
Onde todos os cálculos adicionais estão em init (). Mas somente você, como desenvolvedor, realmente conhece esse init (). E é claro, depois de meses, você simplesmente esquece. Mas se você tem uma fábrica - faça tudo o que precisa em um método para ocultar esse init () da chamada direta - para que não haja problemas. Com essa abordagem, não há problemas em cair na criação e no vazamento de memória.
Alguém lhe falou sobre cache. É bom. Mas você também deve se lembrar do padrão Flyweight, que é bom de usar com o modo Factory.
fonte