O que são métodos estáticos de fábrica?

261

O que é um método de "fábrica estática"?

freddiefujiwara
fonte
Um método alternativo de fábrica estática é usar injeção de dependência.
precisa saber é o seguinte
1
@ThangPham A resposta de Jason Owen é falha porque pretende falar sobre o padrão de Método de Fábrica, que é muito diferente do padrão de método de fábrica estático sobre o qual ele realmente fala. Portanto, embora ele responda bem à pergunta real, não acho que possa ser aceito em seu estado atual, porque traz um padrão não relacionado e aumenta a confusão já incrivelmente comum sobre a diferença entre os dois padrões.
Theodore Murdock
@CMCDragonkai Acho que injeção de dependência e fábrica estática são diferentes. A fábrica estática pode ser necessária mesmo no caso de injeção de dependência para instanciar dependências a serem injetadas.
precisa saber é o seguinte

Respostas:

126

Evitamos fornecer acesso direto às conexões com o banco de dados porque elas consomem muitos recursos. Portanto, usamos um método estático de fábrica getDbConnectionque cria uma conexão se estiver abaixo do limite. Caso contrário, ele tenta fornecer uma conexão "sobressalente", falhando com uma exceção se não houver.

public class DbConnection{
   private static final int MAX_CONNS = 100;
   private static int totalConnections = 0;

   private static Set<DbConnection> availableConnections = new HashSet<DbConnection>();

   private DbConnection(){
     // ...
     totalConnections++;
   }

   public static DbConnection getDbConnection(){

     if(totalConnections < MAX_CONNS){
       return new DbConnection();

     }else if(availableConnections.size() > 0){
         DbConnection dbc = availableConnections.iterator().next();
         availableConnections.remove(dbc);
         return dbc;

     }else {
         throw new NoDbConnections();
     }
   }

   public static void returnDbConnection(DbConnection dbc){
     availableConnections.add(dbc);
     //...
   }
}
Matthew Flaschen
fonte
se entendi correto, você pode adicionar availableConnections.add (db) ao método returnDbConnection (DbConnection db)?
Haifeng Zhang
@haifzhan, não tem a intenção de ser completo, mas tudo bem.
Matthew Flaschen
@MatthewFlaschen também deve o totalConnections ser diminuído enquanto a conexão é retornada?
rolling stone
@ Sridhar, não, é o número de conexões que existem (rastreadas para que mais de MAX_CONNS não sejam criadas), não o número que está circulando.
Matthew Flaschen
O método @MatthewFlaschen you será capturado pelo sonarcube como bug-bloqueador se DbConnection for Closeable.
Awan Biru
477

O padrão estático do método de fábrica é uma maneira de encapsular a criação de objetos. Sem um método de fábrica, você poderia simplesmente chamar a classe construtor diretamente: Foo x = new Foo(). Com este padrão, você iria em vez chamar o método de fábrica: Foo x = Foo.create(). Os construtores são marcados como particulares, portanto, não podem ser chamados, exceto de dentro da classe, e o método factory é marcado como staticpara que possa ser chamado sem primeiro ter um objeto.

Existem algumas vantagens nesse padrão. Uma é que a fábrica pode escolher entre muitas subclasses (ou implementadores de uma interface) e devolvê-la. Dessa forma, o chamador pode especificar o comportamento desejado por meio de parâmetros, sem precisar conhecer ou entender uma hierarquia de classes potencialmente complexa.

Outra vantagem é, como apontaram Matthew e James, controlar o acesso a um recurso limitado, como conexões. Essa é uma maneira de implementar conjuntos de objetos reutilizáveis - em vez de construir, usar e derrubar um objeto, se a construção e a destruição forem processos caros, pode fazer mais sentido construí-los uma vez e reciclá-los. O método de fábrica pode retornar um objeto instanciado existente e não utilizado, se ele tiver um, ou construir um se a contagem de objetos estiver abaixo de algum limite inferior ou lançar uma exceção ou retornar nullse estiver acima do limite superior.

