Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 5 696

/ вопрос решён /

Здравствуйте!

Возник такой вопрос. У меня есть должна быть по сути таблица (список повторяющихся структур), которая представлена в Приложении к вопросу.
Я сначала думал запихнуть свою структуру в класс-наследник TObjectList, потом все таки остановился на массиве записей.

А хочется решить красиво и грамотно.

Посоветуйте, что лучше применять в таких случаях. Может, hash-таблицы какие или еще чего (желательно со ссылкой на мануал)))

Приложение:
  1. TResultsDataRecord = record
  2. public
  3.  
  4. CompetitorName: string;
  5.  
  6. CutoffTimeSec: Integer;
  7.  
  8. WorkingTimeSec: Integer;
  9.  
  10. PureTimeSec: Integer;
  11.  
  12. PenaltySec: Integer;
  13.  
  14. ResultSec: Integer;
  15.  
  16. ResultNumber: Integer;
  17.  
  18. Place: Integer;
  19. end;
  20.  
  21. TResultsDataList = array of TResultsDataRecord;


Aндрей Вопрос решён, но можно продолжить его обсуждение в мини-форуме

Вопрос задал: 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ндрей

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

bugmenot (статус: 3-ий класс), 26 октября 2011, 19:46 [#2]:

Цитата (Aндрей):

Посоветуйте, что лучше применять в таких случаях.
Принципиальной разницы нет. Но, список будет красивее, т.к. динамический массив рано или поздно придется паковать. min@y™ кстати слоупок и до сих пор сидит в Delphi 7, соответственно не знает о
TObjectList<TResultsDataRecord>
виконання програми розпочинається з того самого мiсця, де призупинилося.

min@y™

min@y™ (статус: Доктор наук), 26 октября 2011, 19:56 [#3]:

Цитата (bugmenot):

min@y™ кстати слоупок и до сих пор сидит в Delphi 7, соответственно не знает о

TObjectList

Ты прав. Пора обзавестись ХЕ. А то отстал от времени. Чо, там реально такой шнягой можно весь мой код (см. выше) заменить?
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
bugmenot

bugmenot (статус: 3-ий класс), 26 октября 2011, 20:39 [#4]:

Цитата (min@y™):

мой код (см. выше)

Там какие-то извращения с матрешками-делегатами, я смутно понимаю зачем это нужно. А вот когда TList или TCollection затачивается под специфический класс - то да, параметризованные типы это делают просто подстановкой нужного типа в угловые скобки. Довольно уродливо, но удобно.

Вон, в тырнете почитай - http://sjrd.developpez.com/delphi/tutoriel/generics/
виконання програми розпочинається з того самого мiсця, де призупинилося.

min@y™

min@y™ (статус: Доктор наук), 26 октября 2011, 20:45 [#5]:

Цитата (bugmenot):

Там какие-то извращения с матрешками-делегатами, я смутно понимаю зачем это нужно. А вот когда TList или TCollection затачивается под специфический класс - то да, параметризованные типы это делают просто подстановкой нужного типа в угловые скобки. Довольно уродливо, но удобно.

Напиши пример, плиз, на основе моего кода, чтобы я смог сравнить на предмет преимуществ и недостатков. Очень, уж, мне интересно. А то, действительно, ощущаю себя динозавром.
Послезавтра пойду напишу заяву на закупку ХЕ. Думаю, что не откажут, т.к. у меня послезавтра ДР. :)
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
min@y™

min@y™ (статус: Доктор наук), 27 октября 2011, 09:35 [#6]:

Цитата (min@y™):

Да, я тоже думал сначала делать через классы, но меня смущает, что контейнер будет хранить около 100 объектов моего типа и таких контейнеров будет где-то 40. Не многовато ли для памяти(я в этом не разбираюсь)?

Ну, на пару % будет побольше, чем в случае record'ов вместо классов. Зато удобнее в 100500 раз.

Поверь, браза, это всё цветочки. Я писал программу управления устройством прозвонки кабелей и проводного монтажа. Так вот, каждый контакт устройства, описывался отдельным объектом (в каждом разъёме 70 контактов), каждый разъём - тоже объект (в каждом устройстве прозвонки 15 разъёмов), а на интерфейсе может висеть до 31 устройства параллельно. Однако, работает всё реактивно. Могу дать посмотреть тебе этот модуль посмотреть.

Кстати, лет 5 назад я делал прогу для таксопарка (учёт времени/выручки водителей) по такому же принципу. Смена для одного водилы - объект, данные водилы (позывные, номер, ФИО, марка машины и список отработанных смен) - тоже объект. Таблица - объект, содержащий список водил (больше 200 человек) и прочую лабуду, включая методы отрисовки на экране и вывод на принтер, сохранение/загрузку и т.д. Всё, опять же, работает без проблем.

Так шта не парься.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
Aндрей

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

DNK (статус: Студент), 27 октября 2011, 12:53 [#8]:

Aндрей: С какой версии дельфы в классе можно объявлять константы? Смысл private default property Items?
"Digital Networked Knight"
bugmenot

bugmenot (статус: 3-ий класс), 29 октября 2011, 09:46 [#9]:

Цитата (min@y™):

Напиши пример, плиз

Моя ссылка не понравилась?
виконання програми розпочинається з того самого мiсця, де призупинилося.

bugmenot

bugmenot (статус: 3-ий класс), 29 октября 2011, 09:48 [#10]:

Цитата (DNK):

Смысл private default property Items?

Не, настоящая жесть была бы если было бы strict private =)
виконання програми розпочинається з того самого мiсця, де призупинилося.

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 февраля 2025, 11:27
Выполнено за 0.05 сек.