2012-01-18 13 views
7

Tengo una interfaz C# y una clase concreta que implementa esa interfaz. Ahora quiero crear otra clase que implemente esa interfaz. Suficientemente simple.C# Interfaz y clases base

Sin embargo, la mayoría de los métodos serán exactamente los mismos en las clases, y solo un par de métodos realmente cambiarán.

No quiero duplicar toda la lógica en mi segunda clase que está contenida en mi primera.

¿Cómo creo la 2da clase y uso la lógica en mi primera clase a excepción de las cosas adicionales?

Mi interfaz se llama IEventRepository, y mi primera clase se llama BaseEvents. Ahora quiero crear una nueva clase llamada FooBarEvents.

Mi definición de clase para FooBarEvents es:

public class FooBarEvents : BaseEvents, IEventRepository 

Mi intención era entonces utilizar el base.Method retorno() en cada método que duplica el código.

Supongo que esto no es correcto?

+0

¿Exactamente por qué está utilizando una interfaz? –

Respuesta

10

FooBarEvents sólo tendrá que heredar de BaseEvents, no aplique además IEventRepository, como BaseEvents ya implementa la interfaz. Si necesita cambiar el comportamiento de algunos métodos IEventRepository en FooBarEvents, simplemente anule esos métodos.

Editar: algunos ejemplos

interface IEventRepository 
{ 
    void CommonMethodA(); 
    void CommonMethodB(); 
    void ImplentationSpecificMethod(); 
} 

abstract class BaseEvents : IEventRepository 
{ 
    public void CommonMethodA() 
    { ... } 

    public virtual void CommonMethodB() 
    { ... } 

    public abstract void ImplementationSpecificMethod(); 

    public void BaseEventsMethod() 
    { ... } 

    public void BaseEventsMethod2() 
    { ... } 
} 

class FooBarEvents : BaseEvents 
{ 
    public override void CommonMethodB() 
    { 
     // now FooBarEvents has a different implementation of this method than BaseEvents 
    } 

    public override void ImplementationSpecificMethod() 
    { 
     // this must be implemented 
    } 

    public new void BaseEventsMethod2() 
    { 
     // this hides the implementation that BaseEvents uses 
    } 

    public void FooBarEventsMethod() 
    { 
     // no overriding necessary 
    } 
} 

// all valid calls, assuming myFooBarEvents is instantiated correctly 
myFooBarEvents.CommonMethodA() 
myFooBarEvents.CommonMethodB() 
myFooBarEvents.BaseEventsMethod(); 
myFooBarEvents.BaseEventsMethod2(); 
myFooBarEvents.FooBarEventsMethod(); 
myFooBarEvents.ImplementationSpecificMethod(); 

// use the contract thusly: 
void DoSomethingWithAnEventRepository(BaseEvents events) 
{ ... } 
+0

Lo entiendo, pero la clase FooBarEvents sería específica del cliente y puede tener otros 10 métodos que no se implementan en BaseEvents (son específicos). ¿No sería una mala práctica para BaseEvents tener 10 métodos todos como virtuales y sin hacer nada más que lanzar una excepción no implementada o una excepción de operación no válida? – Paul

+0

No estoy seguro de entender lo que estás preguntando.¿Estás diciendo que agregarás 10 métodos específicos del cliente a 'FooBarEvents' pero que deberías agregar firmas de esos eventos a' BaseEvents' para anularlos? Ese no es el caso; simplemente puede agregar las implementaciones directamente a 'FooBarEvents'. Editaré mi respuesta y agregaré un ejemplo. –

+0

Si no agrego esas firmas a BaseEvents, entonces obtendré un error que dice que BaseEvents no implementa ciertos miembros de la interfaz. Estoy usando inyección de dependencia, así que tendré que agregar el contrato a la interfaz para los miembros que quiero en mi clase FooBarEvents. – Paul

6

Dado que BaseEvents ya implementa IEventRepository, no es necesario implementarlo de nuevo en FooBarEvents. FooBarEvents hereda automáticamente la implementación BaseEvents '.

