Подтвердить что ты не робот

"Базовый абстрактный общий класс является плохим выбором в большинстве ситуаций". Зачем? (Или почему нет)

Я только что видел в комментарии blog post:

Базовый абстрактный общий класс плохой выбор в большинстве ситуаций

Это правда, если не почему?

Какое понимание приводит к этому утверждению?

4b9b3361

Ответ 1

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

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

// Meaningful common ancestor for the working classes.
interface IWorker
{
   object DoWork();
}

// Generic abstract base class for working classes implementations.
abstract WorkerImpl<TResult> : IWorker
{
   public abstract TResult DoWork();

   object IWorker.DoWork()
   {
      return DoWork(); // calls TResult DoWork();
   }
}

// Concrete working class, specialized to deal with decimals.
class ComputationWorker : WorkerImpl<decimal>
{
    override decimal DoWork()
    {
       decimal res;

       // Do lengthy stuff...

       return res;
    }
}

В этом примере DoWork() было переопределено в абстрактном классе, став конкретным и специализированным в ComputationWorker.

Ответ 2

Я согласен, потому что все, что наследует абстрактный общий класс, не будет полиморфным с базовым классом. То есть, если у вас есть

abstract class myBase<T>

то вы создаете

class myThing: myBase<thing>
class myOtherThing: myBase<otherThing>

вы не можете создавать методы, которые работают против myThing и myOtherThing, поскольку они не разделяют предка. Нет никакого смысла в базовом классе быть абстрактным, на самом деле, это может быть просто класс.

Но если у вас есть базовый класс

abstract class myBase
class myBase<T>: myBase

как общий шаблон для общих классов (например, IEnumerable - с использованием интерфейсов), тогда все они разделяют myBase.

(править) Я только что прочитал фактическое сообщение в блоге - и на самом деле, комментарий в действительности недействителен. "Абстрактный базовый базовый класс", на который он ссылается, Range<T> наследует IEnumerable<T>, который наследует не общий интерфейс IEnumerable. Так что это не настоящий абстрактный базовый класс. Но в целом я думаю, что это правда.

Ответ 3

Одна проблема с абстрактным базовым базовым классом заключается в том, что вы не можете набрать украшение:

public abstract class Activity<TEntity>
{
  public Activity() { }

  protected virtual object Implementation { ... }
}

public abstract class CompensableActivity<TEntity,TCompensation> : Activity<TEntity>
  where TCompensation : Activity<T>, new()
{
  public CompensableActivity() { }

  protected override object Implementation
  {
    get { new Wrapper(base.Implementation, Compensation); }
  }

  private Activity<TEntity> Compensation
  {
    get
    {
      var compensation = new TCompensation();
      if(compensation is CompensableActivity<TEntity,Activity<TEntity>)
      {
        // Activity<TEntity> "does not meet new() constraint" !
        var compensable = comp as CompensableActivity<TEntity, Activity<TEntity>>;
        var implement = compensable.Implementation as Wrapper;
        return implement.NormalActivity;
      }
      else { return compensation; }
    }
  }
}

Ответ 4

Краген делает хороший момент. Все, что меньше 50% вашего кода, является "неправильным выбором в большинстве ситуаций".

Однако, хотя нигде около 50% ваших классов не должны быть абстрактными базовыми классами, это также не менее хорошо, чем любая другая языковая функция.

Например, BindingList<T> можно рассматривать как абстрактный базовый базовый класс. Это общий контейнер, и сортировка требует от вас извлечь из него и переопределить ApplySortCore.

KeyedCollection<TKey, TItem> не просто действует как абстрактный базовый базовый класс, он один. Чтобы использовать его, вы ДОЛЖНЫ извлечь из него и реализовать GetKeyForItem.

Ответ 5

Я не согласен с толпой здесь. В некоторых случаях абстрактным общим классом является лучший дизайн. Хороший пример в .NET можно найти в System.Collections.ObjectModel, где KeyedCollection позволяет вам легко переопределять и реализовывать типизированную сериализуемую сборку словарей!

Я исключил большую часть кода, но это принцип:

public class NameCollection : System.Collections.ObjectModel.KeyedCollection<string, INamedObj>
{

    protected override string GetKeyForItem(INamedObj item)
    {
        return item.Name;
    }
}

Ответ 6

Ну, статистически говоря, если бы кто-то спросил меня , должен ли я сделать этот класс абстрактным родовым классом?, ответ почти наверняка не будет - через 3 года..Net development Я думаю, что могу подсчитайте количество абстрактных классов, которые я написал, которые имели общие параметры типа, с одной стороны.

Кроме этого, я не вижу какой-либо особой причины, чтобы абстрактный общий класс считался Bad Thing - его просто не было общим.

Ответ 7

Бывают ситуации, когда абстрактный базовый класс полезен.

У нас есть несколько приложений .net, которые используют разные двигатели баз данных. Несколько серверов sql, пара mysql и множество приложений oracle.

У нас есть общий общий объект базы данных, который основан на абстрактном классе, который представляет собой factory, который возвращает правильный объект базы данных в параметре factory в зависимости от типа базы данных.

Таким образом, если я запускаю новое приложение, все, что мне нужно сделать, это загрузить этот объект базы данных, передать его тип, передать в строку подключения и bam... i...... >

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