|
Вопрос # 5 696/ вопрос решён / |
|
Здравствуйте!
Возник такой вопрос. У меня есть должна быть по сути таблица (список повторяющихся структур), которая представлена в Приложении к вопросу.
Я сначала думал запихнуть свою структуру в класс-наследник TObjectList, потом все таки остановился на массиве записей.
А хочется решить красиво и грамотно.
Посоветуйте, что лучше применять в таких случаях. Может, hash-таблицы какие или еще чего (желательно со ссылкой на мануал)))
Приложение: Переключить в обычный режим- TResultsDataRecord = record
- public
-
- CompetitorName: string;
-
- CutoffTimeSec: Integer;
-
- WorkingTimeSec: Integer;
-
- PureTimeSec: Integer;
-
- PenaltySec: Integer;
-
- ResultSec: Integer;
-
- ResultNumber: Integer;
-
- Place: Integer;
- end;
-
- TResultsDataList = array of TResultsDataRecord;
 |
Вопрос задал: Aндрей (статус: 1-ый класс)
Вопрос отправлен: 26 октября 2011, 17:47
Состояние вопроса: решён, ответов: 1.
|
Ответ #1. Отвечает эксперт: min@y™
Советую сделать всё через классы. ИМХО, так гораздо удобнее. Я всегда так делаю.
Вот учебный (абстрактный) пример реализации:
unit MyItems;
interface
uses
Classes, Contnrs;
type
// Для примера, пусть это класс, экземпляры которого надо хранить в списке
TMyItem = class
private
FValue: Integer; // Пусть это данные, к которым надо иметь доступ
FOnChange: TNotifyEvent; // Событие при зименении FValue
procedure SetValue(const ANew: Integer);
public
constructor Create;
property Value: Integer read FValue write SetValue;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
TMyContainerChangeItem = procedure (Sender: TObject; Item: TMyItem) of object; // Тип события
// А вот это класс-контейнер
TMyContainer = class
private
FItems: TObjectList; // Список для хранения
FOnChangeItem: TMyContainerChangeItem; // Событие при изменении какого-либо из хранящихся объектов
// Функции доступа к элементам списка
function GetCount: Integer;
function GetItem(const Index: Integer): TMyItem;
procedure OnChangeItemHandler(Sender: TObject); // Обработчик события от хранящихся объектов
public
constructor Create;
destructor Destroy; override;
function Add(const Value: Integer): TMyItem; // Добавление
procedure Delete(const Index: Integer); overload; // Удаление по индексу
procedure Delete(AItem: TMyItem); overload; // Удаление по ссылке (указателю на экземпляр)
property Count: Integer read GetCount; // Количество в списке
property Items[const Index: Integer]: TMyItem read GetItem; // Доступ по индексу
property OnChangeItem: TMyContainerChangeItem read FOnChangeItem write FOnChangeItem; // событие
end;
implementation
{ TMyItem }
constructor TMyItem.Create;
begin
FValue:= 0; // По умолчанию
end;
procedure TMyItem.SetValue(const ANew: Integer);
begin
if FValue <> ANew
then begin
FValue:= ANew;
// Генерирование события
if Assigned(FOnChange)
then FOnChange(Self);
end;
end;
{ TMyContainer }
function TMyContainer.Add(const Value: Integer): TMyItem;
begin
Result:= TMyItem.Create();
Result.Value:= Value;
Result.OnChange:= OnChangeItemHandler;
FItems.Add(Result);
end;
procedure TMyContainer.Delete(const Index: Integer);
begin
if (Index > -1) and (Index < Self.Count)
then FItems.Delete(Index);
// else ( Здесь можно ругнуться сообщением об ошибке )
end;
procedure TMyContainer.Delete(AItem: TMyItem);
var
Index: Integer;
begin
Index:= FItems.IndexOf(AItem);
if Index <> -1
then FItems.Delete(Index);
end;
constructor TMyContainer.Create;
begin
FItems:= TObjectList.Create(True);
end;
destructor TMyContainer.Destroy;
begin
// Если FItems - это список потоков, то их здесь можно (нужно) прервать
FItems.Free();
inherited;
end;
function TMyContainer.GetCount: Integer;
begin
Result:= FItems.Count;
end;
function TMyContainer.GetItem(const Index: Integer): TMyItem;
begin
if (Index > -1) and (Index < Self.Count)
then Result:= TMyItem(FItems[Index])
else Result:= nil;
end;
procedure TMyContainer.OnChangeItemHandler(Sender: TObject);
begin
if Assigned(FOnChangeItem)
then FOnChangeItem(Self, TMyItem(Sender));
end;
end.
 |
