Pregunta ¿Por qué tener un método Create en lugar de usar "nuevo"?


¿Cuáles son las ventajas y cuándo es apropiado usar un constructor estático?

public class MyClass
{
    protected MyClass()
    {
    }

    public static MyClass Create()
    {
        return new MyClass();
    }
}

y luego creando una instancia de la clase a través de

MyClass myClass = MyClass.Create();

en lugar de simplemente tener un constructor público y crear objetos usando

MyClass myClass = new MyClass();

Puedo ver que el primer enfoque es útil si el método Create devuelve una instancia de una interfaz que la clase implementa ... forzaría a las personas que llaman a crear instancias de la interfaz en lugar del tipo específico.


11
2018-05-18 03:10


origen


Respuestas:


Este es el patrón de fábrica, y a menudo se puede usar para producir una subclase, pero permite que los parámetros del método estático determinen cuál.

También podría usarse si no se requiere siempre un nuevo objeto, por ejemplo, en una implementación de agrupamiento.

También se puede usar si todas las instancias del objeto deben almacenarse en caché o registrarse de otra manera al momento de la creación. Esto asegura que el cliente no se olvide de hacer eso.

Y, por supuesto, es parte integrante del patrón de Singleton.


15
2018-05-18 03:31



Esto no es un singleton ... Create devolvería la misma instancia cada vez si fuera así.

Este es un patrón de fábrica. Normalmente haría esto con interfaces, no con clases, así que tengo que extenderlo aquí, pero un ejemplo artificial sería:

public static MyClass Create()
{
    if(OS == Windows)
        return new MyDerivedClassForWindows();
    else if(OS == Linux)
        return new MyDerivedClassForLinux();
    etc....
}

8
2018-05-18 03:33



El ejemplo particular que has publicado realmente no tendría ninguna ventaja sobre el uso de un constructor normal. Hay dos común patrones, sin embargo, que utilizan un método como este para producir un objeto:

Patrón Singleton

El patrón singleton se puede usar cuando desea evitar que se creen varias instancias de un objeto, pero aún desea aprovechar los aspectos orientados a objetos de una clase (por ejemplo, campos, propiedades, métodos sin parámetros). Ejemplo:

public class MySingletonClass
{
    private MySingletonClass currentInstance = null;

    public MySingletonClass CreateInstance()
    {
         if (currentInstance == null)
         {
              currentInstance = new MySingletonClass();
         }
         else
         {
              return currentInstance;
         }
    }
}

Patrón de fábrica

El patrón de fábrica es una gran oportunidad para abstraer la creación de clases concretas; por ejemplo, supongamos por un momento que tiene algún XML, y dependiendo de qué nodo (NodeA, NodeB o NodeC) vea en el XML, tiene una clase diferente que lo procesará. Ejemplo:

public class MyXmlProcessorFactory
{
    public static IMyXmlProcessor GetMyXmlProcessor(XmlDocument document)
    {
         XmlNode rootNode = document.DocumentElement;

         if (rootNode.SelectSingleNode("NodeA") != null)
         {
              return new NodeAMyXmlProcessor();
         }
         else if (rootNode.SelectSingleNode("NodeB") != null)
         {
              return new NodeBMyXmlProcessor();
         }
         else if (rootNode.SelectSingleNode("NodeC") != null)
         {
              return new NodeCMyXmlProcessor();
         }
         else
         {
              return new DefaultMyXmlProcessor();
         }
    }
}

4
2018-05-18 03:55



Otra razón, demostrada por el método estático Guid.NewGuid (), es si el tipo es una estructura. En este caso, el CLR requiere que el constructor sin parámetros predeterminado cree una nueva instancia con todos los campos inicializados a los valores predeterminados. En el caso de Guid, esto significa:

Guid g = new Guid ();

sería Guid.Empty. Obviamente, desea la posibilidad de crear un nuevo Guid que esté aleatorizado, por lo que el método Guid.NewGuid () es una forma de hacerlo.


3
2018-05-18 03:46



