¿Por qué se crea una instancia de los objetos de esta manera?

7

Algunas veces veo un objeto instanciado de esta manera.

ICustomer oCustomer = new Customer

Obviamente, pero la clase Cliente está implementando la interfaz de ICustomer en este ejemplo. ¿Hay alguna ventaja de instanciar un objeto de esa manera? A mi entender, si una clase en la implementación de una interfaz ya está siguiendo el contrato. ¿Cuál es el nombre de esa práctica y hay una desventaja de crear una instancia de un objeto de manera "normal" (lo que normalmente hago)? Sé que ya existen algunas preguntas, pero en realidad no resaltan las ventajas y desventajas

Creación de instancias de interfaz frente a la creación de instancias de clase

Customer oCustomer = new Customer
    
pregunta Howls Hagrid 02.04.2015 - 02:09

5 respuestas

18

Hay una, muy importante distinción que creo que estás pasando por alto.

El código que proporcionó es para tres cosas: la declaración de una variable, la creación de instancias de un objeto y la inicialización de esa variable con ese objeto.

No hay implementación de interfaz aquí . Customer necesita implementar ICustomer (o hacer uno o dos trucos más) para que compile exitosamente , pero no hay una implementación real en este lugar.

Ahora que la terminología está fuera del camino, concentrémonos en el problema: ¿es mejor?

Este tipo de cosas cae en el ámbito del programa para una interfaz . Cuando declara su variable, necesita darle un tipo. Ese tipo debería definir el tipo de cosas que la variable puede hacer. Es un contrato que usted hace con futuros programadores (o usted mismo) que oCustomer solo puede hacer este tipo de cosas. Debe decidir este contrato independientemente de la fuente que utiliza para inicializar la variable.

Si esta variable solo necesita la interfaz, usar la interfaz como su tipo define claramente lo que puede (y no puede) hacer. Si esta variable realmente necesita ser un Customer completo, entonces vuelva a verificar que realmente lo necesita. Si lo haces, sigue adelante y haz que sea un Customer . Esto proporciona una comunicación clara con los futuros programadores (o usted) de que la variable debe ser de ese tipo. Y si la variable es solo un marcador de posición para su inicializador; Si su tipo realmente no importa, entonces use var .

Los beneficios de la programación a una interfaz se describen en profundidad en el enlace anterior, pero se reducen a permitirle ser flexible. El software inevitablemente cambia. Al codificar en una interfaz, permite que este código permanezca felizmente inconsciente cuando Customer cambia, o si necesita mañana para inicializar oCustomer con un VipCustomer en su lugar.

Este tipo de cosas se aplica en muchos lugares a lo largo de la programación, no solo en declaraciones de variables.

    
respondido por el Telastyn 02.04.2015 - 02:43
10

Mientras su código se vea tan simple como este

void ExampleFunc()
{
   ICustomer oCustomer = new Customer();
   oCustomer.Method1OfICustomer();
   oCustomer.Method2OfICustomer();
   // ...
}

hay no diferencia semántica: puede intercambiar "Cliente IC" por "Cliente", y el comportamiento será idéntico. En este ejemplo, sin embargo, podría cumplir ya algunos propósitos documentales. La primera línea puede expresar la decisión de diseño del programador para evitar agregar llamadas como

   oCustomer.MethodNotPartOfICustomer();

en el futuro, pero de hecho, cuando se necesite este tipo de llamada más adelante, también se podría cambiar la línea "nueva" o agregar el método faltante al ICustomer más tarde.

De hecho, el uso de interfaces, como lo indica el término, comenzará a tener más sentido cuando exista alguna "interfaz" real involucrada: la interacción entre funciones, clases y componentes. Por ejemplo, la función

void ExampleFunc(ICustomer oCustomer)
{
   oCustomer.Method1OfICustomer();
   oCustomer.Method2OfICustomer();
   // ...
}

es probablemente más genérico que

void ExampleFunc(Customer oCustomer)
{
   oCustomer.Method1OfICustomer();
   oCustomer.Method2OfICustomer();
   // ...
}

ya que funcionará con cualquier clase que implemente la interfaz ICustomer , no solo Customer . Por ejemplo, para propósitos de prueba, se podría pensar en pasar un "CustomerMock" a la función, algo que no se puede hacer con la segunda variante.

    
respondido por el Doc Brown 02.04.2015 - 08:38
2

