![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Наследники TList
Добежал © (2008-09-24 18:19:00)Думаю, в любом крупном проекте используется TList, так как постоянно возникает необходимость хранить списки с некоей информацией. И тут возможны два подхода:
1) когда о содержимом TList знает только "вышестоящий" класс, он и типизирует информацию:
TMySuperClass = class(...)
...
FClientList: TList;
...
end;
Реализация:
constructor TMySuperClass.create;
begin
...
FClientList := TList.Create;
...
end;
destructor TMySuperClass.destroy;
var
i: integer;
begin
...
for i:=0 to FClientList.Count - 1 do
Dispose(PClientInfo(FClientList[i]));
FClientList.Free;
end;
Можно немного продвинутей писать (продвинутей ли?), если в классе происходит удаление какого-то клиента во время работы, то ввести функцию DeleteClientByPos:
function DeleteClientByPOS(iPos: integer): boolean;
begin
if (iPos >=0) and (iPos < FClientList.Count) then
begin
Dispose(FClientList[iPos]);
FClientList.delete(iPos);
Result := true;
end
else Result := false;
end;
Тогда деструктор поменять можно на:
for i:=FClientList.Count-1 downto 0 do
DeleteClientByPOS(i);
суть не меняется.
2) второй же вариант - это написание каждый раз наследника TList, который будет уметь работать именно с типизированными указателями нужной структуры.
Второй вариант по идеологии правильней, но каждый раз писать... А ведь таких списков может быть десятки, сотни... тысячи. Да и шаблоны дельфи не поддерживает.
Кто как делает? Еще фишка в том, что половина модуля может состоять потом из реализаций TList'ов. Выносить в отдельный модуль uData? Или uLister какой-нибудь ;)
А наверняка еще и парадигма мож какая имеется на эту тему? Жду отзывов кто как делает ;)
Ega23 (2008-09-25 00:10:00) [81]
> Я не писал наследников, использовал TObjectList напрямую.
Напрямую не всегда удобно, приводить Items[i] всегда надо.
MsGuns (2008-09-24 23:52:00) [82]Я вообще не понял к чему сабж. Это типа "Чуваки, я завязал кушать мясо и чувствую себя зашибись !" ?
Eraser (2008-09-24 23:39:00) [83]> [8] guav © (24.09.08 21:14)
+1 )
jack128_ (2008-09-24 21:56:00) [84]
> Да и шаблоны дельфи не поддерживает.
Ну собственно
> уже ж появились дженерики
это я только вернувшись к семинара..
guav (2008-09-24 21:44:00) [85]Удаление из середины вообще нужно ? А констатное время доступа к элементу по его номеру в списке ?
> Жду отзывов кто как делает ;)
Я не писал наследников, использовал TObjectList напрямую.
DVM (2008-09-24 21:32:00) [86]Я за первый вариант.
guav (2008-09-24 21:14:00) [87]уже ж появились дженерики, нет ? ;)
Добежал (2008-09-24 21:08:00) [88]
> А в целом - есть TObjectList, который прекрасно вызывает
> деструкторы своих объектов, если надо
понятно, но это если хранить классы. У меня зачастую хранятся именно структуры аля:
TClientInfo = record
Name:
Family:
Date
bla bla
end;
С другой стороны каждую структуру можно сделать классом... Будет такой аля java подход ;)
> Вообще отказаться от листов с рекордами. Что я и сделал
типа такая попытка вызвать интерес и нарваться на вопрос уточняющий. А я не буду задавать вопрос. Отказался - и молодец ;)
Sergey Masloff (2008-09-24 21:05:00) [89]Почему не нужно наследоваться от TList написано у Бакнела. У меня нет доводов которые я могу ему противопоставить.
Поросенок Винни-Пух (2008-09-24 18:34:00) [90]Кроме третьего варианта есть еще дав с половиной.
Если вся загвоздка в типе для диспоза, то ведь сам тип можно сделать параметром и передавать в десруктор элемента списка
oldman (2008-09-24 18:28:00) [91]
> А ведь таких списков может быть десятки, сотни... тысячи.
Ты чего там пишешь?
Поросенок Винни-Пух (2008-09-24 18:26:00) [92]Третий вариант. Радикальный.
Вообще отказаться от листов с рекордами. Что я и сделал.
Ega23 (2008-09-24 18:26:00) [93]А в целом - есть TObjectList, который прекрасно вызывает деструкторы своих объектов, если надо.
Ega23 (2008-09-24 18:25:00) [94]Наследника. Надо типизированного - пиши типизированного.
for i:=0 to FClientList.Count - 1 do
Dispose(PClientInfo(FClientList[i]));
Перекрыть Notify в наследнике.
TGUIDList = class (TList)
private
function GetItem(Index: Integer): TGUID;
protected
procedure Notify(Ptr: Pointer; Action: TListNotification); override;
public
function Add(Item : TGUID) : Integer;
procedure Clear; override;
property Items[Index : Integer] : TGUID read GetItem; default;
function LoadFromStream(ms : TMemoryStream; const BuffLength : Cardinal) : Boolean;
function SaveToStream(const TagID : Integer; ms : TMemoryStream) : Boolean;
end;
{ TGUIDList }
//*****************************************************************************
function TGUIDList.Add(Item: TGUID): Integer;
var
p : PGUID;
begin
New(p);
p^ := Item;
Result := inherited Add(p);
end;
//*****************************************************************************
procedure TGUIDList.Clear;
var
i : Integer;
p : Pointer;
begin
for i:=0 to Count-1 do
begin
p := Get(i);
Dispose(PGUID(p));
end;
inherited;
end;
//*****************************************************************************
function TGUIDList.GetItem(Index: Integer): TGUID;
begin
Result := PGUID(Get(Index))^;
end;
//*****************************************************************************
function TGUIDList.LoadFromStream(ms: TMemoryStream;
const BuffLength: Cardinal): Boolean;
var
guid : TGUID;
i, cnt : Integer;
recSize : Cardinal;
begin
try
Result := True;
Clear;
recSize := SizeOf(TGUID);
cnt := BuffLength div recSize;
if cnt=0 then Exit;
for i:=1 to cnt do
begin
ms.ReadBuffer(guid, recSize);
Add(guid);
end;
except
Clear;
Result := False;
end;
end;
//*****************************************************************************
procedure TGUIDList.Notify(Ptr: Pointer; Action: TListNotification);
begin
inherited;
if Action in [lnExtracted, lnDeleted] then
Dispose(PGUID(Ptr));
end;
//*****************************************************************************
function TGUIDList.SaveToStream(const TagID: Integer;
ms: TMemoryStream): Boolean;
var
i : Integer;
BuffLen : Cardinal;
guid : TGUID;
begin
try
ms.WriteBuffer(TagId, 4);
BuffLen := Count*SizeOf(TGUID);
ms.WriteBuffer(BuffLen, 4);
for i:=0 to Count-1 do
begin
guid := Items[i];
ms.WriteBuffer(guid, SizeOf(TGUID));
end;
Result := True;
except
Result := False;
end;
end;
//*****************************************************************************