Conforme o artigo da Wikipedia, vários métodos de fábrica também permitem interpretações diferentes de tipos de argumentos semelhantes. Normalmente, o construtor tem o mesmo nome que a classe, o que significa que você só pode ter um construtor com uma determinada assinatura . As fábricas não são tão restritas, o que significa que você pode ter dois métodos diferentes que aceitam os mesmos tipos de argumento:

Coordinate c = Coordinate.createFromCartesian(double x, double y)

e

Coordinate c = Coordinate.createFromPolar(double distance, double angle)

Isso também pode ser usado para melhorar a legibilidade, como observa Rasmus.

Jason Owen
fonte
32
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.
Josh luz do sol
A recompensa para mim nesta resposta é a referência a objetos agrupáveis. É exatamente assim que estou usando o padrão de método de fábrica. Os métodos de fábrica são fornecidos para ajudar a controlar o ciclo de vida de um objeto: "create" extrai um objeto do pool ou cria uma nova instância se o pool estiver vazio, "destroy" o devolve ao pool para reutilização futura.
precisa saber é o seguinte
2
Você realmente deveria estar usando "padrão de método de fábrica estático" onde quer que diga "padrão de método de fábrica" ​​nesta postagem, está usando o termo errado. Além disso, você está vinculando ao artigo da Wikipedia com um padrão diferente do que está falando. O padrão Factory Method provavelmente deveria ter sido chamado de "Factory Interface", porque envolve o uso de vários objetos de fábrica que implementam uma interface de fábrica para permitir que um único algoritmo produza e trabalhe com instâncias de uma interface, aceitando um objeto de fábrica que pode produzir a subclasse específica desejada.
Theodore Murdock
8
Eu concordo com @TheodoreMurdock. Você está usando o termo errado. O que você está falando é o "Static Factory Method" de Joshua Bloch, mas você usa o termo "Factory Method Pattern" do GoF. Edite-o para que outras pessoas não entendam mal.
Emeraldhieu 19/09/2014
1
Observe que o construtor não precisa ser privado. Uma classe poderia fornecer métodos públicos de fábrica estática e construtores.
Kevin
171

NOTA! "O método estático de fábrica NÃO é o mesmo que o padrão do Método de Fábrica " (c) Java efetivo, Joshua Bloch.

Método Factory: "Defina uma interface para criar um objeto, mas deixe as classes que implementam a interface decidirem qual classe instanciar. O método Factory permite que uma classe adie a instanciação para subclasses" (c) GoF.

"O método estático de fábrica é simplesmente um método estático que retorna uma instância de uma classe." (c) Java efetivo, Joshua Bloch. Geralmente esse método está dentro de uma classe específica.

A diferença:

A idéia principal do método estático de fábrica é obter controle sobre a criação de objetos e delegá-lo do construtor ao método estático. A decisão do objeto a ser criado é como na Abstract Factory feita fora do método (no caso comum, mas nem sempre). Enquanto a idéia-chave (!) Do Factory Method é delegar a decisão de qual instância da classe criar dentro do Factory Method. Por exemplo, a implementação clássica de Singleton é um caso especial do método estático de fábrica. Exemplo de métodos estáticos de fábrica comumente usados:

  • valor de
  • getInstance
  • newInstance
Grygoriy Gonchar
fonte
Você pode me dizer a diferença entre os novos A () e A.newInstance ()? e dentro da A.newInstance, o que devemos fazer?
Shen
69

A legibilidade pode ser melhorada por métodos estáticos de fábrica:

Comparar

public class Foo{
  public Foo(boolean withBar){
    //...
  }
}

//...

// What exactly does this mean?
Foo foo = new Foo(true);
// You have to lookup the documentation to be sure.
// Even if you remember that the boolean has something to do with a Bar
// you might not remember whether it specified withBar or withoutBar.

para

public class Foo{
  public static Foo createWithBar(){
    //...
  }

