![]() |
| ||
|
|
Новости |
Поиск |
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 какой-нибудь ;)
А наверняка еще и парадигма мож какая имеется на эту тему? Жду отзывов кто как делает ;)
Игорь Шевченко (2008-10-05 13:47:00) [1]пуризм это конечно хорошо, но я не совсем понял, чем класс, в который агрегируется TList будет работать быстрее ? При уничтожении такого TList все равно будут вызываться все те же методы Clear и Notify для каждого из элементов, что и при уничтожении наследника от TList.
То есть, я даже прочитав цитату не понял, чем порождение наследников хуже, чем агрегация. В случае агрегации разве что кода писать больше, но это у пуристов всегда так - лишь бы писать :)
Добежал (2008-10-05 12:04:00) [2]Выложу полностью:
"Еще одной проблемой при использовании Tlist является создание производного класса. Если попытаться это сделать, можно столкнуться с
Разного рода проблемами, вызванными тем, что методы Tlist являются статическими, к тому же имеют приватные поля, которые недоступны, и.т.д
Можно только посоветовать не пытаться порождать новые классы от Tlist. Tlist - это не тот класс на основе которого можно создавать производные классы. Он был создан не таким расширяемым как например Tstrings. При необходимости можно создать отдельный класс, который для хранения данных использует Tlist. Применяйте в данном случае делегирование а не наследование
При написании предыдущего параграфа автор книги не знал чтокомпания Borland сделала с классом TList в Delphi5. В Delphi5 по каким-то непостижимым причинам было изменено функционирование класса TList с целью поддержки производного класса - TObjectList. TObjectList предназначен для хранения экземпляров объектов. Он находится в модуле contnrs
Что изменилось? В версии до D5 TList очищался путем освобождения внутреннего массива указателей, что было операцией класса O(1). Посколько в Борланд хотели чтобы TObjectList при определенных условиях мог освобождать содержащиеся в нем объекты, она для обеспечения такой функциональности изменила основной принцип работы TList. В Delphi 5 и выше TList очищается вызовом для каждого элемента нового виртуального метода Notify. TList.Notify не делает ничего но TObjectList.Notify при удалении элеиентов списка очищает занимаемую ими память
Вы можете спросить - ну и что? Дело в том что новый метод принадлежит к операциям класса O(N) то есть теперь время на очистку зависит от числа элементов в списке. По сравнению с предыдущими версиями новая версия TList (и каждый экземпляр наследников) стали работать медленнее. И единственная причина этого - нежелание Борланд воспользоваться делегированием вместо наследования. По мнению компании намного удобней было изменить стандартный класс
И что еще хуже с точки зрения ООП - мы получили ситуацию когда для поддержки производного класса был изменен родительский класс. TList не должен освобождать свои элементы - это правило начиная с Delphi1 Тем не менее он был изменен для того чтобы такая возможность появилась в производных классах (фактичекски только в одном - TObjectList "
И еще мнение Denny Thorpe из самой Borland
TList это рабочая лошадка а не порождающий класс... При необходимости использования списка создайте простой интерфейсный класс порожденный от TObject а не от TList который будет иметь только нужные вам эквиваленты свойств и методов TList и возвращаемые типы функций и типы параметров которого соответствуют хранимому типу. В таком случае интерфейсный класс будет содержать в себе TList и использовать его для хранения данных
Добежал (2008-10-05 12:01:00) [3]
> Бакнелл утверждает, что после того, как добавлен пустой
> метод Notify, удаление элементов из массива происходит гораздо
> медленнее
неверно. Написано по другому, вот:
Что изменилось? В версии до D5 TList очищался путем освобождения внутреннего массива указателей, что было операцией класса O(1). Посколько в Борланд хотели чтобы TObjectList при определенных условиях мог освобождать содержащиеся в нем объекты, она для обеспечения такой функциональности изменила основной принцип работы TList. В Delphi 5 и выше TList очищается вызовом для каждого элемента нового виртуального метода Notify. TList.Notify не делает ничего но TObjectList.Notify при удалении элеиентов списка очищает занимаемую ими память
Вы можете спросить - ну и что? Дело в том что новый метод принадлежит к операциям класса O(N) то есть теперь время на очистку зависит от числа элементов в списке. По сравнению с предыдущими версиями новая версия TList (и каждый экземпляр наследников) стали работать медленнее. И единственная причина этого - нежелание Борланд воспользоваться делегированием вместо наследования. По мнению компании намного удобней было изменить стандартный класс
Тын-Дын (2008-09-29 01:52:00) [4]
> Sergey Masloff (24.09.08 21:05) [6]
> Почему не нужно наследоваться от TList написано у Бакнела.
> У меня нет доводов которые я могу ему противопоставить.
>
Нашел я место у Бакнелла, где написано про TList. Но не нашел довод заего позицию.
Основной аргумент против использования наследования от TList - замедление работы TList.
Аргумент практически не выдерживает критики.
Бакнелл утверждает, что после того, как добавлен пустойметод Notify, удаление элементов из массива происходит гораздо медленнее(цитата от автора).
Это значительное снижение скорости, как утверждает автор, происходит за счет вызова метода Notify.
Но насколько может замедлить работу единственныйвызов пустого метода при удалении одного элемента? На время выполнения нескольких машинных инструкции?
Поэтому вряд ли оправдана его рекомендация не использовать TList для создания произвдных классов.
Для упрощения работы с массивом я бы посоветовал автору использовать не структуры данных, а классы. В этом случае не будет стоять проблема приведения типов при удалении объектов.
Испольование классов приведет к незначительному увеличению времени обработки и увеличении используемой памяти, но облегчит разработку и повысит прозрачность кода.
Тын-Дын (2008-09-27 14:16:00) [5]А можно Бакнелла процитировать?
Германн (2008-09-27 03:05:00) [6]
> > Увязли в болоте. :)
> ну так, очень старались...
>
А я и не сомневался. :)
Ну это наша исконно русская черта. :)
Кто-бы блин сомневался :)
sniknik (2008-09-27 02:18:00) [7]> Вот так наконец понятно?
теперь дошло... ты хочешь чтобы я с датасетом повторил те же "телодвижения", что ты делаешь с dom объектом... объект другой, работают с ним по другому (и изначально объяснялся именно правильный вариант работы, но тогда ты это игнорировал), преимущества проявляются именно при сравнении с нормальной работой, поэтому давайте заставим других извращаться также как и ты, и сразу станет понятно насколько твое извращение легче и удобнее.
именно такой подход к работе с xml мне и не нравится, конкретно вот это и этому подобное я и считаю "запарками" в работе.
т.е. неважно, что у меня електроотвёртка и я закручиваю шуруп (и говорю, что это удобнее размахивания молотком), но у тебя то молоток и гвоздь, и ты хочешь посоревноваться именно в забивании (старательно пропуская объяснения как это работать отвёрткой)... спасибо, нафиг.
> Увязли в болоте. :)
ну так, очень старались...
Германн (2008-09-27 01:49:00) [8]Увязли в болоте. :)
Медвежонок Пятачок (2008-09-27 01:28:00) [9]это не структура? нет? а что же ты тогда имел в виду говоря это слово?
with TClientDataSet.Create(nil) do
begin
.....
end;
Вот так наконец понятно?
Или все еще нет?
Если нет, то я пас.
Медвежонок Пятачок (2008-09-27 00:38:00) [10]а я знаю людей, которые много лет подряд открывают serialnum.txt в блокноте и глядя на буквы и цифры вводят вручную в поле регистации длиннющие номера. попеременно переключаясь с блокнота на сетап.
:)
sniknik (2008-09-27 00:35:00) [11]> мда. по ходу дела непонятно не мне, а тебе.
а то. трудно понять человека который разговаривает лозунгами (о крутизне xml), туманными фразами (вроде вот этой на которую отвечаю, вроде сказал что мне что то не понятно, а сказать что непонятно с его точки зрения? это объяснить? я то стараюсь...), и обещаниями о том что там де легко все и просто (это в общем по топику).
давай еще раз о структуре (я же говорил, я стараюсь), что ты понимаеш по этим?
вот давая переведем все в понятный тебе xml, т.е. добавим в показаный код после ADODataSet1.CreateDataSet; ещё ADODataSet1.SaveToFile('D:\xml.xml'); (сохраним как xml, без данных, т.е. "чистую" структуру) получим
<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<s:Schema id="RowsetSchema">
<s:ElementType name="row" content="eltOnly" rs:updatable="true">
<s:AttributeType name="Field1" rs:number="1" rs:nullable="true" rs:write="true">
<s:datatype dt:type="int" dt:maxLength="4" rs:precision="0" rs:fixedlength="true" />
</s:AttributeType>
<s:AttributeType name="Field2" rs:number="2" rs:nullable="true" rs:write="true">
<s:datatype dt:type="int" dt:maxLength="4" rs:precision="0" rs:fixedlength="true" />
</s:AttributeType>
<s:AttributeType name="Field3" rs:number="3" rs:nullable="true" rs:write="true">
<s:datatype dt:type="string" rs:dbtype="str" dt:maxLength="50" rs:precision="0" />
</s:AttributeType>
<s:extends type="rs:rowbase" />
</s:ElementType>
</s:Schema>
<rs:data />
</xml>
это не структура? нет? а что же ты тогда имел в виду говоря это слово?
Игорь Шевченко (2008-09-27 00:30:00) [12]у...а я вот наследников от TList пишу уже много лет...И жив пока, несмотря на грозного Бакнелла. Да и Борланды их, наследников, тоже пишут. Наверно они не читали, почему от него нельзя наследоваться.
Медвежонок Пятачок (2008-09-26 23:55:00) [13]ну ладно уговорил полный код приведу раз непонятно ->
мда. по ходу дела непонятно не мне, а тебе.
sniknik (2008-09-26 23:52:00) [14]> Ну а все таки. Есть пустой рекордсет. Загружать пока не из чего, но структуру создать надо.
вот мы её и создаем, заодно открываем рекордсет командой CreateDataset, сколько повторять, ну ладно уговорил полный код приведу раз непонятно ->
type
TForm1 = class(TForm)
ADODataSet1Field1: TIntegerField;
ADODataSet1Field2: TIntegerField;
ADODataSet1Field3: TStringField;
procedure FormCreate(Sender: TObject);
private
public
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ADODataSet1.CreateDataSet;
end;
все, структура создана (из 3х полей), рекордсет открыт и готов к работе.
> Я в хмл создам ее за меньшим количеством кода.
а я угадаю с семи нот! нашёл чем хвастать... делать больше нечего как только создавать структуры и радоваться этому.
говорили, же про работу с данными. создание структуры только малая ее часть... тем более, что для xml структура продолжает создаваться на протяжении всего вноса данных, т.к. "размазана" по всему объему массива данных, и вносится вместе с ними.
а то что ты собирался показать, это только начало, подготовка т.сказать (по аналогии с рекордсетом это будет аналогом "ложения" его на форму).
Медвежонок Пятачок (2008-09-26 22:58:00) [15]в таком случае больше не надо приводить мне аргументы про "избыточность" и "тяжеловесность" xml.
все что делается мастером, не считаем, это не "телодвижения", это "движение носа".
Ну а все таки. Есть пустой рекордсет. Загружать пока не из чего, но структуру создать надо. Я в хмл создам ее за меньшим количеством кода.
sniknik (2008-09-26 20:18:00) [16]> для CDS это midaslib размером всего около 300к
для ADO это такой же внешний COM сом обьект как и DOM xml, к программе конечно что то добавится, что то же пишется естественно при работе с данными (а типа с xml не так).
> сколько телодвижений надо сделать для создания датасета на пустом месте?
одно. читай sniknik © (26.09.08 17:42) [62]
все что делается мастером, не считаем, это не "телодвижения", это "движение носа".
> + про тип рекордсета и его пакет хотелось бы узнать до кучи.
какая тебе разница на тип? берешь любой из указанных двух. работа ведется практически одинаково. различия есть конечно, но чтобы начинать на них ориентироваться, тем более использовать... это не сразу будет и в большинстве случаев не нужно.
и какая разница на пакет? раз тебе все одно "не тесно". и разговор был не о "тяжести" выраженной в килобайтах, а о необходимости "парится" (не знаю что это у тебя значит, только повторяю за тобой...).
ты, имхо, уводишь "спор" в другое русло, несущественными вопросами. зачем?
все, что нужно чтобы проверить уже сказано. просто повторить по шагам (в обратку проверять работу с xml мне нет нужды, я с ним работал, потому и могу сравнивать).
Поросенок Винни-Пух (2008-09-26 18:32:00) [17]для CDS это midaslib размером всего около 300к
Мне не тесно. Это я на тему изыточности и тяжести, про которую мен рассказывают.
про кдс снова повторяюсь - сколько телодвижений надо сделать для создания датасета на пустом месте?
+ про тип рекордсета и его пакет хотелось бы узнать до кучи.
Правильный$Вася (2008-09-26 18:28:00) [18]
> ко мне при этом прикомпилится
тесно?
для CDS это midaslib размером всего около 300к
зато всегда с собой и никаких заморочек с отсутствием на чужом компе
Поросенок Винни-Пух (2008-09-26 18:20:00) [19]я не про необходимость бд и говорю.
скажи тип своего рекордсета и фамилию dpk который ко мне при этом прикомпилится.
sniknik (2008-09-26 18:18:00) [20]> которой вообще к бд нет необходимости обращаться
сколько раз повторять, что и для этих рекогдсетов нет этой необходимости. данные рекордсеты, это самодостаточные обьекты для работы с данными.
ещё раз - НИКАКИХ БД НЕ ТРЕБУЕТСЯ. но и не помешают если возникнет необходимость в более серьезной обработке данных.