Интерфейс C # и базовые классы - PullRequest
8 голосов
/ 18 января 2012

У меня есть интерфейс C # и конкретный класс, который реализует этот интерфейс.Теперь я хочу создать еще один класс, который реализует этот интерфейс.Достаточно просто.

Однако большинство методов в классах будут совершенно одинаковыми, и только пара методов изменится.

Я не хочу дублировать всю логику вмой второй класс, который содержится в моем первом.

Как мне создать второй класс и использовать логику в моем первом классе, за исключением дополнительных вещей?

Мой интерфейс называется IEventRepository,и мой первый класс называется BaseEvents.Теперь я хочу создать новый класс с именем FooBarEvents.

Мое определение класса для FooBarEvents:

public class FooBarEvents : BaseEvents, IEventRepository

Я собирался использовать возвращаемый base.Method () в каждом методедублирует код.

Я полагаю, это не правильно?

Ответы [ 8 ]

12 голосов
/ 18 января 2012

FooBarEvents нужно только наследовать от BaseEvents, а не реализовывать IEventRepository, поскольку BaseEvents уже реализует интерфейс Если вам нужно изменить поведение некоторых IEventRepository методов в FooBarEvents, просто переопределите эти методы.

Редактировать: некоторые примеры

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)
{ ... }
6 голосов
/ 18 января 2012

Поскольку BaseEvents уже реализует IEventRepository, вам не нужно реализовывать его снова в FooBarEvents.FooBarEvents автоматически наследует BaseEvents 'реализацию.

3 голосов
/ 18 января 2012

В следующем коде показано, как обеспечить общую реализацию некоторых методов интерфейса с абстрактным базовым классом и предоставить пользовательские реализации для других.

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
    }
  }

}

3 голосов
/ 18 января 2012

Почему бы вам не определить ваши методы в базовом классе как Virtual и переопределить те, которые вы хотите изменить в дочернем классе?

2 голосов
/ 18 января 2012

Использовать наследование:

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 унаследует все поведение Bar, и вы можете изменить специфическое поведение любых необходимых вам методов, переопределив их в BarOnSteroids (они должны быть помечены как виртуальные в базовом классе Bar).

Таким образом, вы получите следующее:

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.

Предполагается, что вы хотите изменить определенное поведение методов, являющихся частью интерфейса IFoo. Если все, что вам нужно, это добавить дополнительную функциональность к BarOnSteroids, тогда просто наследуйте форму Bar, чтобы унаследовать все ее функциональные возможности, и добавьте все необходимые новые методы для реализации новой функциональности.

2 голосов
/ 18 января 2012

Вы можете сделать свой второй класс продолжением вашего первого класса. Ваш первый класс может быть абстрактным, но реализовывать только общие методы из интерфейса.

0 голосов
/ 18 января 2012

Есть несколько разных подходов.

One. Полностью пропустите интерфейс и сделайте его абстрактным классом. Это проще, когда работает, но тот факт, что у вас может быть только один базовый класс, ограничивает использование в 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
  }
}

Вы можете иметь один класс, реализующий интерфейс, а другой наследовать от него:

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;
  }
}

Пусть они оба переопределят абстрактный класс, который дает некоторое общее поведение:

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;
  }
}

Они могут также использовать статический вспомогательный класс, который не имеет ничего общего с иерархией, но который предоставляет методы, полезные для реализации функциональности.

Будьте осторожны с этим паттерном:

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

Даже если IEventRepository.Method1 определено более разумно, вышеприведенное может привести к путанице.

0 голосов
/ 18 января 2012

Если определенный набор методов в реализации BaseEvents для IEventRepository всегда всегда будет поддерживать одну и ту же реализацию, то вы можете просто реализовать их в классе BaseEvents и отметить те из них что может изменить как virtual. Таким образом, если FooBarEvents хочет изменить реализацию одного из методов, он может просто переопределить его.

Просто примечание относительно добавления IEventsRepository в ваш класс FooBarEvents: это действительно так. См. здесь для ответа Джона Скита об этом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...