  public static Foo createWithoutBar(){
    //...
  }
}

// ...

// This is much easier to read!
Foo foo = Foo.createWithBar();
Rasmus Faber
fonte
Então, tentei implementar o seu exemplo, mas não tenho certeza de como isso funciona. Os dois métodos createWithBar e createWithoutBar deveriam chamar 2 construtores particulares dentro da classe Foo?
Essej 8/08/16
@Baxtex: Sim. Cada um chamará um construtor privado. Talvez apenas o mesmo: private Foo(boolean withBar){/*..*/} public static Foo createWithBar(){return new Foo(true);} public static Foo createWithoutBar(){return new Foo(false);}
Rasmus Faber
Eu acho que isso não é "escala" muito bem. Se você tiver três ou mais parâmetros, como você pode usar essa ideia e criar um bom nome para o método?
Dherik
@ Dherik: Então você provavelmente deve usar o padrão construtor: new FooBuilder (). WithBar (). WithoutFoo (). WithBaz (). Build ();
Rasmus Faber 29/11
21
  • possuem nomes, diferentemente dos construtores, que podem esclarecer o código.
  • não precisa criar um novo objeto em cada chamada - os objetos podem ser armazenados em cache e reutilizados, se necessário.
  • pode retornar um subtipo de seu tipo de retorno - em particular, pode retornar um objeto cuja classe de implementação é desconhecida para o chamador. Esse é um recurso muito valioso e amplamente utilizado em muitas estruturas que usam interfaces como o tipo de retorno dos métodos estáticos de fábrica.

de http://www.javapractices.com/topic/TopicAction.do?Id=21

soldier.moth
fonte
18

Tudo se resume à manutenção. A melhor maneira de colocar isso é que sempre que você usa a newpalavra-chave para criar um objeto, você está acoplando o código que está gravando em uma implementação.

O padrão de fábrica permite separar como você cria um objeto do que faz com ele. Quando você cria todos os seus objetos usando construtores, está essencialmente conectando o código que usa o objeto a essa implementação. O código que usa seu objeto é "dependente" desse objeto. Isso pode não parecer muito importante na superfície, mas quando o objeto muda (pense em alterar a assinatura do construtor ou em subclassificar o objeto), é necessário voltar e religar as coisas em todos os lugares.

Hoje, as fábricas foram largamente descartadas em favor do uso de injeção de dependência, porque exigem muito código de placa de caldeira que acaba sendo um pouco difícil de manter. A injeção de dependência é basicamente equivalente às fábricas, mas permite que você especifique como seus objetos são conectados de forma declarativa (por meio de configurações ou anotações).

cwash
fonte
3
Você está dizendo que as fábricas precisam de um resgate? ;)
John Farrell
4
Haha! Neste dia e idade eu acho que todos nós poderíamos usar um resgate ... :)
cwash
11

Se o construtor de uma classe for privado, você não poderá criar um objeto para a classe de fora dela.

class Test{
 int x, y;
 private Test(){
  .......
  .......
  }
}

Não podemos criar um objeto para a classe acima de fora dela. Portanto, você não pode acessar x, y de fora da classe. Então, qual é o uso dessa classe?
Aqui está o método Answer: FACTORY .
Adicione o método abaixo na classe acima

public static Test getObject(){
  return new Test();
}

Então agora você pode criar um objeto para esta classe de fora dela. Desse jeito...

Test t = Test.getObject();

Portanto, um método estático que retorna o objeto da classe executando seu construtor privado é chamado como método FACTORY
.

Santhosh
fonte
1
Por que você chama isso de "solução"? Declarar um construtor privado não é um "problema", é um padrão de design.
Ojonugwa Jude Ochalifu
1
Atualizada. Obrigado de qualquer forma
Santhosh
Oi, @Santhosh Estou preocupado: por que você não deixa o construtor privado público? Se você não deseja criar subclasse, tudo bem para mim, mas se não pretendo criar construtor privado, temos algum benefício em Static Factory Methodrelação ao construtor público?
Shen
9

Pensei em acrescentar alguma luz a este post sobre o que sei. Usamos essa técnica extensivamente em nossa recent android project. Em vez de creating objects using new operatorvocê também pode usar static methodpara instanciar uma classe. Listagem de código:

//instantiating a class using constructor
Vinoth vin = new Vinoth(); 

//instantiating the class using static method
Class Vinoth{
  private Vinoth(){
  }
  // factory method to instantiate the class
  public static Vinoth getInstance(){
    if(someCondition)
        return new Vinoth();
  }
}

Os métodos estáticos suportam a criação condicional de objetos : toda vez que você invoca um construtor, um objeto é criado, mas você pode não querer isso. suponha que você queira verificar alguma condição apenas para criar um novo objeto. Você não criaria uma nova instância do Vinoth todas as vezes, a menos que sua condição seja satisfeita.

Outro exemplo extraído do Java eficaz .

public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
}

Este método converte um valor primitivo booleano em uma referência de objeto booleano. O Boolean.valueOf(boolean)método nos ilustra, nunca cria um objeto. A capacidade de static factory methodsretornar o mesmo objeto de repetidas invocationspermite que as classes mantenham controle estrito sobre quais instâncias existem a qualquer momento.

Static factory methodsé que, diferentemente constructors, eles podem retornar um objectde qualquer subtypetipo de retorno. Uma aplicação dessa flexibilidade é que uma API pode retornar objetos sem tornar suas classes públicas. Ocultar classes de implementação dessa maneira leva a uma API muito compacta.

Calendar.getInstance () é um bom exemplo para o acima, cria-se, dependendo da localidade um BuddhistCalendar, JapaneseImperialCalendarou por um padrão Georgian.

Outro exemplo que eu poderia pensar é Singleton pattern: onde você torna seus construtores privados, cria um getInstancemétodo próprio , onde você garante que sempre haja apenas uma instância disponível.

public class Singleton{
    //initailzed during class loading
    private static final Singleton INSTANCE = new Singleton();

    //to prevent creating another instance of Singleton
    private Singleton(){}

    public static Singleton getSingleton(){
        return INSTANCE;
    }
}
Thalaivar
fonte
4

Um método de fábrica, um método que abstrai a instanciação de um objeto. Geralmente as fábricas são úteis quando você sabe que precisa de uma nova instância de uma classe que implemente alguma interface, mas não conhece a classe de implementação.

Isso é útil ao trabalhar com hierarquias de classes relacionadas, um bom exemplo disso seria um kit de ferramentas da GUI. Você pode simplesmente codificar as chamadas aos construtores para implementações concretas de cada widget, mas se você quiser trocar um kit de ferramentas por outro, terá muitos lugares para mudar. Ao usar uma fábrica, você reduz a quantidade de código que precisaria alterar.

Bryan Kyle
fonte
Supondo que sua fábrica retorne um tipo de interface, e não a classe concreta com a qual você está lidando.
Bill Lynch
1
Esta resposta é sobre o padrão de design do método de fábrica e não os métodos de fábrica estáticos. Um método estático de fábrica é simplesmente um método estático público que retorna uma instância de uma classe. Consulte o Capítulo 2 do Java efetivo para obter mais detalhes.
Josh luz do sol
4

Uma das vantagens que resulta da fábrica estática é que essa API pode retornar objetos sem tornar suas classes públicas. Isso levou a uma API muito compacta. Em java, isso é alcançado pela classe Collections, que oculta cerca de 32 classes, o que a torna muito compacta.

Rakesh Chauhan
fonte
2

Um método estático de fábrica é bom quando você deseja garantir que apenas uma única instância retorne a classe de concreto a ser usada.

Por exemplo, em uma classe de conexão com o banco de dados, convém que apenas uma classe crie a conexão com o banco de dados, de modo que, se você decidir mudar do Mysql para o Oracle, poderá alterar a lógica de uma classe e o restante do aplicativo irá use a nova conexão.

Se você deseja implementar o pool de banco de dados, isso também seria feito sem afetar o restante do aplicativo.

Ele protege o restante do aplicativo das alterações que você pode fazer na fábrica, que é a finalidade.

O motivo para ser estático é que, se você deseja acompanhar algum recurso limitado (número de conexões de soquete ou identificadores de arquivo), essa classe pode acompanhar quantos foram desmaiados e retornados, para não esgotar o recurso limitado.

James Black
fonte
2

Uma das vantagens dos métodos estáticos de fábrica com o construtor privado (a criação de objetos deve ter sido restrita a classes externas para garantir que as instâncias não sejam criadas externamente) é que você pode criar classes controladas por instância . E as classes controladas por instância garantem que não existem duas instâncias distintas iguais ( a.equals (b) se e somente se a == b ) durante a execução do programa, significa que você pode verificar a igualdade de objetos com o operador == em vez do método equals , de acordo com java eficaz.

A capacidade dos métodos estáticos de fábrica de retornar o mesmo objeto a partir de invocações repetidas permite que as classes mantenham controle rígido sobre quais instâncias existem a qualquer momento. Diz-se que as classes que fazem isso são controladas por instância. Há vários motivos para escrever classes controladas por instância. O controle de instância permite que uma classe garanta que é um singleton (Item 3) ou não instável (Item 4). Além disso, permite que uma classe imutável (Item 15) garanta que não existem duas instâncias iguais: a.equals (b) se e somente se a == b. Se uma classe faz essa garantia, seus clientes podem usar o operador == em vez do método equals (Object), o que pode resultar em melhor desempenho. Os tipos enum (Item 30) fornecem essa garantia.

De Java eficaz, Joshua Bloch (Item 1, página 6)

SherlockHomeless
fonte
1

estático

Um membro declarado com a palavra-chave 'estático'.

métodos de fábrica

Métodos que criam e retornam novos objetos.

em Java

A linguagem de programação é relevante para o significado de 'estático', mas não para a definição de 'fábrica'.

Marquês de Lorne
fonte
As respostas @Victor não precisam conter argumentos. Os fatos devem ser suficientes: se controversos, eles podem ser apoiados por argumento ou citação. Não sei que há algo controverso aqui.
Marquês de Lorne
Afirmei que, como a resposta era muito curta e realmente não entendia bem no primeiro, segundo e terceiro olhar, de qualquer maneira, cabe ao OP pedir novamente. Deixa pra lá, eu mudei de idéia e tento remover o voto negativo, mas não posso.
Victor
@ Victor Define 'muito curto'. Às vezes, a resposta real é apenas 'sim', 'não', 'nem' ou 'ambos'. "Curto demais" é inteiramente subjetivo. Ainda não entendi o seu comentário original. Você não precisa de argumentos para suportar definições. Por definição. Eu editei minha resposta para que agora seja possível remover o voto negativo.
Marquês de Lorne
É claro que é subjetivo ... todas as respostas de stackoverflow são subjetivas, na verdade elas estão relacionadas ao nível de conhecimento e vontade de resposta do autor. Eu realmente não entendo sua resposta, talvez tenha sido curta.
Victor Victor
@Victor Rubbish. As questões de fato não são subjetivas, nem as que podem ser derivadas inferencialmente de fatos ou axiomas. Por outro lado, 'curto demais' é subjetivo, e eu já falei sobre isso. Essa resposta é essencialmente o mesmo que este , que você não comentaram. Seus comentários permanecem obscuros.
Marquês de Lorne
1

A implementação Java contém as classes de utilitários java.util.Arrays e java.util.Collections, ambas contêm métodos estáticos de fábrica , exemplos e como usar:

A classe java.lang.String também possui métodos estáticos de fábrica :

  • String.format(...), String.valueOf(..), String.copyValueOf(...)
Владимир Дворник
fonte