- Код: Выделить всё
MyCollection := TCollection.Create(TMyCollectionItem);
Этот способ хорош, если коллекция используется для внутреннего использования. Если же она делается для интерфейса работы, то никто не застрахован, чтобы в этой коллекции попытаться сохранить элемент типа TStrangeCollectionItem и компилятор ошибки не выдаст, а в момент добавления возникнет runtime-ошибка InvalidProperty, которую отловить гораздо сложнее, особенно тому, кто не сам создавал данную коллекцию.
Поэтому создание коллекции сопровождается добавлением следующего в прямом смысле слова шаблонно-генерируемого кода
- Код: Выделить всё
TMyCollection = class (TCollection)
public
constructor Create;
function Add: TMyCollectionItem;override;
function FindItemID(ID: Integer): TMyCollectionItem;override;
function Insert(Index: Integer): TMyCollectionItem;override;
property ItemClass: TMyCollectionItemClass;override;
property Items[Index: Integer]: TMyCollectionItem;override;
end;
По большому счету только в этом и все преимущество генериков. А теперь пойдем по недостаткам.
1) как правильно сделать связанные генерики? Например хочу, чтобы и базовый класс мог бы генерироваться так:
- Код: Выделить всё
TMyCollectionItem = class(TCollectionItem)
public
property Collection: TMyCollection;
end;
очень часто в C++ есть контейнеры и итераторы, между которыми аналогичная связь
2)мое лично мнение, но генерики должны быть только для классов.
то есть, например коллекция может генерироваться лишь от потомка TCollectionItem
- Код: Выделить всё
TGenericCollection<T: TCollectionItem> = class
На данный момент никто не запрещает специализировать генерик чем-угодно, ошибка возникает уже при компиляции специализированного генерика, хотя лучше всего если бы была ошибка например “Данный тип не подходит для специализации” или “Данный тип нарушает концепцию генерика”.
Тут появилось слово “концепция”. Это слово появилось в C++ в стандарте 2008, хотя шаблоны уж двадцать лет как есть. Это те же самые ограничения. Например можно создать концепцию “числовой тип” и уже после этого генерик нельзя специализировать строкой. А пока концепции еще не реализованы в C++, то никто не запрещает специализировать генерик строкой. Более того, может оказаться, что компиляция пройдет (потому что генерик использовал только “больше”, “равно” и “плюс”), но после того, как в новой версии разработчик задействовал и “минус”, то компиляция уже не пройдет.
Поэтому имхо, лучше использовать в качестве концепций классы и интерфейсы. Концепция определяется самим классом. Конечно, с простыми типами тогда уже ничего не получится.
3)генерики нарушают модульность. Привычная схема “декларация отдельно, реализация отдельно” уже не работает. В С++ вместо h и cpp появляются файлы без расширения, которые нужно компилировать при каждой сборке (утрирую), привычная схема линковки, понятное дело, уже не работает. Генерик+dll это вообще убийственная связка=) Еще много проблем этого уровня, число решений лучше считать по числу компиляторов C++, которые поддерживают экспорт шаблонов (кажется, он всего один=)).
На мой взгляд, лучше всего – это сделать более совершенные концепции рефакторинга кода, но это весьма далекие перспективы.