¿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. )
design-patterns
dbkk
fuente
fuente
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,TryCreate
parece más limpio.Name
y escribirCsvLine
, 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.Respuestas:
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 seFoo::Create()
vuelve prácticamente inútil. Toda la lógica definida allí deberá reescribirse nuevamente en el heredadoCreate()
.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 .
fuente
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.
fuente