Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.05.20;
Скачать: CL | DM;

Вниз

Классы на базе 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;
Скачать: CL | DM;

Наверх




Память: 0.61 MB
Время: 0.069 c
2-1177419557
bagos
2007-04-24 16:59
2007.05.20
закраска ячеек в гриде


5-1153742858
Нулевой
2006-07-24 16:07
2007.05.20
Как добавить свойства компонента в Object Inspector?


1-1173421896
zap8
2007-03-09 09:31
2007.05.20
Как осуществить DragDrop ссылки из Internet Explorer


1-1174898170
Zvitchenzug
2007-03-26 12:36
2007.05.20
Как "вытянуть" HTML-страницы из всех открытых окон IE


15-1176697078
X9
2007-04-16 08:17
2007.05.20
Работа на Электроника МК 61