Интерфейс, абстрактные или просто виртуальные методы?


У меня есть куча систем, назовем их A, B, C, D, E, F, G, H, I, J.

Все они имеют сходные методы и свойства. Некоторые из них содержат точно такой же метод и свойства, некоторые могут незначительно отличаться, а некоторые могут сильно отличаться. Прямо сейчас у меня есть много дублированного кода для каждой системы. Например, у меня есть метод под названием GetPropertyInformation(), который определен для каждой системы. Я пытаюсь выяснить, какой метод был бы лучшим подходом для уменьшения дубликата кода, или, возможно, один из методов ниже не является способом go:

Интерфейс

public Interface ISystem
{
    public void GetPropertyInformation();
    //Other methods to implement
}

public class A : ISystem
{
    public void GetPropertyInformation()
    {
       //Code here
    }
}

Аннотация

public abstract class System
{
    public virtual void GetPropertyInformation()
    {
        //Standard Code here
    }
}

public class B : System
{
   public override void GetPropertyInformation()
   {
      //B specific code here
    }
}

Виртуальные методы в Супербазисном классе

public class System
{
   public virtual void GetPropertyInformation()
    {
     //System Code
    }
}

public class C : System
{
  public override void GetPropertyInformation()
  {
      //C Code
  }
}

Один вопрос, хотя это может быть глупо, давайте предположим, что я пошел с абстрактным подходом, и я хотел переопределить GetPropertyInformation, но мне нужно было передать ему дополнительный параметр, возможно ли это или мне придется создать другой метод в абстрактном классе? Например, GetPropertyInformation(x)

6 8

6 ответов:

Ваш абстрактный и "супербазисный" подходы не слишком отличаются. Вы всегда должны делать базовый класс абстрактным, и вы можете предоставить реализацию по умолчанию (виртуальные методы) или нет (абстрактные методы). Решающим фактором является то, хотите ли вы когда-нибудь иметь экземпляры базового класса, я думаю, что нет.

Так что это между базовым классом и интерфейсом. Если существует сильная связь между вашими классами A, B C, то вы можете использовать базовый класс и, вероятно, общую реализацию.

Если классы A, B, C естественным образом не принадлежат к одному "семейству", то используйте интерфейс.

И System - не такое уж хорошее имя.

И вы не можете изменить список параметров при переопределении. Возможно, параметры по умолчанию могут помочь, в противном случае вам просто нужно 2 перегрузки для GetPropertyInformation().

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

Что касается переопределения метода и изменения списка параметров, то это просто невозможно. Представьте себе, как бы вы вызвали этот метод в базовом классе или ссылке на интерфейс?

Я бы выбрал что-то вроде того, что я добавил ниже. Вы по-прежнему получаете выгоду от контракта интерфейса и совместной реализации.

public Interface ISystem
{
    public void GetPropertyInformation();
    //Other methods to implement
}

public abstract class System : ISystem
{
    public virtual void GetPropertyInformation()
    {
        //Standard Code here
    }
}

public class B : System
{  
   public string ExtendedSystemProp {get;set;}

   public override void GetPropertyInformation()
   {
      base.GetPropertyInformation();

      var prop = "some extra calculating";

      GetExtraPropertyInformation(prop);
    }

    public void GetExtraPropertyInformation(string prop)
    {
         ExtendedSystemProp = prop;
    }
}

ISystem genericSystem = new B();
genericSystem.GetPropertyInformation();

(genericSystem as B).ExtendedSystemProp = "value";

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

Решение использовать базовый класс или интерфейс для вашей реализации действительно зависит от вашего использования. Имеют ли A-I достаточно общего друг с другом, чтобы все они действительно были производными от одного и того же базового класса? Если да, то используйте базовый класс. Является это действительно то, что просто GetPropertyInformation является общим, а в остальном системы полностью функционально различны? Тогда вы действительно просто хотите, чтобы у них был общий интерфейс.

Другие рассмотрели то, что было первоначально в моем ответе, но о пункте "Добавление параметра": не забывайте, что последний C# также позволяет вам иметь необязательные параметры в методах.

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