Я только что видел в комментарии blog post:
Базовый абстрактный общий класс плохой выбор в большинстве ситуаций
Это правда, если не почему?
Какое понимание приводит к этому утверждению?
Я только что видел в комментарии blog post:
Базовый абстрактный общий класс плохой выбор в большинстве ситуаций
Это правда, если не почему?
Какое понимание приводит к этому утверждению?
"Большинство ситуаций" совершенно расплывчато. Общий абстрактный класс (или интерфейс) - это плохая идея , если, единственным общим предком между потомками такого класса является 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
.
Я согласен, потому что все, что наследует абстрактный общий класс, не будет полиморфным с базовым классом. То есть, если у вас есть
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
. Так что это не настоящий абстрактный базовый класс. Но в целом я думаю, что это правда.
Одна проблема с абстрактным базовым базовым классом заключается в том, что вы не можете набрать украшение:
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; }
}
}
}
Краген делает хороший момент. Все, что меньше 50% вашего кода, является "неправильным выбором в большинстве ситуаций".
Однако, хотя нигде около 50% ваших классов не должны быть абстрактными базовыми классами, это также не менее хорошо, чем любая другая языковая функция.
Например, BindingList<T>
можно рассматривать как абстрактный базовый базовый класс. Это общий контейнер, и сортировка требует от вас извлечь из него и переопределить ApplySortCore
.
KeyedCollection<TKey, TItem>
не просто действует как абстрактный базовый базовый класс, он один. Чтобы использовать его, вы ДОЛЖНЫ извлечь из него и реализовать GetKeyForItem
.
Я не согласен с толпой здесь. В некоторых случаях абстрактным общим классом является лучший дизайн. Хороший пример в .NET можно найти в System.Collections.ObjectModel, где KeyedCollection позволяет вам легко переопределять и реализовывать типизированную сериализуемую сборку словарей!
Я исключил большую часть кода, но это принцип:
public class NameCollection : System.Collections.ObjectModel.KeyedCollection<string, INamedObj>
{
protected override string GetKeyForItem(INamedObj item)
{
return item.Name;
}
}
Ну, статистически говоря, если бы кто-то спросил меня , должен ли я сделать этот класс абстрактным родовым классом?, ответ почти наверняка не будет - через 3 года..Net development Я думаю, что могу подсчитайте количество абстрактных классов, которые я написал, которые имели общие параметры типа, с одной стороны.
Кроме этого, я не вижу какой-либо особой причины, чтобы абстрактный общий класс считался Bad Thing - его просто не было общим.
Бывают ситуации, когда абстрактный базовый класс полезен.
У нас есть несколько приложений .net, которые используют разные двигатели баз данных. Несколько серверов sql, пара mysql и множество приложений oracle.
У нас есть общий общий объект базы данных, который основан на абстрактном классе, который представляет собой factory, который возвращает правильный объект базы данных в параметре factory в зависимости от типа базы данных.
Таким образом, если я запускаю новое приложение, все, что мне нужно сделать, это загрузить этот объект базы данных, передать его тип, передать в строку подключения и bam... i...... >
Я предполагаю, что я пытаюсь сказать, все зависит от контекста и от того, как он используется на самом деле.