Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 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]


> может - значение по-умолчанию присваивать.


Ага. А вызывающий код потом будет долго недоумевать - как же так, оно присвоило одно значение, а присвоилось совсем другое.

Я к чему веду речь - яйцеголовые массу книжек написали, если всем их советам следовать безоговорочно, можно никогда не написать ни одной программы, потому как с точки зрения какого-нибудь из теоретиков обязательно какой-то изъян в коде найдется.

Проще надо быть, как Эрик Реймонд советует.



Страницы: 1 2 вся ветка

Форум: "Начинающим";
Текущий архив: 2007.05.20;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.05 c
2-1178093914
Perf2k2
2007-05-02 12:18
2007.05.20
ListView: как проверить, выеделена ли пустая строка или нет?


2-1177606141
Malik
2007-04-26 20:49
2007.05.20
Проблема со StatusBar om


2-1177668183
Сергей Ю
2007-04-27 14:03
2007.05.20
Ошибка runtime на строке end. Как отловить?


1-1174494493
VitAngel
2007-03-21 19:28
2007.05.20
Выделение строки в DBGrid


2-1177576431
umbra
2007-04-26 12:33
2007.05.20
что содержит строка после SetLength?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский