| 
| 
 | Вопрос # 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сця, де призупинилося.
 
 |  Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте. |