¿Qué son los métodos estáticos de fábrica?

261

¿Qué es un método de "fábrica estática"?

freddiefujiwara
fuente
Un método alternativo de fábrica estática está utilizando la inyección de dependencia.
CMCDragonkai
1
La respuesta de @ThangPham Jason Owen es errónea porque pretende estar hablando del patrón del Método de Fábrica, que es muy diferente del patrón del método de fábrica estático del que realmente habla. Entonces, aunque hace un buen trabajo al responder la pregunta real, no creo que pueda aceptarse en su estado actual, porque trae un patrón no relacionado y aumenta la confusión ya increíblemente común sobre la diferencia entre los dos patrones.
Theodore Murdock
@ CMCDragonkai Creo que la inyección de dependencia y la fábrica estática son diferentes. La fábrica estática puede ser necesaria incluso en caso de inyección de dependencias para instanciar las dependencias que se van a inyectar.
Karan Khanna

Respuestas:

126

Evitamos proporcionar acceso directo a las conexiones de la base de datos porque requieren muchos recursos. Entonces usamos un método de fábrica estático getDbConnectionque crea una conexión si estamos por debajo del límite. De lo contrario, intenta proporcionar una conexión "libre", fallando con una excepción si no hay ninguna.

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
fuente
si entiendo correcto, ¿puede agregar availableConnections.add (db) al método returnDbConnection (DbConnection db)?
Haifeng Zhang
@haifzhan, en realidad no está destinado a ser completo, pero está bien.
Matthew Flaschen
@MatthewFlaschen también, ¿deberían disminuirse las conexiones totales mientras se devuelve la conexión?
Rolling Stone
@Sridhar, no, es la cantidad de conexiones que existen (rastreadas para que no se creen más de MAX_CONNS), no la cantidad que circula.
Matthew Flaschen
@MatthewFlaschen su método será capturado por sonarcube como error de bloqueo si DbConnection es cerrable.
Awan Biru
477

El patrón de método de fábrica estático es una forma de encapsular la creación de objetos. Sin un método de fábrica, sólo tendría que llamar a la clase de constructor directamente: Foo x = new Foo(). Con este patrón, debe en su lugar llamar al método de fábrica: Foo x = Foo.create(). Los constructores están marcados como privados, por lo que no se pueden llamar excepto desde dentro de la clase, y el método de fábrica se marca de staticmodo que se pueda llamar sin tener primero un objeto.

Hay algunas ventajas en este patrón. Una es que la fábrica puede elegir entre muchas subclases (o implementadores de una interfaz) y devolver eso. De esta manera, la persona que llama puede especificar el comportamiento deseado a través de parámetros, sin tener que conocer o comprender una jerarquía de clases potencialmente compleja.

Otra ventaja es, como han señalado Matthew y James, controlar el acceso a un recurso limitado como las conexiones. Esta es una forma de implementar grupos de objetos reutilizables : en lugar de construir, usar y derribar un objeto, si la construcción y la destrucción son procesos costosos, podría tener más sentido construirlos una vez y reciclarlos. El método de fábrica puede devolver un objeto instanciado existente sin usar si tiene uno, o construir uno si el recuento de objetos está por debajo de un umbral inferior, o lanzar una excepción o devolver nullsi está por encima del umbral superior.

Según el artículo en Wikipedia, los múltiples métodos de fábrica también permiten diferentes interpretaciones de tipos de argumentos similares. Normalmente, el constructor tiene el mismo nombre que la clase, lo que significa que solo puede tener un constructor con una firma determinada . Las fábricas no están tan restringidas, lo que significa que puede tener dos métodos diferentes que aceptan los mismos tipos de argumentos:

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

y

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

Esto también se puede utilizar para mejorar la legibilidad, como señala Rasmus.

Jason Owen
fuente
32
Tenga en cuenta que un método de fábrica estático no es lo mismo que el patrón de Método de fábrica de Patrones de diseño [Gamma95, p. 107]. El método de fábrica estático descrito en este artículo no tiene un equivalente directo en los Patrones de diseño.
Josh Sunshine
La recompensa para mí en esta respuesta es la referencia a objetos agrupables. Así es EXACTAMENTE cómo estoy usando el patrón de método de fábrica. Se proporcionan métodos de fábrica para ayudar a controlar el ciclo de vida de un objeto: "crear" extrae un objeto del grupo o crea una nueva instancia si el grupo está vacío, "destruir" lo devuelve al grupo para su futura reutilización.
MutantXenu
2
Realmente deberías estar usando "patrón de método de fábrica estático" siempre que digas "patrón de método de fábrica" ​​en esta publicación, estás usando el término incorrecto. Además, está vinculando el artículo de Wikipedia con un patrón diferente al patrón del que está hablando. El patrón del Método de Fábrica probablemente debería haberse llamado el patrón de "Interfaz de Fábrica", porque involucra el uso de varios objetos de fábrica que implementan una interfaz de fábrica para permitir que un solo algoritmo produzca y funcione con instancias de una interfaz, al aceptar un objeto de fábrica que puede producir la subclase deseada específica.
Theodore Murdock
8
Estoy de acuerdo con @TheodoreMurdock. Estás usando el término equivocado. De lo que estás hablando es del "Método de fábrica estática" de Joshua Bloch, pero usas el término "Patrón de método de fábrica" ​​de GoF. Edítelo para que otras personas no lo malinterpreten.
emeraldhieu
1
Tenga en cuenta que el constructor no tiene que ser privado. Una clase podría proporcionar tanto métodos de fábrica estáticos públicos como constructores.
Kevin
171

¡NOTA! "El método de fábrica estático NO es el mismo que el patrón de Método de fábrica " (c) Java efectivo, Joshua Bloch.

Método Factory: "Defina una interfaz para crear un objeto, pero deje que las clases que implementan la interfaz decidan qué clase instanciará. El método Factory permite que una clase difiera la instanciación a las subclases" (c) GoF.

"El método de fábrica estático es simplemente un método estático que devuelve una instancia de una clase". (c) Efectivo Java, Joshua Bloch. Por lo general, este método está dentro de una clase particular.

La diferencia:

La idea clave del método de fábrica estática es obtener control sobre la creación de objetos y delegarlo del constructor al método estático. La decisión del objeto a crear es como en Abstract Factory hecha fuera del método (en el caso común, pero no siempre). Si bien la idea clave (!) Del Método Factory es delegar la decisión de qué instancia de clase crear dentro del Método Factory. Por ejemplo, la implementación clásica de Singleton es un caso especial del método estático de fábrica. Ejemplo de métodos de fábrica estáticos comúnmente utilizados:

  • valor de
  • obtener Instancia
  • nueva instancia
Grygoriy Gonchar
fuente
¿Me puede decir la diferencia entre el nuevo A () y A.newInstance ()? y dentro de A.newInstance, ¿qué debemos hacer?
Shen
69

La legibilidad se puede mejorar mediante 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.

a

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

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

// ...

// This is much easier to read!
Foo foo = Foo.createWithBar();
Rasmus Faber
fuente
Así que intenté implementar tu ejemplo, pero no estoy seguro de cómo funciona. ¿Se supone que los dos métodos createWithBar y createWithoutBar llaman a 2 constructores privados dentro de la clase Foo?
Essej
@Baxtex: sí. Cada uno llamará a un constructor privado. Quizás el mismo: private Foo(boolean withBar){/*..*/} public static Foo createWithBar(){return new Foo(true);} public static Foo createWithoutBar(){return new Foo(false);}
Rasmus Faber
Creo que esto no es "escala" muy bien. Si tiene tres o más parámetros, ¿cómo podría usar esta idea y crear un buen nombre para el método?
Dherik
@Dherik: Entonces probablemente deberías usar el patrón de construcción en su lugar: nuevo FooBuilder (). WithBar (). WithoutFoo (). WithBaz (). Build ();
Rasmus Faber
21
  • tener nombres, a diferencia de los constructores, que pueden aclarar el código.
  • no es necesario crear un nuevo objeto en cada invocación; los objetos se pueden almacenar en caché y reutilizar, si es necesario.
  • puede devolver un subtipo de su tipo de retorno; en particular, puede devolver un objeto cuya clase de implementación es desconocida para el llamante. Esta es una característica muy valiosa y ampliamente utilizada en muchos marcos que utilizan interfaces como el tipo de retorno de los métodos estáticos de fábrica.

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

soldado.moth
fuente
18

Todo se reduce a la mantenibilidad. La mejor manera de decir esto es que cuando usa la newpalabra clave para crear un objeto, está acoplando el código que está escribiendo en una implementación.

El patrón de fábrica le permite separar cómo crea un objeto de lo que hace con el objeto. Cuando crea todos sus objetos usando constructores, esencialmente está cableando el código que usa el objeto para esa implementación. El código que usa su objeto es "dependiente de" ese objeto. Puede que esto no parezca un gran problema en la superficie, pero cuando el objeto cambia (piense en cambiar la firma del constructor o subclasificar el objeto) debe retroceder y volver a cablear las cosas en todas partes.

Hoy en día, las fábricas han sido descartadas en gran medida a favor del uso de la inyección de dependencia porque requieren una gran cantidad de código de placa de caldera que resulta un poco difícil de mantener. La inyección de dependencia es básicamente equivalente a las fábricas, pero le permite especificar cómo sus objetos se conectan entre sí de forma declarativa (a través de la configuración o anotaciones).

cwash
fuente
3
¿Estás diciendo que las fábricas necesitan un rescate? ;)
John Farrell
44
¡Jaja! En estos tiempos, creo que todos podríamos usar un rescate ... :)
cwash
11

Si el constructor de una clase es privado, no puede crear un objeto para la clase desde fuera de ella.

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

No podemos crear un objeto para la clase anterior desde fuera de ella. Por lo tanto, no puede acceder a x, y desde fuera de la clase. Entonces, ¿de qué sirve esta clase?
Aquí está la respuesta: método de FÁBRICA .
Agregue el siguiente método en la clase anterior

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

Entonces ahora puede crear un objeto para esta clase desde fuera de ella. De esa manera...

Test t = Test.getObject();

Por lo tanto, un método estático que devuelve el objeto de la clase ejecutando su constructor privado se llama método FACTORY
.

Santhosh
fuente
1
¿Por qué lo llamas una "solución"? Declarar un constructor privado no es un "problema", es un patrón de diseño.
Ojonugwa Jude Ochalifu
1
Actualizado. Gracias de todos modos
Santhosh
Hola @Santhosh. Me preocupa. ¿Por qué no dejas que el constructor privado sea público? Si no desea crear una subclase, está bien para mí, pero si no tengo la intención de hacer un constructor privado, ¿tenemos algún beneficio Static Factory Methodsobre el constructor público?
Shen
9

Pensé que agregaría algo de luz a esta publicación sobre lo que sé. Utilizamos esta técnica ampliamente en nuestro recent android project. En lugar de creating objects using new operatorusted, también puede usar static methodpara crear una instancia de una clase. Listado 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();
  }
}

Los métodos estáticos admiten la creación de objetos condicionales : cada vez que invoque un constructor, se creará un objeto, pero es posible que no lo desee. suponga que desea verificar alguna condición solo entonces desea crear un nuevo objeto. No crearía una nueva instancia de Vinoth cada vez, a menos que su condición se cumpla.

Otro ejemplo tomado de Effective Java .

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

Este método traduce un valor primitivo booleano en una referencia de objeto booleano. El Boolean.valueOf(boolean)método nos ilustra, nunca crea un objeto. La capacidad de static factory methodsdevolver el mismo objeto de repetido invocationspermite a las clases mantener un control estricto sobre qué instancias existen en cualquier momento.

Static factory methodses que, a diferencia constructors, que puede devolver una objectde cualquier subtypede su tipo de retorno. Una aplicación de esta flexibilidad es que una API puede devolver objetos sin hacer públicas sus clases. Ocultar clases de implementación de esta manera conduce a una API muy compacta.

Calendar.getInstance () es un gran ejemplo para lo anterior, se crea según la configuración regional a BuddhistCalendar, JapaneseImperialCalendaro por defecto Georgian.

Otro ejemplo que podría pensar es Singleton pattern, cuando haces que tus constructores sean privados, crea un getInstancemétodo propio donde te aseguras de que siempre haya una sola instancia disponible.

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
fuente
4

Un método de fábrica un método que abstrae la creación de instancias de un objeto. En general, las fábricas son útiles cuando sabe que necesita una nueva instancia de una clase que implemente alguna interfaz pero no conoce la clase de implementación.

Esto es útil cuando se trabaja con jerarquías de clases relacionadas, un buen ejemplo de esto sería un kit de herramientas GUI. Simplemente podría codificar las llamadas a los constructores para implementaciones concretas de cada widget, pero si alguna vez quisiera cambiar un kit de herramientas por otro, tendría muchos lugares para cambiar. Al usar una fábrica, reduce la cantidad de código que necesitaría cambiar.

Bryan Kyle
fuente
Suponiendo que su fábrica devuelva un tipo de interfaz, y no la clase concreta con la que está tratando.
Bill Lynch
1
Esta respuesta es sobre el patrón de diseño del método de fábrica, no sobre los métodos de fábrica estáticos. Un método de fábrica estático es simplemente un método público estático que devuelve una instancia de una clase. Consulte el Capítulo 2 de Java efectivo para obtener más detalles.
Josh Sunshine
4

Una de las ventajas que se deriva de la fábrica estática es que esa API puede devolver objetos sin hacer públicas sus clases. Esto condujo a una API muy compacta. En java, esto se logra mediante la clase Collections, que oculta alrededor de 32 clases, lo que hace que la colección API sea muy compacta.

Rakesh Chauhan
fuente
2

Un método de fábrica estático es bueno cuando desea asegurarse de que solo una instancia única devolverá la clase concreta que se utilizará.

Por ejemplo, en una clase de conexión de base de datos, es posible que desee que solo una clase cree la conexión de la base de datos, de modo que si decide cambiar de Mysql a Oracle puede cambiar la lógica en una clase, y el resto de la aplicación lo hará usa la nueva conexión.

Si desea implementar la agrupación de bases de datos, eso también se haría sin afectar el resto de la aplicación.

Protege el resto de la aplicación de los cambios que puede realizar en la fábrica, que es el propósito.

La razón por la que es estática es si desea realizar un seguimiento de algunos recursos limitados (número de conexiones de socket o identificadores de archivos), entonces esta clase puede realizar un seguimiento de cuántos se han pasado y devuelto, por lo que no agota el recurso limitado

James Black
fuente
2

Una de las ventajas de los métodos de fábrica estáticos con constructor privado (la creación de objetos debe haber sido restringida para clases externas para garantizar que las instancias no se creen externamente) es que puede crear clases controladas por instancias . Y las clases controladas por instancia garantizan que no existan dos instancias distintas iguales ( a.equals (b) si y solo si a == b ) durante la ejecución de su programa, eso significa que puede verificar la igualdad de objetos con el operador == en lugar del método igual , según Effective java.

La capacidad de los métodos de fábrica estáticos para devolver el mismo objeto de invocaciones repetidas permite a las clases mantener un control estricto sobre qué instancias existen en cualquier momento. Se dice que las clases que hacen esto están controladas por instancia. Hay varias razones para escribir clases controladas por instancia. El control de instancia permite que una clase garantice que es un singleton (Elemento 3) o no instantable (Elemento 4). Además, permite que una clase inmutable (Elemento 15) garantice que no existen dos instancias iguales: a.equals (b) si y solo si a == b. Si una clase hace esta garantía, sus clientes pueden usar el operador == en lugar del método igual (Objeto), lo que puede mejorar el rendimiento. Los tipos de enumeración (Artículo 30) proporcionan esta garantía.

De Java efectivo, Joshua Bloch (artículo 1, página 6)

SherlockHomeless
fuente
1

estático

Un miembro declarado con la palabra clave 'static'.

métodos de fábrica

Métodos que crean y devuelven nuevos objetos.

en Java

El lenguaje de programación es relevante para el significado de 'estático' pero no para la definición de 'fábrica'.

Marqués de Lorne
fuente
Las respuestas de @Victor no necesitan contener argumentos. Los hechos deberían ser suficientes: si son controvertidos, pueden ser respaldados por argumentos o citas. No sé si hay algo controvertido aquí.
Marqués de Lorne
Dije que debido a que la respuesta era demasiado corta y realmente no se entendía bien en la primera, segunda y tercera mirada, de todos modos depende del OP para volver a preguntar. No importa, he cambiado de opinión e intento eliminar el voto negativo, pero no puedo.
Victor
@Victor Define 'demasiado corto'. A veces la respuesta real es simplemente 'sí', 'no', 'ninguno' o 'ambos'. 'Demasiado corto' es completamente subjetivo. Aún no entiendo tu comentario original. No necesita argumentos para admitir definiciones. Por definición. He editado mi respuesta para que ahora sea posible eliminar el voto negativo.
Marqués de Lorne
Por supuesto, es subjetivo ... todas las respuestas de stackoverflow son subjetivas, de hecho, están relacionadas con el nivel de conocimiento y la voluntad de responder del autor. Realmente no entiendo tu respuesta, tal vez fue breve.
Victor
@Victor Basura. Los asuntos de hecho no son subjetivos, y tampoco lo son los asuntos que pueden derivarse inferencialmente de hechos o axiomas. "Demasiado corto", por otro lado, es subjetivo, y ya lo he abordado. Esta respuesta es esencialmente la misma que esta , que no ha comentado. Tus comentarios permanecen oscuros.
Marqués de Lorne
1

La implementación de Java contiene las clases de utilidades java.util.Arrays y java.util.Collections, ambas contienen métodos estáticos de fábrica , ejemplos de esto y cómo usarlo:

También la clase java.lang.String tiene métodos de fábrica estáticos :

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