Когда целесообразно использовать Generics Versus Inheritance? - PullRequest
8 голосов
/ 28 апреля 2009

Каковы ситуации и связанные с ними преимущества использования Generics по сравнению с Inheritance и наоборот, и как их лучше сочетать?

Спасибо за ответ, ребята.

Я постараюсь изложить мотивацию для этого вопроса как можно лучше: У меня есть класс, как показано ниже:

class InformationReturn<T> where T : Info
{
    InformationReturn(Employee employee, List<T>) { ... }
}

Теперь предположим, что у меня есть репозиторий, который принимает аргумент InformationReturn, который должен обрабатывать различные поля в БД в зависимости от типа объекта Info. Лучше ли создавать разные репозитории для каждого типа Т; один репозиторий, который использует отражение для определения типа; или есть ли лучший способ использования возможностей наследования по сравнению с генериками?

Примечание : другой код клиента должен работать по-разному в зависимости от типа T.

Ответы [ 7 ]

12 голосов
/ 28 апреля 2009

Обобщение и наследование - это две разные вещи. Наследование - это концепция ООП, а дженерики - это функция CLR, которая позволяет указывать параметры типа во время компиляции для типов, которые их предоставляют.

Наследование и дженерики действительно довольно хорошо работают вместе.

Наследование:

Наследование позволяет мне создать один тип:

class Pen { }

, а затем создайте еще один тип, расширяющий Pen:

class FountainPen : Pen { }

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

Дженерики:

Обобщение - это функция CLR, которая позволяет мне создавать такой тип:

class Foo<T> 
{
    public T Bar { get; set; }
}

Теперь, когда я использую Foo<T>, я могу указать тип T, предоставив аргумент универсального типа:

Foo<int> foo = new Foo<int>();

Теперь, поскольку я указал, что T будет int для объекта, который я только что создал, тип Foo.Bar также будет int, поскольку он был объявлен как тип T.

9 голосов
/ 28 апреля 2009

Используйте обобщенные значения для определения алгоритма или типа поведения, которое может быть выражено в терминах некоторого «неизвестного типа» при сохранении API, который строго типизирован в терминах этого неизвестного типа. Неизвестный тип известен как параметр типа и выражается в коде следующим образом:

public class List<T>
{
    public void Add(T item)
}

(и т. Д.) - здесь T - параметр типа. Общие методы похожи:

public void Foo<T>(T item)

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

List<string> list = new List<string>();
list.Add("hi");

Использование наследования для специализации поведения типа.

Я не могу думать о многих местах, где они являются альтернативами друг другу ...

8 голосов
/ 28 апреля 2009

Я думаю, что вы должны использовать обобщенные элементы, если вы хотите, чтобы к различным типам (Add, Remove, Count) применялась одинаковая функциональность, и она будет реализована одинаково. Наследование - это когда вам нужна та же функциональность (GetResponse), но вы хотите, чтобы она реализовывалась разными способами.

5 голосов
/ 28 апреля 2009

Это действительно разные идеи. Обобщения позволяют вам объявлять общие «специфические» функциональные возможности (рискуя казаться оксюморонными) в общем виде. List<int> не функционирует иначе, чем List<string>, за исключением типа данных, которые содержатся внутри.

Хотя наследование можно использовать для того же, я мог бы создать класс List, затем класс IntList и StringList, которые наследуются от него. Я мог бы легко заставить эти два класса функционировать совершенно по-разному, или иметь один функционал предложения, недоступный в другом.

Редактировать

После проверки правки вопроса ответ сортируется так: «это зависит». Вы можете приводить аргументы для обеих сторон - и, действительно, LINQ to SQL и Entity Framework являются комбинацией как рефлексивного осмотра с использованием обобщенных типов, так и классов сущностей со строгой типизацией и других классов репозитория. Вы, конечно, можете использовать подход, который вы рассматриваете, просто знайте, что, в общем, проблема, которая может быть решена либо с помощью рефлексии, либо с помощью чего-то еще, скорее всего, будет быстрее, когда будет решена «чем-то другим». Все сводится к тому, сколько вы хотите компромисса между производительностью, ремонтопригодностью, удобочитаемостью и надежностью.

4 голосов
/ 02 мая 2009

Используйте дженерики, когда вы хотите создать «шаблон», который может применяться ко многим стилям неизвестных классов. Например. Коллекции держат ??? хорошие кандидаты на генерики. Наследование - это когда у вас есть базовое понятие, что дети «являются» расширением этой концепции.

Мои общие правила

  • если вы начнете определять свойства как объект в своем коде и будете многократно приводить типы, тогда, вероятно, настало время для обобщений.
  • Если вы хотите программировать против «более высокой концепции», а также производного класса, тогда его наследование.
  • Если ваш класс собирается обернуть или работать над концертным классом, тогда его дженерики.
  • Если вы полагаетесь на специфику неизвестного «еще не определенного» класса, то вам, вероятно, лучше использовать дженерики.
  • Если у вас производные классы "is a", то обычно это наследование
  • Если ваш суперкласс "использует некоторые x", то его дженерики.
3 голосов
/ 28 апреля 2009

Наследование - это гораздо больше о "is-a" (лягушка - животное), где дженерики - это создание контейнеров, которые действуют на типизированные данные (Список T, Обработчик T и т. Д.). Они не являются взаимоисключающими .

Вы можете иметь это, если хотите:

public class Base<T>
{

}

public class Derived : Base<Foo>
{

}
0 голосов
/ 10 сентября 2018

Ни наследование, ни параметризованные типы не могут изменяться во время выполнения

Наследование позволяет вам предоставлять реализации операций по умолчанию и позволяет подклассам переопределять их.

Параметризованные типы позволяют вам изменять типы, которые может использовать класс.

Но какой подход лучше, зависит от вашего дизайна и ограничений реализации

Элементы шаблонов проектирования многоразового объектно-ориентированного программного обеспечения

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