2

Puede hacer que su segunda clase amplíe su primera clase. Su primera clase puede ser abstracta pero solo implementar los métodos comunes desde la interfaz.

+0

"Puedes hacer que tu segunda clase te extienda de segunda clase" - ¿quieres decir "extender tu primera clase"? –

+0

sí lo siento - tiene razón samuel –

+0

Estoy usando inyección de dependencia Ninject que no quiere saber sobre clases abstractas. – Paul

0

Si una determinada selección de métodos en la BaseEvents implementación de IEventRepository son siempre va a mantener la misma aplicación, a continuación, puedes ponerlas en práctica en la clase BaseEvents y la marca los que podrían cambiar como virtual. De esta forma, si FooBarEvents desea cambiar la implementación de uno de los métodos, simplemente puede anularlo.

Solo una nota con respecto a agregar IEventsRepository a su clase FooBarEvents: es válido para hacer eso. Consulte here para obtener una respuesta de Jon Skeet al respecto.

3

¿Por qué no define sus métodos en la clase base como Virtual y que reemplazan los que desea cambiar en la clase secundaria?

2

utilizar la herencia:

public interface IFoo 
{ 
    void GeneralBehaviorMethod1(); 
    void GeneralBehaviorMethod2(); 
    void SpecificBehaviorMethod1(); 
} 

public class Bar: IFoo 
{ 
    public void GeneralBehaviorMethod1() {...} 
    public void GeneralBehaviorMethod2() {...} 

    public virtual void SpecificBehaviorMethod1() {...} 
    ... 
} 

public class BarOnSteroids: Bar 
{ 
    public override void SpecificBehaviorMethod1() {...} 
} 

BarOnSteroids heredarán todo el comportamiento de Bar y se puede alterar el comportamiento específico de los métodos que necesita reemplazando en BarOnSteroids (tienen que ser marcado como virtual en la clase base Bar).

De esta manera se tendría el siguiente:

IFoo iFoo = new Bar(); 
iFoo.SpecificBehaviorMethod1(); //Bar implementation will be called; 

IFoo iFoo = new BarOnSteroids(); 
iFoo.SpecificBehaviorMethod1(); //BarOnSteroids implementation will be called. 
iFoo.CommonBehaviorMethod1(); //Bar implementation will be called. 

Bar bar = new BarOnSteroids(); 
bar.SpecificBehaviorMethod1(); //BarOnSteroids implementation will be called. 
bar.CommonBehaviorMethod1(); //Bar implementation will be called. 

Esto supone que desea cambiar el comportamiento específico de los métodos que son parte de la interfaz IFoo. Si todo lo que desea es agregar funcionalidad adicional al BarOnSteroids, simplemente herede el formulario Bar para heredar toda su funcionalidad y agregar todos los nuevos métodos necesarios para implementar la nueva funcionalidad.

+0

Así que si estaba consumiendo IFoo usando Bar y llamé SpecificBehaviourMethod1, supongo que obtendría una NotImplementedException, parece como si BarOnSteroids hiciera algo como Bar doesnt? – Paul

+0

@Pual. Consulte la edición de la respuesta. En resumen, no, tanto 'Bar' como' BarOnSteroids' debe implementar 'SpecificBehaviorMethod1' porque este método es parte del contrato' IFoo'. Siendo el caso que 'SpecificBehaviorMethod' es virtual, llamará a la implementación específica al tipo real de la instancia a la que llama. – InBetween

3

El siguiente código muestra cómo proporcionar una implementación común de algunos métodos de interfaz con una clase base abstracta y proporciona implementaciones personalizadas para otros.

public interface IEventRepository 
{ 
    void Method1(); 
    void Method2(); 
} 

public abstract class BaseEvents : IEventRepository 
{ 
    public void Method1() 
    { 
    Console.WriteLine("This is shared functionality"); 
    } 