La forma en que lo creas no es mejor ni peor de ninguna manera.

Pensemos en ello:

Puedes establecer objetos u obtener objetos (es decir, pasarlos a un constructor, método o devolverlos desde un método).

En cualquiera de los dos casos, siempre y cuando proporcione una interfaz para configurar y obtener puede renovar su objeto de la forma que desee, ya que de cualquier manera podrá aprovechar el polimorfismo, la abstracción y la encapsulación. - y ese es el punto central del principio program to interface not to implementation , que es de lo que trata tu pregunta central.

    
respondido por el AvetisG 02.04.2015 - 02:46
1

En C # no hay mucha diferencia.

La diferencia radica en lo que puede llamar en la referencia que creó.

Este código

ICustomer customer = new Customer();

crea una referencia de interfaz llamada customer a la instancia creada por la llamada new Customer(); .

Este código

Customer customer = new Customer();

crea una referencia de objeto nombre customer a la instancia creada por la llamada new Customer(); .

Si bien ambas referencias apuntan a una instancia de la clase Customer , son diferentes. La referencia de la interfaz solo ofrece lo que está definido en la interfaz ICustomer , independientemente de qué otra cosa haga disponible la clase Customer . Al usar la referencia de objetos, puede usar todo lo que la clase Customer tiene para ofrecer.

Usando una referencia de interfaz, tendrías que volver a la clase implementadora para usar las cosas "adicionales" que ofrece la clase. Algo que realmente haces no quieres hacer. Después de todo, cuando se le pasa una referencia de interfaz, no puede estar seguro de qué clase se utilizó para crear una instancia del objeto al que hace referencia. Realmente solo hay una excepción a esta regla: cuando acaba de crear la referencia de la interfaz y necesita usar métodos que no desea colocar en la interfaz porque solo son necesarios durante la construcción / construcción / inicialización de la instancia. E incluso este debería ser un caso raro.

Para C # eso es todo.

Para los idiomas en los que el desarrollador es responsable de la administración explícita de por vida de los objetos que se crean instancias (es decir, tener que liberar cada objeto explícitamente), puede haber una gran diferencia entre las dos formas de referenciar el objeto instanciado.

En Delphi, por ejemplo, los objetos interconectados (instancias de una clase que implementa una interfaz) se cuentan de forma predeterminada y se liberan "automáticamente" cuando su recuento de referencias se reduce a cero. El recuento de referencia se incrementa y disminuye en _AddRef y _Release llamadas que el compilador agrega automáticamente a su código.

En Delphi, realmente nunca querrás crear una referencia de objeto a una instancia de una clase interconectada. Si lo hace, significa que el compilador no insertará la llamada _AddRef que incrementa el recuento de referencia a 1 en la instanciación. Lo que significa que el recuento de referencia es uno demasiado bajo. Lo que significa que la instancia se liberará demasiado pronto.

Es por eso que el consejo para idiomas como Delphi es nunca mezclar referencias de interfaz y objeto y usar siempre referencias de interfaz para clases conectadas .

    
respondido por el Marjan Venema 03.04.2015 - 16:08
-6

Esta pregunta va al corazón de lo que significa Orientación a objetos . En pocas palabras, en un lenguaje como Java, C # o Visual Basic.NET, class es (y struct s) define Tipos de datos abstractos y interface s define Objetos . Tan pronto como tenga un class o struct como un tipo (es decir, el tipo de una variable, campo, propiedad o parámetro de método local, un tipo de retorno de método, un argumento de tipo para una clase o interfaz genérica, el destino) de un operador de conversión o el argumento de un operador instanceof ), no está haciendo programación orientada a objetos.

Lo único que puede usar para un tipo, es un interface , no puede usar class es o struct s (y ciertamente no primitivos en un lenguaje como Java que los tiene). El único lugar donde se permite un class o struct , está justo al lado del operador new : class es y struct s son simplemente fábricas de objetos.

Esto se explica mucho mejor de lo que podría esperar lograr en En Entender la abstracción de datos , Revisited por William R. Cook . Utiliza Java para los ejemplos, pero se aplica igual de bien a C # o cualquier otro idioma.

Entonces, la respuesta simple es: si no estuvieras creando una instancia de un objeto de esta manera, no sería ser un objeto, sino una instancia de un tipo de datos abstracto.

    
respondido por el Jörg W Mittag 02.04.2015 - 08:54

Lea otras preguntas en las etiquetas