Por ejemplo:
Decir que tengo clases A, B, C. Tengo dos interfaces, llamémoslas IAnimaly IDog. IDoghereda de IAnimal. Ay Bson IDogs, mientras Cque no lo es, pero es un IAnimal.
La parte importante es que IDogno proporciona funcionalidad adicional. Solo se usa para permitir Ay B, pero no C, para pasar como argumento a ciertos métodos.
¿Es esta una mala práctica?
object-oriented
interfaces
Kendall Frey
fuente
fuente

IAnimalyIDogson terribles nombres de tautología!MyProject.Data.IAnimalyMyProject.Data.Animalson mejores queMyProject.Data.Interfaces.AnimalyMyProject.Data.Implementations.AnimalInterfaceoImplementation, ya sea en un prefijo repetitivo o en un espacio de nombres, es una tautología de cualquier manera y viola DRY.Doges todo lo que debería preocuparte.PitBull extends Dogtampoco necesita redundancia de implementación, la palabraextendsme dice todo lo que necesito saber, lea el enlace que publiqué en mi comentario original.Respuestas:
Interfaz que no tiene ningún miembro o tiene exactamente los mismos miembros con otra interfaz que se hereda de la misma interfaz llamada Interfaz de marcador y la está utilizando como marcador.
No es una mala práctica, pero la interfaz puede reemplazarse por atributos (anotaciones) si el idioma que está utilizando lo admite.
Puedo decir con confianza que no es una mala práctica porque he visto un patrón de "interfaz de marcador" de uso intensivo en Orchard Project
Aquí hay una muestra del proyecto Orchard.
Consulte la interfaz de marcador .
fuente
Ca un método que espera unIDog.Kennelclase que almacena una lista deIDogs.Sí, es una mala práctica en casi todos los idiomas.
Los tipos no están allí para codificar datos; son una ayuda para demostrar que sus datos van a donde deben ir y se comportan como deben comportarse. La única razón para subtipar es si cambia un comportamiento polimórfico (y no siempre entonces).
Como no hay que escribir, lo que un IDog puede hacer está implícito. Un programador piensa una cosa, otro piensa otra y las cosas se rompen. O las cosas que representa aumentan a medida que necesita un control más detallado.
[editar: aclaración]
Lo que quiero decir es que estás haciendo algo de lógica basada en la interfaz. ¿Por qué algunos métodos solo funcionan con perros y otros con cualquier animal? Esa diferencia es un contrato implícito ya que no hay un miembro real que proporcione la diferencia; No hay datos reales en el sistema. La única diferencia es la interfaz (de ahí el comentario de 'no escribir'), y lo que eso significa será diferente entre los programadores. [/editar]
Ciertos idiomas proporcionan mecanismos de rasgos donde esto no es tan malo, pero tienden a centrarse en las capacidades, no en el refinamiento. Tengo poca experiencia con ellos, así que no puedo hablar de las mejores prácticas allí. En C ++ / Java / C #, aunque ... no es bueno.
fuente
Kennelclase que almacena una lista deIDogs.Solo conozco bien C #, por lo que no puedo decir esto para la programación OO en general, pero como ejemplo de C #, si necesita clasificar las clases, las opciones obvias son interfaces, propiedades de enumeración o atributos personalizados. Por lo general, elegiría la interfaz sin importar lo que piensen los demás.
fuente
No hay nada de malo en tener una interfaz que herede otra interfaz sin agregar nuevos miembros, si se espera que todas las implementaciones de la última interfaz puedan hacer cosas útiles que algunas implementaciones de la primera no pueden hacer. De hecho, es un buen patrón que, en mi humilde opinión, debería haberse usado más en cosas como .NET Framework, especialmente porque un implementador cuya clase satisfaría naturalmente las restricciones implícitas en la interfaz más derivada puede indicar que simplemente implementando la interfaz más derivada , sin tener que cambiar ninguno de los códigos o declaraciones de implementación de miembros.
Por ejemplo, supongamos que tengo las interfaces:
interfaz IMaybeMutableFoo { Bar Thing {get; set;} // Y también otras propiedades bool IsMutable; IImmutableFoo AsImmutable (); } interfaz IImmutableFoo: IMaybeMutableFoo {};Se
IImmutableFoo.AsImmutable()esperaría que se implementara una implementación de ;IMaybeMutableFoo.AsImmutable()se espera que una implementación de clase mutable devuelva un nuevo objeto profundamente inmutable que contiene una instantánea de los datos. Una rutina que quiere almacenar una instantánea de los datos contenidos en unIMaybeMutableFoopodría ofrecer sobrecargas:público vacío StoreData (IImmutableFoo ThingToStore) { // Almacenar la referencia será suficiente, ya que se sabe que ThingToStore es inmutable } público vacío StoreData (IMaybeMutableFoo ThingToStore) { StoreData (ThingToStore.AsImmutable ()); // Llamar a la sobrecarga más específica }En los casos en que el compilador no sabe que lo que se va a almacenar es un
IImmutableFoo, llamaráAsImmutable(). La función debería volver rápidamente si el elemento ya es inmutable, pero una llamada a la función a través de una interfaz todavía lleva tiempo. Si el compilador sabe que el elemento ya es unIImmutableFoo, puede omitir la llamada de función innecesaria.fuente