Ответ отправил: min@y™ (статус: Доктор наук)
Время отправки: 26 октября 2011, 17:59
Оценка за ответ: 5
Комментарий к оценке: Да, я тоже думал сначала делать через классы, но меня смущает, что контейнер будет хранить около 100 объектов моего типа и таких контейнеров будет где-то 40. Не многовато ли для памяти(я в этом не разбираюсь)?
|
Мини-форум вопроса
Всего сообщений: 10; последнее сообщение — 29 октября 2011, 09:48; участников в обсуждении: 4.
|
Aндрей (статус: 1-ый класс), 26 октября 2011, 17:49 [#1]:
привел к читабельному виду
TResultsDataRecord = record
public
//Название команды/участника
CompetitorName: string;
//Отсечка(сек)
CutoffTimeSec: Integer;
//Время работы(сек)
WorkingTimeSec: Integer;
//Чистое время(сек)
PureTimeSec: Integer;
//Сумма штрафов(сек)
PenaltySec: Integer;
//Результат(сек)
ResultSec: Integer;
//Результат(в баллах)
ResultNumber: Integer;
//Место
Place: Integer;
end;
TResultsDataList = array of TResultsDataRecord;
|
|
bugmenot (статус: 3-ий класс), 26 октября 2011, 19:46 [#2]:
Цитата (Aндрей):
Посоветуйте, что лучше применять в таких случаях. Принципиальной разницы нет. Но, список будет красивее, т.к. динамический массив рано или поздно придется паковать. min@y™ кстати слоупок и до сих пор сидит в Delphi 7, соответственно не знает о TObjectList<TResultsDataRecord>
виконання програми розпочинається з того самого мiсця, де призупинилося.
|
|
min@y™ (статус: Доктор наук), 26 октября 2011, 19:56 [#3]:
Цитата (bugmenot):
min@y™ кстати слоупок и до сих пор сидит в Delphi 7, соответственно не знает о
TObjectList
Ты прав. Пора обзавестись ХЕ. А то отстал от времени. Чо, там реально такой шнягой можно весь мой код (см. выше) заменить?
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
bugmenot (статус: 3-ий класс), 26 октября 2011, 20:39 [#4]:
Цитата (min@y™):
мой код (см. выше)
Там какие-то извращения с матрешками-делегатами, я смутно понимаю зачем это нужно. А вот когда TList или TCollection затачивается под специфический класс - то да, параметризованные типы это делают просто подстановкой нужного типа в угловые скобки. Довольно уродливо, но удобно.
Вон, в тырнете почитай - http://sjrd.developpez.com/delphi/tutoriel/generics/
виконання програми розпочинається з того самого мiсця, де призупинилося.
|
|
min@y™ (статус: Доктор наук), 26 октября 2011, 20:45 [#5]:
Цитата (bugmenot):
Там какие-то извращения с матрешками-делегатами, я смутно понимаю зачем это нужно. А вот когда TList или TCollection затачивается под специфический класс - то да, параметризованные типы это делают просто подстановкой нужного типа в угловые скобки. Довольно уродливо, но удобно.
Напиши пример, плиз, на основе моего кода, чтобы я смог сравнить на предмет преимуществ и недостатков. Очень, уж, мне интересно. А то, действительно, ощущаю себя динозавром.
Послезавтра пойду напишу заяву на закупку ХЕ. Думаю, что не откажут, т.к. у меня послезавтра ДР.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
min@y™ (статус: Доктор наук), 27 октября 2011, 09:35 [#6]:
Цитата (min@y™):
Да, я тоже думал сначала делать через классы, но меня смущает, что контейнер будет хранить около 100 объектов моего типа и таких контейнеров будет где-то 40. Не многовато ли для памяти(я в этом не разбираюсь)?
Ну, на пару % будет побольше, чем в случае record'ов вместо классов. Зато удобнее в 100500 раз.
Поверь, браза, это всё цветочки. Я писал программу управления устройством прозвонки кабелей и проводного монтажа. Так вот, каждый контакт устройства, описывался отдельным объектом (в каждом разъёме 70 контактов), каждый разъём - тоже объект (в каждом устройстве прозвонки 15 разъёмов), а на интерфейсе может висеть до 31 устройства параллельно. Однако, работает всё реактивно. Могу дать посмотреть тебе этот модуль посмотреть.
Кстати, лет 5 назад я делал прогу для таксопарка (учёт времени/выручки водителей) по такому же принципу. Смена для одного водилы - объект, данные водилы (позывные, номер, ФИО, марка машины и список отработанных смен) - тоже объект. Таблица - объект, содержащий список водил (больше 200 человек) и прочую лабуду, включая методы отрисовки на экране и вывод на принтер, сохранение/загрузку и т.д. Всё, опять же, работает без проблем.
Так шта не парься.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
Aндрей (статус: 1-ый класс), 27 октября 2011, 10:44 [#7]:
Спасибо, переделал вот так
TResultData = class
public
//Название команды/участника
CompetitorName: string;
//Отсечка(сек)
CutoffTimeSec: Integer;
//Общее Время работы(сек)
TimeSec: Integer;
//Чистое время(сек)
WorkingTimeSec: Integer;
//Сумма штрафов(сек)
PenaltySec: Integer;
//Результат(сек)
ResultSec: Integer;
//Результат(в баллах)
ResultNumber: Integer;
//Место
Place: Integer;
end;
TResultDataList = class(TObjectList)
public
constructor Create;
function Add (AResult: TResultData): Integer;
function Remove (AResult: TResultData): Integer;
function IndexOf(AResult: TResultData): Integer; overload;
function IndexOf(ACompetitorName: string): Integer; overload;
function First : TResultData;
function Last : TResultData;
function IsTeamExists(TeamName: string): Boolean;
private
function GetItem(Index: Integer): TResultData;
procedure SetItem(Index: Integer; AResult: TResultData);
property Items[Index: Integer]: TResultData read GetItem write SetItem; default;
public
const RESULT_NOT_EXIST = -4;
end;
|
27 октября 2011, 11:51: Статус вопроса изменён на решённый (изменил автор вопроса — Aндрей)
|
DNK (статус: Студент), 27 октября 2011, 12:53 [#8]:
Aндрей: С какой версии дельфы в классе можно объявлять константы? Смысл private default property Items?
"Digital Networked Knight"
|
|
bugmenot (статус: 3-ий класс), 29 октября 2011, 09:46 [#9]:
Цитата (min@y™):
Напиши пример, плиз
Моя ссылка не понравилась?
виконання програми розпочинається з того самого мiсця, де призупинилося.
|
|
bugmenot (статус: 3-ий класс), 29 октября 2011, 09:48 [#10]:
Цитата (DNK):
Смысл private default property Items?
Не, настоящая жесть была бы если было бы strict private =)
виконання програми розпочинається з того самого мiсця, де призупинилося.
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|