Estás en lo correcto. Este no es un patrón de Singleton. Es un patrón de fábrica.

El uso de Create () en lugar de new da te permite dar nombres significativos a los métodos, dando al usuario más claridad

Tome esto por ejemplo:

public class User
{
    public int id;
    public string userName;
    public string password;
    public string role;

    private User() { }

    public static User CreateByCredentials(string uid, string pwd)
    {
        User user = new User();
        user.userName = uid;
        user.password = pwd;
        return user;
    }

    public static User CreateById(int id)
    {
        User user = new User();
        user.id = id;
        return user;
    }

}

Hay dos ventajas para este enfoque:

  1. Podemos devolver un objeto nulo, lo cual es imposible de hacer con un constructor (Esto puede o no ser útil en todos los casos).
  2. Si hay muchas maneras diferentes de crear un objeto, le da la oportunidad de proporcionar nombres de funciones más significativos. En el ejemplo, tiene User.CreateByCredentials (string username, string password) & User.CreateById (int id). Puede lograr la misma funcionalidad con sobrecarga de constructor, pero rara vez con la misma claridad.

3
2018-05-18 04:30



Puede ser útil en casos donde las instancias de clases múltiples comparten el mismo bloque de datos inicializados; este es el patrón de fábrica de OOP.

Un ejemplo sería una clase que se conecta a una base de datos: solo se necesita una conexión y todas las instancias de la clase pueden compartirla.

http://en.wikipedia.org/wiki/Factory_pattern

Billy3


2
2018-05-18 03:17



Más formalmente, generalmente se lo conoce como Reemplace el constructor con el método de fábrica 

Desea hacer más que construcción simple cuando crea un objeto.

es decir, al usar un método de fábrica, puede ser más explícito y tener más opciones de creación disponibles para el código sobre un simple constructor.

Yo recomendaría el libro Refactorización:  Mejorando el Diseño del Código Existente (Fowler) 


2
2018-05-18 04:36



Hay varias razones por las que puede hacer esto, por ejemplo, siempre devolver una instancia desde un grupo de objetos fijo (incluido un objeto Singleton) o, como usted dice, devolver instancias de una interfaz.

Pero si no tienes una razón clara para hacerlo, no lo hagas.


1
2018-05-18 03:17



Esta es una buena manera de forzar a MyClass a ser definitiva, si usas constructor privado. De esta forma no se pueden crear subclases, porque su constructor no puede acceder al constructor de super.

Otra ventaja es cuando tienes un parámetro para el constructor. Luego puede nombrar la creación con la emulación de argumentos con nombre:

public static MyClass createWithDays(int days) {
...
}

Ahora compara new MyClass(5) a MyClass.createWithDays(5)


1
2018-05-18 03:32



Además de cuando es un singleton, tener un "método de fábrica estático" como MyClass.Create puede ser útil si la persona que implementa MyClass.Create podría querer devolver una subclase de MyClass ... por ejemplo, durante las pruebas podría devolver una instancia del MyClassWithExtraTestingFunctionality subclase ... o, dependiendo de una opción de configuración, una instancia del MyClassBeingRemotedOverTheNetwork subclase ...


1
2018-05-18 03:35



Muchas de las otras respuestas han cubierto ocasiones específicas donde esta idea puede ser útil. La idea de encapsular la creación de instancias se usa en muchos frameworks IoC como Spring, Castle, etc. La idea es que al centralizar la creación de instancias, puede personalizar la configuración de su aplicación para usar diferentes conjuntos de objetos. Un ejemplo común es el registro. Al cambiar la configuración, puede decirle a su fábrica de registradores que produzca diferentes instancias de sus clases de registro según la situación.

Si se aplica, esta idea puede conducir a sistemas muy poco acoplados, que pueden cambiarse fácilmente después de la implementación o incluso en tiempo de ejecución. Sin embargo, la complejidad aumenta a medida que tiene otro nivel de indirección.


1
2018-05-18 03:45



Preguntas populares