2009-11-06 8 views
45

Parece que no puedo encontrar una respuesta al respecto y solo quiero asegurarme de que sea un estándar de codificación correcto. Tengo la interfaz A que utilizan muchas clases diferentes y no quiero que la interfaz A cambie. Me encontré con un nuevo requisito que requerirá una enumeración necesaria para muchas de las clases que implementan la interfaz A, pero no todas las clases necesitan esta enumeración. No quiero que las clases que no requieren esta nueva enumeración implementen esta nueva funcionalidad. Así que creé la Interfaz B que contiene la nueva enumeración que necesitaba agregar. Luego hice Interface B Heredar interfaz A y esta es mi preocupación, ¿está bien que una interfaz pueda heredar otra interfaz? Para continuar con mis cambios, cambié las clases que necesitaban la nueva enumeración para Implementar la Interfaz B en lugar de la Interfaz A, ya que la Heredaba la Interfaz B. Pensé en Implementar ambas Interfaces en mis clases que las necesitaban, pero estoy usando Interfaz a lo largo del código y me gustaría usar solo una interfaz para mirar las clases y no dos.En caso de que una interfaz herede otra interfaz

Espero que esto haya sido lo suficientemente claro (probablemente por mucho tiempo) pero si alguien me puede dar algún consejo sobre esto o lo estoy haciendo bien o lo estoy haciendo mal, por favor avíseme.

Gracias!

Respuesta

60

La herencia de interfaz es una herramienta excelente, aunque solo debe usarla cuando la interfaz B es realmente sustituible para la interfaz A, no solo para agregar comportamientos poco relacionados.

Es difícil decir si es apropiado para su caso específico, pero no hay nada de malo en la práctica en principio. Lo ves en las API de primer nivel todo el tiempo. Para recoger sólo un ejemplo común, a partir del marco .NET:

public interface ICollection<T> : IEnumerable<T>, IEnumerable 
+2

Originalmente sugerí que se aplicara el principio de sustitución de Liskov. En retrospectiva, eso no es realmente relevante. La mayoría de los requisitos del LSP (mantenimiento de invariantes, restricciones en condiciones previas y posteriores) solo son aplicables a implementaciones concretas, no a interfaces. Una vez dicho esto, el principio general de sustituibilidad debería seguir guiando las decisiones de herencia de interfaz. –

+0

Principio de sustitución Liskov: es importante asegurarse de que la interfaz B pueda reemplazar por completo la interfaz A. De lo contrario, terminará con la funcionalidad que debe implementar y que no desea. Esto conduce a un código adicional que no desea, lo que hace que el software sea menos estable. –

2

OMI esto es exactamente el enfoque correcto, no veo ningún problema con él.

6

Es ciertamente posible tener un árbol de herencia de interfaces, e incluso "herencia múltiple" con interfaces. Si es lo correcto o no, depende de las interfaces en cuestión. Si realmente es el caso de que la interfaz B es una extensión o refinamiento de la interfaz A, entonces la herencia tiene sentido, pero si la nueva enumeración no está relacionada en gran medida con el concepto expresado por la interfaz A, los convertiría en dos interfaces separadas y tendría las clases que necesitan implementar ambas interfaces.

+0

Buen punto y sí en esta situación están relacionados. – ajrawson

5

Técnicamente hablando, las interfaces no heredan entre sí. Lo que realmente ocurre cuando creas un IFoo que hereda de IBar, estás diciendo que cualquier clase que implemente IFoo también debe implementar IBar.

interface IBar 
{ 
    void DoBar(); 
} 

interface IFoo : IBar 
{ 
    void DoFoo(); 
} 

En este ejemplo, la interfaz de IFoo no tiene un método DoBar(). La mayoría de las veces la distinción no importa, pero puede morderte al utilizar la reflexión en una interfaz en lugar de una clase.

+3

Incluso teniendo en cuenta el comportamiento que ha descrito (descrito con gran detalle en la columna reciente de Phil Haack, http://haacked.com/archive/2009/11/10/interface-inheritance-esoterica.aspx), creo que es excesivamente confuso decir "las interfaces no se heredan entre sí" en C# cuando la documentación de referencia de C# incluso usa esa terminología, como en "Una interfaz puede heredar de una o más interfaces base". (http://msdn.microsoft.com/en-us/library/87d83y5b%28VS.80%29.aspx) Prefiero solo decir que, en C#, la herencia de la interfaz se comporta de manera diferente a la herencia de clase al reflejar los miembros heredados . –

+1

Bastante justo. Supongo que depende de cómo se define "heredar". Ciertamente, la sintaxis de C# es la misma ya sea en clases o interfaces. Pero si considera que la herencia incluye a los miembros del padre, entonces su modelo mental no concuerda con la realidad cuando habla de interfaces. –

1

creo que las bases de datos siempre ofrecen una gran manera de demostrar las interfaces, por lo que teniendo en cuenta si una interfaz debe heredar otro aspecto interfaz en el siguiente,

IMySqlDatabase : IDatabase 
MySqlDatabase : IMySqlDatabase 

IMsSqlDatabase : IDatabase 
MsSqlDatabase : IMsSqlDatabase 

Un MySqlDatabase es un IMySqlDatabase y un IMySqlDatabase es un iDatabase.

Ahora, si necesita realizar cambios en su interfaz IDatabase, sus nietos (las clases de base de datos remotas) pueden obtener los beneficios, pero no tendrá que expandir MySQL Y MsSQL (o incluso más interfaces DBMS).Al mismo tiempo, en su intermediario (IMsSqlDatabase) todavía puede tener funciones de interfaz que un MySQL u Oracle DB no admitiría.

13

Considere si las interfaces deben estar lógicamente emparejadas, y si cree que funcionan bien entre sí, entonces use absolutamente la herencia.

Veamos un ejemplo;

public interface IScanner 
{ 
    void Scan(); 
} 

public interface IPrinter 
{ 
    void Print(); 
} 

impresoras y escáneres son a menudo objetos separados, cada uno con su propia funcionalidad sin embargo, estos dos dispositivos a menudo se combina en el mismo dispositivo;

public interface IPhotocopier : IScanner, IPrinter 
{ 
    void Copy(); 
} 

tiene sentido que IPhotocopier debe heredar de iScanner y IPrinter ya que esto permite ahora la fotocopiadora para ser utilizado ya sea como un escáner o una impresora (que contiene), además de su rol primario como una copiadora.

Ahora veamos una interfaz más;

public interface IBlender 
{ 
    void Blend(); 
} 

No tendría sentido permitir IBlender a ser heredado por cualquiera de las interfaces anteriores (¿qué les llame? IBlendingScanner?).

Si no puede dar a su nueva interfaz un nombre razonable, esto podría indicar que es posible que no desee utilizar la herencia en esta instancia.

Es una mala idea para heredar algunas interfaces como IDisposable, ya que esto obliga a todas las implementaciones de su nueva interfaz para implementar el patrón disponer incluso si no tienen ningún recurso desechables.

Cuestiones relacionadas