Tengo una clase: A
es un compuesto de varias clases más pequeñas B
, C
y D
.
B
, C
Y D
poner en práctica las interfaces IB
, IC
y ID
respectivamente.
Dado que A
admite toda la funcionalidad de B
, C
e D
, A
implementa IB
, IC
y ID
también, pero desafortunadamente esto lleva a una gran cantidad de cambios de ruta en la implementación deA
Al igual que:
interface IB
{
int Foo {get;}
}
public class B : IB
{
public int Foo {get {return 5;}}
}
interface IC
{
void Bar();
}
public class C : IC
{
public void Bar()
{
}
}
interface ID
{
string Bash{get; set;}
}
public class D: ID
{
public string Bash {get;set;}
}
class A : IB, IC, ID
{
private B b = new B();
private C c = new C();
private D d = new D();
public int Foo {get {return b.Foo}}
public A(string bash)
{
Bash = bash;
}
public void Bar()
{
c.Bar();
}
public string Bash
{
get {return d.Bash;}
set {d.Bash = value;}
}
}
¿Hay alguna manera de deshacerse de esta redirección repetitiva A
? B
, C
y D
todos implementan funcionalidades diferentes pero comunes, y me gusta que A
implemente IB
, IC
y ID
porque significa que puedo pasar por A
sí mismo como una dependencia que coincide con esas interfaces, y no tengo que exponer los métodos auxiliares internos.
c#
design-patterns
patterns-and-practices
composition
Nick Udell
fuente
fuente
A
implementarIB
,IC
yID
es que es más sensato escribirPerson.Walk()
en lugar dePerson.WalkHelper.Walk()
, por ejemplo.Respuestas:
Lo que estás buscando comúnmente se llama mixins . Lamentablemente, C # no los admite de forma nativa.
Hay pocas soluciones: una , dos , tres y muchas más.
De hecho, me gusta mucho el último. La idea de usar una clase parcial generada automáticamente para generar la plantilla repetitiva es probablemente la más cercana a una solución realmente buena:
fuente
Si bien no reduce la plantilla en el código en sí, Visual Studio 2015 ahora viene con una opción de refactorización para generar automáticamente la plantilla para usted.
Para usar esto, primero cree su interfaz
IExample
e implementaciónExample
. Luego cree su nueva claseComposite
y hágala heredarIExample
, pero no implemente la interfaz.Agregue una propiedad o campo de tipo
Example
a suComposite
clase, abra el menú de acciones rápidas en el tokenIExample
en suComposite
archivo de clase y seleccione "Implementar interfaz a través de 'Ejemplo'" donde "Ejemplo" en este caso es el nombre del campo o propiedad.Debe tener en cuenta que si bien Visual Studio generará y redirigirá todos los métodos y propiedades definidos en la interfaz a esta clase auxiliar para usted, no redirigirá los eventos a partir del momento en que se publicó esta respuesta.
fuente
Tu clase está haciendo demasiado, es por eso que tienes que implementar tanto repetitivo. Dices en los comentarios:
Estoy en desacuerdo. Es probable que el acto de caminar implique muchas reglas y no pertenezca a la
Person
clase: pertenece a unaWalkingService
clase con unwalk(IWalkable)
método donde la persona implementaIWalkable
.Siempre tenga en cuenta los principios SÓLIDOS cuando escriba código. Los dos que son más aplicables aquí son Separación de preocupaciones (extraer el código para caminar en una clase separada) y Segregación de interfaz (dividir interfaces en tareas / funciones / habilidades específicas). Parece que puede tener algo de I con sus múltiples interfaces, pero luego está deshaciendo todo su buen trabajo al hacer que una clase las implemente.
fuente
walk(IWalkable)
método, personalmente no me gusta porque los servicios de caminata se convierten en responsabilidad de la persona que llama y no de la Persona, y no se garantiza la coherencia. Cualquier persona que llame tendría que saber qué servicio utilizar para garantizar la coherencia, mientras que mantenerlo en la clase Persona significa que debe cambiarse manualmente para que el comportamiento de caminar difiera, al tiempo que permite la inversión de dependencia.Lo que estás buscando es herencia múltiple. Sin embargo, ni C # ni Java lo tienen.
Puede extender B desde A. Esto eliminará la necesidad de un campo privado para B, así como el pegamento de redireccionamiento. Pero solo puede hacer esto para uno de B, C o D.
Ahora, si puede hacer que C herede de B y D de C, entonces solo tiene que hacer que A extienda D ...;) - solo para que quede claro, no estoy alentando eso en este ejemplo ya que no hay indicación para ello.
En C ++, podría tener A heredar de B, C y D.
Pero la herencia múltiple hace que los programas sean más difíciles de razonar y tiene sus propios problemas; Además, a menudo hay una forma limpia de evitarlo. Aún así, a veces sin él, uno necesita hacer compensaciones de diseño entre repetitivo y cómo se expone el modelo de objeto.
Se siente un poco como si estuvieras tratando de mezclar composición y herencia. Si esto fuera C ++, podría usar una solución de herencia pura. Pero como no lo es, recomendaría abrazar la composición.
fuente