    public abstract void Method2(); 
} 

public class Implementation1 : BaseEvents 
{ 
    override public void Method2() 
    { 
    Console.WriteLine("Impl1.Method2"); 
    } 
} 

public class Implementation2 : BaseEvents 
{ 
    override public void Method2() 
    { 
    Console.WriteLine("Impl2.Method2"); 
    } 
} 

public class Program 
{ 
    static void Main(string[] args) 
    { 
    var implementations = new List<IEventRepository> { new Implementation1(), new Implementation2() }; 

    foreach (var i in implementations) 
    { 
     Console.WriteLine(i.GetType().Name); 
     Console.Write("\t"); 
     i.Method1(); // writes 'This is shared functionality' 

     Console.Write("\t"); 
     i.Method2(); // writes type specific message 
    } 
    } 

}

+0

¿Podemos tener un declaración de implementación de interfaz explícita en este caso? Quiero decir algo como IEventRepository.Method2() {}. – remio

+0

seguro, pero yo realmente no entiendo el valor de las interfaces explícitas – Jason

+0

En mi opinión, impone el tipo al ayudar a la clase del cliente a olvidarse de la implementación subyacente. – remio

0

Hay algunos enfoques diferentes.

Uno. Omita la interfaz por completo y conviértala en una clase abstracta. Esto es más sencillo cuando funciona, pero el hecho de que sólo puede tener una clase base restringe su uso en C#

public abstract class EventRepository 
{ 
    public abstract int MustBeOverridden(string str);//classes have to override this 
    public virtual int CanBeOverridden(int i)//classes can override but may choose not to. 
    { 
    return 4; 
    } 
    public int CannotOverride(string str)//this is always the same 
    { 
    return MustBeOverridden(str) + 3;//can make use of this 
    } 
} 

Usted puede tener una clase implementa la interfaz, y la otra se derivan de ella:

public interface IEventRepository 
{ 
    int Method1(string str); 
    int Method2(string str); 
} 

public class EventClass1 : IEventRepository 
{ 
    public int Method1(string str)//can't be overridden as not marked virtual 
    { 
    return 1; 
    } 
    public virtual int Method2(string str)//can be overridden 
    { 
    return 2; 
    } 
} 

public class EventClass2 : EventClass1 
{ 
    public override int Method2(string str) 
    { 
    return -2; 
    } 
} 

tenerlos a ambos anulan una clase abstracta que proporciona un comportamiento común:

public abstract class EventClass : IEventRepository 
{ 
    public abstract int Method1(string str); 
    public int Method2(string str) 
    { 
    return 2; 
    } 
} 

public class EventClass1 : EventClass 
{ 
    public override int Method1(string str) 
    { 
    return 1; 
    } 
} 
public class EventClass2 : EventClass 
{ 
    public override int Method1(string str) 
    { 
    return -1; 
    } 
} 

también podrían utilizar una clase auxiliar estática que no tiene nada que ver con la jerarquía, pero que proporciona métodos que son útiles para implementar la funcionalidad.

Tenga cuidado con pesar de este patrón:

public class EventClass1 : IEventRepository 
{ 
    public int Method1(string str)//not override-able 
    { 
    return 1; 
    } 
    public int Method2(string str)//not override-able 
    { 
    return 2; 
    } 
} 
public class EventClass2 : EventClass1, IEventRepository 
{ 
    //We really want our own Method1! 
    public new int Method1(string str) 
    { 
    return 3; 
    } 
    int IEventRepository.Method1(string str) 
    { 
    return -1; 
    } 
} 

EventClass2 e2 = new EventClass2(); 
EventClass1 e1 = e2; 
IEventRepository ie = e2; 
Console.WriteLine(e2.Method1(null));//3 
Console.WriteLine(e1.Method1(null));//1 
Console.WriteLine(ie.Method1(null));//-1 

Incluso cuando IEventRepository.Method1 se define más sensible, lo anterior es probable que lleve a confusión.

Cuestiones relacionadas