Método de creación estática: ventajas y desventajas en comparación con los constructores

11

¿Cuáles son las ventajas y desventajas de tener métodos de creación de objetos estáticos sobre constructores?

class Foo {
  private Foo(object arg) { }

  public static Foo Create(object arg) {
    if (!ValidateParam(arg)) { return null; }
    return new Foo(arg);
  }
}

Pocos en los que puedo pensar:

Pros:

  • Devuelve nulo en lugar de lanzar una excepción (nómbrelo TryCreate). Esto puede hacer que el código sea más conciso y limpio en el lado del cliente. Los clientes rara vez esperan que un constructor falle.
  • Cree diferentes tipos de objetos con una semántica clara, por ejemplo, CreatFromName(String name)yCreateFromCsvLine(String csvLine)
  • Puede devolver un objeto en caché si es necesario, o una implementación derivada.

Contras:

  • Código menos reconocible, más difícil de leer.
  • Algunos patrones, como la serialización o la reflexión, son más difíciles (p Activator<Foo>.CreateInstance(). Ej. )
dbkk
fuente
1
Es mas lento. Tienes que manejar la referencia nula de todos modos.
Amir Rezaei el
1
@Amir Handling null es ( Foo x = Foo.TryCreate(); if (x == null) { ... }). El manejo de una excepción de ctor es ( Foo x; try { x = new Foo(); } catch (SomeException e) { ... }). Cuando llamo a un método normal, prefiero excepciones a los códigos de error, pero con la creación de objetos, TryCreateparece más limpio.
dbkk
¿En su validación haría alguna verificación de tipo?
Amir Rezaei el
Con respecto al segundo Pro, "Crear diferentes tipos de objetos con una semántica clara, por ejemplo, CreatFromName (String name) y CreateFromCsvLine (String csvLine)", podría ser mejor crear Namey escribir CsvLine, en lugar de expresar requisitos a través de nombres de métodos. Esto le permitiría sobrecargar Crear. El uso de cadenas para ambos podría considerarse una "obsesión primitiva" (suponiendo que no haya hecho esta elección por razones de rendimiento conocidas). Echa un vistazo a Object Calisthenics para una forma divertida de explorar esto.
bentayloruk

Respuestas:

7

El mayor inconveniente con los ' creadores ' estáticos probablemente esté limitando la herencia. Si usted o el usuario de su biblioteca derivan una clase de su Foo, entonces se Foo::Create()vuelve prácticamente inútil. Toda la lógica definida allí deberá reescribirse nuevamente en el heredado Create().

Sugeriría un compromiso: defina un constructor con una lógica de inicialización de objeto trivial que nunca falla / arroja, luego defina creador (es) con almacenamiento en caché, construcción alternativa, etc. Eso deja la posibilidad de derivar y se beneficia de tener creadores para una clase dada .

mojuba
fuente
1
En la práctica, no es realmente un problema, porque la mayoría de las clases no están diseñadas para ser heredadas (y, por lo tanto, deberían estar selladas / finales). Si luego resulta que desea abrir la clase a herencia, siempre puede mover cualquier lógica de inicialización a un constructor protegido.
Doval
7

Crear es un método de fábrica. Cuando siento la necesidad de esto, implemento el patrón Factory y defino una interfaz para representar el contrato para crear el objeto, así como una clase de implementación, que luego se inyecta donde es necesario. Esto conserva las ventajas de mover la responsabilidad de creación fuera de la clase, pero evita (o al menos hace más obvio) las limitaciones de realizar la creación de objetos fuera del constructor de la clase.

quentin-starin
fuente