Форум: "Начинающим";
Текущий архив: 2007.05.20;
Скачать: [xml.tar.bz2];
ВнизКлассы на базе TList... Найти похожие ветки
← →
Knight © (2007-04-27 14:20) [0]Сколько раз хотел разобраться с этим вопросом, но всё время что-то отвлекало... но надоело, хочу таки разобраться! Мож поможите? :)
Допустим есть какой-то типTMyItem=record
Str1:String;
...
end;
Надо загнать эти итемсы в лист так чтобы обрачаться с нимMyList[i].Str1
а неPMyItem(MyList[i])^.Str1
Мож кто накидает скелет класса?
TMyList=class(TList)
end;
← →
clickmaker © (2007-04-27 14:22) [1]таких скелетов целый склад в Classes.pas VCL
function Get(Index: Integer): IInterface;
procedure Put(Index: Integer; const Item: IInterface);
property Items[Index: Integer]: IInterface read Get write Put; default;
← →
Сергей М. © (2007-04-27 14:30) [2]
> Допустим есть какой-то тип
При условии "какой-то" (а не заранее определенный) готового решения нет и быть не может, если это только не диспинтерфейс.
← →
Knight © (2007-04-27 14:36) [3]> [2] Сергей М. © (27.04.07 14:30)
"какой-то" для примера.. а так будет вполне определённый для конкретной задачи.
← →
Knight © (2007-04-27 14:45) [4]> [1] clickmaker © (27.04.07 14:22)
> таких скелетов целый склад в Classes.pas VCL
Вот там как-паз окромя самого TList и нет ничего... а без интерфейсов никак?
← →
default © (2007-04-27 14:57) [5]Knight © (27.04.07 14:45) [4]
ну ты можешь внутри класса своей специализированной коллекции использовать тот же TList, а в интерфейс своего класса добавить методы типа Add(item: TYourItemType); Remove(item: TYourItemType)....
и будет типа
....
Private List: TList;
...
типами элементов коллекции я тут считаю записи(как у тебя в сабже)
procedure TYourCollection.Add(item: TYourItemType);
begin
List.Add(@item)
end;
function TYourCollection.Contains(item: TYourItemType): Boolean;
var
i: Integer;
begin
for i := 0 to List.Count-1 do
if PYourItemType(List(i))^ = item then begin
Result := True;
Exit;
end;
Result := False;
end;
end;
← →
default © (2007-04-27 15:13) [6]блин не так
procedure TYourCollection.Add(item: TYourItemType);
begin
List.Add(@item)
end;
тут ведь в методе будет копия записи переданной методу как параметр
можешь использовать вместо записи класс, так будет проще, ибо класс это ссылка
или как-то подругому, но принцип главное ты понял надеюсь, детали сам продумай
← →
clickmaker © (2007-04-27 15:14) [7]
> [4] Knight © (27.04.07 14:45)
я просто тупо выдрал пример из classes.pas. Хоть интерфейс, хоть структура - суть одна.
← →
clickmaker © (2007-04-27 15:31) [8]кстати, есть еще замечательный класс TCollection, от которого можно наследоваться.
К примеруTMyItem= class(TCollectionItem)
private
FStr1:String;
public
property Str1: string read FStr1 write FStr1;
end;
TMyItems = class(TCollection)
private
function GetItem(Index: integer): TMyItem;
procedure SetItem(Index: integer; Value: TMyItem);
public
constructor Create();
function Add: TMyItem;
property Items[Index: integer]: TMyItem read GetItem write SetItem; default;
end;
constructor TMyItems .Create();
begin
inherited Create(TMyItem);
end;
function TMyItems.Add: TMyItem;
begin
Result:=TMyItem(inherited Add);
end;
function TMyItems.GetItem(Index: integer): TMyItem;
begin
Result:=TMyItem(inherited GetItem(Index));
end;
procedure TMyItems.SetItem(Index: integer; Value: TMyItem);
begin
inherited SetItem(Index, Value);
end;
← →
default © (2007-04-27 15:38) [9]тот же принцип и классы используют в качестве типов элементов как я и рекомандовал(а не записи)
вообще, Knight, если ты таких элементарных вещей не понимаешь как же ты собираешься проектировать более-менее серьёзные программы?правда если программирование только хобии - то ещё можно жить, а так это полная труба
← →
Knight © (2007-04-27 15:48) [10]> [9] default © (27.04.07 15:38)
Пока хобби... и такие проблемы до сих пор решал динамическими массивами и коллекциями. Но разобраться таки охота %)
Спасибо всем, дальше порою сам :)
← →
default © (2007-04-27 16:01) [11]Knight © (27.04.07 15:48) [10]
очень советую читать литературу по проектирования программного обеспечения!
есть отличная книга "Совершенный код" Макконнелла(это не совсем по проектированию)
← →
default © (2007-04-27 16:03) [12]Knight © (27.04.07 15:48) [10]
ну коллекциями это нормальное решение!(особенно в отсутствии вещей типа генериков)
← →
Ega23 © (2007-04-27 16:13) [13]Кстати о пцыцах.
А кто и как использует рекорды? Ну, кроме типизированных файлов, структур пакетов для TCP и того, что VCL\WinAPI предлагает (типа TPoint или TTypeInfo)?
Просто заметил за собой, что года 4 назад практически полностью от них отказался. Там, где требуется - перешёл на классы. Их и хранить в TObjectList удобнее, и "домиков" этих треклятых не надо...
← →
Knight © (2007-04-27 16:18) [14]> [13] Ega23 © (27.04.07 16:13)
Я в них обычно всякие свойства храню.. типа настроек проги.
← →
Knight © (2007-04-27 17:04) [15]> [12] default © (27.04.07 16:03)
Коллекции всё-же больше для визуальных вещей... а у меня больше различные структуры, поэтому чаще динамические массивы с несколькими функциями их обслуживающими.
← →
clickmaker © (2007-04-27 17:08) [16]
> [15] Knight © (27.04.07 17:04)
больше для визуальных? это почему?
вот скажем есть у тебя массив, в который ты кладешь некие элементы. Количество данных у тебя неизвестно заранее.
Как ты будешь наращивать массив?
← →
Игорь Шевченко © (2007-04-27 17:08) [17]
> А кто и как использует рекорды?
Хороший вопрос. Аналогичный вопросу кто и как использует Integer, string и остальные типы :)
Используются по мере необходимости, буде таковая возникнет.
← →
Ega23 © (2007-04-27 17:11) [18]
> Используются по мере необходимости, буде таковая возникнет.
Так вот мне интересно, когда такая необходимость возникает?
← →
stakan © (2007-04-27 18:52) [19]
>
>
> Так вот мне интересно, когда такая необходимость возникает?
>
Как правило при необходимости связать какие либо разнородные данные с каким либо объектом (классический пример TTreeNode.Data, содержащее ссылку на запись с разнородными данными)
← →
Knight © (2007-04-27 19:16) [20]> [16] clickmaker © (27.04.07 17:08)
> больше для визуальных? это почему?
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=215
← →
stakan © (2007-04-27 19:26) [21]
> и "домиков" этих треклятых не надо...
Кстати, без домиков тоже работает:PRec = ^TRec;
TRec = record
I: Integer;
S: String;
end;
...
procedure TForm2.Button1Click(Sender: TObject);
var
L: TList;
R: PRec;
begin
New(R);
R.I := 1;
R.S := "123";
L := TList.Create;
try
L.Add(R);
Edit1.Text := PRec(L[0]).S;
Dispose(R);
finally
L.Free;
end;
end;
← →
MsGuns © (2007-04-27 22:07) [22]>Ega23 © (27.04.07 17:11) [18]
>Так вот мне интересно, когда такая необходимость возникает?
Постоянно. Хранить сложные объекты в массиве указателей геморнее, чем в списке. Кроме того, списки "разрешают" хранить указатели на объекты разных типов (классов).
Списки удобны также при динамическом контролировании некоторго множества объектов определенного класса, заранее не известного, и т.д.
← →
clickmaker © (2007-04-28 09:35) [23]
> [20] Knight © (27.04.07 19:16)
ну поскольку в самой коллекции ничего сугубо визуального нет, то кто мешает ее использовать и для невизуальных задач?
а можно и List заточить - дело вкуса
← →
Ega23 © (2007-04-28 09:52) [24]
>
> Постоянно. Хранить сложные объекты в массиве указателей
> геморнее, чем в списке.
Но-но!!! Где это я против списка выступал? Есть прекрасные TObjectList и TInterfaceList, которые я постоянно использую.
Речь шла о TList и class vs record
← →
Ega23 © (2007-04-28 09:53) [25]
> Как правило при необходимости связать какие либо разнородные
> данные с каким либо объектом (классический пример TTreeNode.
> Data, содержащее ссылку на запись с разнородными данными)
Пихаем туда указатель на объект с разнородными данными, в чём проблема?
← →
stakan © (2007-04-28 10:09) [26]
> Пихаем туда указатель на объект с разнородными данными,
> в чём проблема?
Если вспомнить классическое определение (своими словами), обьект - это совокупность данных и методов для работы с этими данными.
Так вот, если методов нет и не надо, то использовать объекты - это имхо стрелять из пушки по воробьям.
← →
Ega23 © (2007-04-28 10:17) [27]
> Так вот, если методов нет и не надо, то использовать объекты
> - это имхо стрелять из пушки по воробьям.
>
Методы всегда есть. В неявном виде.
← →
stakan © (2007-04-28 10:23) [28]
> Методы всегда есть. В неявном виде.
Имелось в виду специфические для данного объекта (в явном виде :) )
← →
Ega23 © (2007-04-28 10:25) [29]
> Имелось в виду специфические для данного объекта (в явном
> виде :) )
>
Если ты понишь, то доступ к полям объекта нпрямую - не рекомендуется. С рекордом же - извините...
← →
MsGuns © (2007-04-28 11:48) [30]Вот ситуация:
имеется приложение, управляющее потоками обмена данными с сервером (что-то типа сервера приложений, но сильно упрощенный). Все потоки делятся на 4 группы: незапущенные (в смысле на SQL сервере), активные, завершенные нормально и прерванные - каждая группа визуализируется отдельно (например, в стрингридах - но это не важно).
В процессе работы потоки постоянно перемещаются из одной группы в другую, стартуют новые и т.д. и все это отображается в интерфейсе.
Причем в трингридах пользователь может информацию сжимать, удаляя "старые".
И ты предлагаешь вместо списков дескрипторов (объектов-записей) потоков (в которых помимо указателя на собственно поток хранится масса всякой фигни о потоке служебного характера), прекрасно реализуемых с помощью "отстойного" TList, выдумывать еще какие-то классы, в которых будет всего-то два метода "добавить" и "удалить" ?
Причем одинаковых для всех "классов" дескрипторов ???
← →
clickmaker © (2007-04-28 12:17) [31]
> прекрасно реализуемых с помощью "отстойного" TList, выдумывать
> еще какие-то классы, в которых будет всего-то два метода
> "добавить" и "удалить" ?
не все любят бесконечные тайпкасты TMySuperClass(List[i])
← →
Игорь Шевченко © (2007-04-28 12:18) [32]
> Если ты понишь, то доступ к полям объекта нпрямую - не рекомендуется.
Почему ?
← →
Ega23 © (2007-04-28 12:32) [33]
> Почему ?
Ну во всех хрестоматийных книжках я видел, что с полями надо через Set и Get работать. В принципе, я тоже это не всегда использую, но это уже на усмотрение разработчика...
← →
Ega23 © (2007-04-28 12:34) [34]
> не все любят бесконечные тайпкасты TMySuperClass(List[i])
+1.
← →
Игорь Шевченко © (2007-04-28 12:44) [35]Ega23 © (28.04.07 12:32) [33]
Ну вот и объясни мне, как прочитавший хрестоматийные книжки,
какая разница в двух случаях:
type
TFoo = class
public
Bar: string;
end;
и
TFoo = class
private
FBar: string;
function GetBar: string;
procedure SetBar (const Value: string);
public
property Bar: string read GetBar write Setbar;
end;
function TFoo.GetBar: string;
begin
Result := FBar;
end;
procedure TFoo.SetBar (const Value: string);
begin
FBar := Value;
end;
кроме распухания кода до невозможности.
← →
Ega23 © (2007-04-28 13:18) [36]
> кроме распухания кода до невозможности.
В таком случае - никакой разницы.
А вот если TFoo.Bar должна иметь ограничения (длина строки, или, например, неотрицательные значения, если integer, или ещё что-нибудь) - то очень даже.
Я может не совсем точно выразился. Имел ввиду, что доступ к полям должен через property-прокладку идти.
← →
vovnuke © (2007-04-28 13:32) [37]> [35] Игорь Шевченко © (28.04.07 12:44)
Отличие в инкапсуляции.
← →
Игорь Шевченко © (2007-04-28 13:45) [38]vovnuke © (28.04.07 13:32) [37]
Ну да. С точки зрения вызывающего кода - особенно видны различия в инкапсуляции. Ему (вызывающему коду) в данном случае пофиг, какая там инкапсуляция за одним лишь исключением - во втором случае Bar нельзя использовать как var-переменную. И вся инкапсуляция.
Ega23 © (28.04.07 13:18) [36]
> А вот если TFoo.Bar должна иметь ограничения (длина строки,
> или, например, неотрицательные значения, если integer,
> или ещё что-нибудь) - то очень даже
И что метод Set должен делать в случае ограничений ?
Exception возбуждать ?
То есть, вызывающий код должен иметь еще и обвязку вида
try
FooInstance.Bar := some_value;
except
on E: Exception do
ShowMessage ("Shit happens: "+E.Message);
end;
А как насчет разобраться в таком коде без стакана ? :)
> Я может не совсем точно выразился. Имел ввиду, что доступ
> к полям должен через property-прокладку идти.
То есть, надо переписать как
TFoo = class
private
FBar: string;
public
property Bar: string read FBar write FBar;
end;
?
И в чем здесь разница для вызывающего кода (за исключением var-переменных) ?
← →
Ega23 © (2007-04-28 13:49) [39]>То есть, вызывающий код должен иметь еще и обвязку вида
try
FooInstance.Bar := some_value;
except
on E: Exception do
ShowMessage ("Shit happens: "+E.Message);
end;
А это уже зависит от ситуации. Может exception, а может - значение по-умолчанию присваивать.
← →
Игорь Шевченко © (2007-04-28 13:54) [40]Ega23 © (28.04.07 13:49) [39]
> может - значение по-умолчанию присваивать.
Ага. А вызывающий код потом будет долго недоумевать - как же так, оно присвоило одно значение, а присвоилось совсем другое.
Я к чему веду речь - яйцеголовые массу книжек написали, если всем их советам следовать безоговорочно, можно никогда не написать ни одной программы, потому как с точки зрения какого-нибудь из теоретиков обязательно какой-то изъян в коде найдется.
Проще надо быть, как Эрик Реймонд советует.
← →
vovnuke © (2007-04-28 14:08) [41]> [38] Игорь Шевченко © (28.04.07 13:45)
Вызывающему коду как раз и не следует видеть разницу в релизации объекта, для него он всего лишь структура отвечающая за выолнение определенных обязательств, и изменение в работе этой структуры не должны сказываться на работе клиента. А при изменении требований к ПО (а требования к ПО меняются всегда), придется поправить только реализацию механизма чтения/записи свойтсва, а не рыскать по коду и искать места которые могут сломаться или отлавливать ошибки.
Или этого мало?
← →
Игорь Шевченко © (2007-04-28 14:33) [42]vovnuke © (28.04.07 14:08) [41]
Требвания меняются, никто не спорит. Но вот что странно - за много лет программирования я лично не часто сталкивался с необходимостью менять именно реализацию механизма чтения/записи свойства так, чтобы не затрагивать вызывающий код. Гораздо чаще вызывающий код тоже затрагивался и довольно значительно. Вот такая вот практика.
Можно считать, что мне не повезло, раз не сталкивался, но за опять же много лет программирования я пришел к одной простой истине - чем меньше в коде строчек, тем он лучше, разумеется, при условии, что код функционален и понятен визуально, без привлечение дополнительных средств, в том числе IDE
← →
ANB © (2007-04-28 15:03) [43]
> Можно считать, что мне не повезло, раз не сталкивался, но
> за опять же много лет программирования я пришел к одной
> простой истине - чем меньше в коде строчек, тем он лучше,
> разумеется, при условии, что код функционален и понятен
> визуально, без привлечение дополнительных средств, в том
> числе IDE
И я пришел к тому же выводу. И еще к одному - не завязываться на модные течения (типа ООП). Цель - получить компактный и понятный код. Если ООП этому помогает - хорошо. Если мешает - лучше написать функцию.
← →
vovnuke © (2007-04-28 16:01) [44]> [42] Игорь Шевченко © (28.04.07 14:33)
По первой части вашего поста: я за вас от души рад, честно, мне повезло не так (конечно в этом и мои ошибки на стадии проектирования).
По вторй части: присутствуют условия, кот. довольно субъективны.
> [43] ANB © (28.04.07 15:03)
По большому счету, согласен.
← →
default © (2007-04-28 19:20) [45]Игорь Шевченко
[35]
ситуации могут быть разные, отдельно взятый пример описывает лишь отдельно взятую ситуацию, это не повод для обобщений
а так рекомендуют по очень простой причине - когда всё делаешь через get/set ты никогда не проиграешь(в худшем случае просто будешь иметь никому не мешающую избыточность), а вот если этого правила иногда придерживаться, а иногда нет и делать это не очень дальновидно, то можно получить проблем, которых совсем не ждёшь, зачем идти на риск?впрочем, вольному воля
Страницы: 1 2 вся ветка
Форум: "Начинающим";
Текущий архив: 2007.05.20;
Скачать: [xml.tar.bz2];
Память: 0.58 MB
Время: 0.049 c