.
Тестируем созданный класс TPASSMomentum (Delphi 7: отладчик, create, private, protected, breakpoint)
Автор megabax   
10.08.2009 г.
New Page 1

Тестируем созданный класс TPASSMomentum (Delphi 7: отладчик, create, private, protected, breakpoint, точка останова)

Все статьи по данной теме.

Сегодня мы приступим к тестированию созданного нами класса индикатора. Для этого создадим тестовый пример. Сначала разместим на форме меню mmMenu и сделаем в нем всего лишь один пункт: "Файл"-->"Загрузить" (itLoad). Затем поместим диалог выбора файла: odOpenDialog, метки lbDateTime и lbResult, кнопкочку "Вычислить" (btnCalk), два компонента SpinEdit (seCandle и seDT), их можно найти на закладке Samples. Вот так примерно будет выглядеть наша форма*:

Delphi 7: отладчик, create, private, protected, momentum,биржевой  индикатор

В фильтре диалога выбора файлов установим фильтр текстовые файлы (с расширенеим *.txt)

Добавим в класс основной формы окна переменные FPriceSource и FIndicator (добавленное выделено красным шрифтом):

  TfrmMomentum = class(TForm)
    odOpenDialog: TOpenDialog;
    mmMenu: TMainMenu;
    itFile: TMenuItem;
    itLoad: TMenuItem;
    lbResult: TLabel;
    btnCalk: TButton;
    seDT: TSpinEdit;
    lbDateTime: TLabel;
    seCandle: TSpinEdit;
    procedure itLoadClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnCalkClick(Sender: TObject);
    procedure seCandleChange(Sender: TObject);
  private
    { Private declarations }
    FPriceSource:TPASSPriceSource;
    FIndicator:TPASSMomentum;
  public
    { Public declarations }
  end;

в обработчике события OnCreate формы нам нужно полям FPriceSource и FIndicator присвоить nil:

procedure TfrmMomentum.FormCreate(Sender: TObject);
begin
   FPriceSource:=nil;
   FIndicator:=nil;
end;

Теперь реализуем процедуру загрузки котировок в обработчике OnClick пункта меню "Загрузить":

procedure TfrmMomentum.itLoadClick(Sender: TObject);
begin
   if odOpenDialog.Execute then
   begin
      if FPriceSource<>nil then FreeAndNil(FPriceSource);
      FPriceSource:=TPASSPriceSource.Create('',false);
      FPriceSource.LoadDataFromTextFile(odOpenDialog.FileName);
   end;
end;

В этой процедуре мы запускаем диалог выбора файла, в случае, если пользователь выбрал файл, уничтожаем объект FPriceSource, если он уже создан, затем вновь создаем его и загружаем выбранный файл. Что бы нам видеть дату свечи, которую мы обрабатываем, сделаем обработчик OnChange объекта seCandle:

procedure TfrmMomentum.seCandleChange(Sender: TObject);
begin
  FPriceSource.CurrentItemIndex:=seCandle.Value;
  lbDateTime.Caption:= DateTimeToStr(FPriceSource.GetDataByFieldName('DateTime'));
end;    

Ну, и наконец, реализуем обработчик нажати яна кнопку "Вычислить"

procedure TfrmMomentum.btnCalkClick(Sender: TObject);
begin
  if FIndicator<>nil then FreeAndNil(FIndicator);
  FIndicator:=TPASSMomentum.Create(seDT.Value,'Close');
  FIndicator.PriceSource:=FPriceSource;
  lbResult.Caption:= intToStr(FIndicator.GetParameterByName('Value'));
end;

Здесь мы уничтожаем объект индикатора, если он у нас уже создан и создаем его заново. Передаем ему в качестве источника котировок FPriceSource, затем вычисляем значение индикатора.

Все, запускаем программу. загружаем индикатор и жмем на кнопку "Вычислить".

Опаньки! У нас вылезло сообщение об ошибке*.

Delphi 7: отладчик, create, private, protected, momentum,биржевой  индикатор

Данная ошибка возникла при попытке выполнить операцию

 FParameters.Add('PriceFieldType',APriceFieldType)*;
 

Delphi 7: отладчик, create, private, protected, momentum,биржевой  индикатор

Давайте при помощи отладчика узнаем, что содержалось в FParameters на момент ошибки. и так, ставим точку останова, просто щелкнув мышкой слева от строки*:

Delphi 7: отладчик, create, private, protected, биржевой  индикатор

Точку останова можно так же поставить (или снять), нажав на клавиатуре клавишу F5, либо через всплывающее меню (по щелчку правой кнопки мыши) "Debuп" --> "Toggle breakpoint"*.

программирование биржевых индикаторов на Delphi

Теперь запустим программу. Когда мы нажмем на кнопочку "Вычислить" у нас выполнения программы прервется в точке останова. что бы посмотреть значения переменных, откроем окно "Watches" через меню "View" --> "Debug Windows" --> "Watches"*:

Delphi 7: отладчик, create, private, protected, momentum,биржевой  индикатор

В это окно добавим переменную FParameters, это можно сделать нажав на клавиатуре клавишу Insert. При этом должно открыться окно добавления переменной*:

Delphi 7: отладчик, create, private, protected, momentum,биржевой  индикатор

Как видим FParameters у нас равно nil*:

Delphi 7: отладчик, create, private, protected, momentum,биржевой  индикатор

Иными словами, данная переменная у нас почему то не инициализировалась, хотя мы вызвали конструктор родительского класса:

inherited Create;

Давайте поставим точку останова выше, как раз на

 inherited Create;
 

Когда программа у остановится, начнем выполнять ее пошагово, нажимая на клавишу F7 на клавиатуре. У нас зайдет в конструктор класса TPASSIndicator, затем в выполниться :

inherited Create

а после него

FParameters:=TPASSParameters.Create

Как видим, у нас FParameters инициализируется. Но, выйдя снова в конструктор класса TPASSMomentum он принимает значение nil.

Оказывается, все дело в особенностях Delphi. Дело в том, что одна и та же переменная, объявленная в разных секция, на самом деле разная. Иными словами, мы получили две локальных переменных. А у нас как раз в классе TPASSIndicator переменная FParameters  объявлена как private, а в классе TPASSMomentum как protected. Мы хотели таким образом добраться до приватной переменной. А не тут то было!

Если бы мы по какой то причине не могли править модуль PASSIndicators (например, не имели бы исходников), то добраться до FParameters  бло бы очень трудно. Таким образом, на примере данной ошибки ясно и понятно показано, в каких случаях нужно объявлять переменные в секции private, и в каких случаях protected. И так, прорезюмирую:

  • Если переменная не должна быть видимой снаружи класса, потому что при записи в нее значения требуется производить какие то действия, то данную переменную следует объявить как private или protected, а для доступа к переменной организовать свойства, к которому подвязать методы для записи в переменную. Смотрите как объявлен класс PASSIndicators:

  TPASSIndicator=Class(TPASSAbstractDataSource)
  private
    FParameters:TPASSParameters; // значения параметров индикатора.
    FPriceSource:TPASSPriceSource; // источник котировок.
    procedure SetPriceSource(APriceSource:TPassPriceSource);
    procedure UpdateParameters; virtual; abstract;
  public
    constructor Create;
    property PriceSource:TPASSPriceSource read FPriceSource write SetPriceSource;
    procedure SetParameterByName(AParameterName:string; AParameterValue:Variant); virtual;
    function GetParameterByName(AParameterName:string):Variant; virtual;
    function GetResultByFieldName(AFieldName:string):double;  virtual; abstract;
    function GetResultByFieldNameAndIndex(FieldName:string; Index:LongInt):double;  virtual; abstract;
    function GetResultByFieldNum(AFieldName:integer):double; virtual; abstract;
    function GetResultByFieldNumAndIndex(FieldName:Integer; Index:LongInt):double; virtual; abstract;
    procedure First; virtual; abstract;
    procedure Last; virtual; abstract;
    function Next:boolean; virtual; abstract;
    function Prev:boolean; virtual; abstract;
    function GetIndicatorName:string; virtual; abstract;
    Destructor Destroy; virtual;
  end;
  • Если необходимо, что бы можно было поиметь доступ к переменной в дочерних классах, которые могу быть объявлены в других модулях (как в нашем случае например), то объявлять данную переменную класса нужно в секции именно protected. Если есть причниа скрыть эту переменную и сделать невидиму в дочерних классах то используем private.

И так мы выяснили, что нам нужно внутренние переменные класса TPASSIndicator объявить как protected. У нас есть исходники мы можем это сделать. Но переписывать модуль PASSIndicators, а заодно и проводить рефреминг кода мы будем на следующем уроке.

 


Скриншоты, помеченные знаком * , являются цитатами и иллюстрациями  в соответствии со ст. 1274 ГК РФ программного продукта "Delphi", авторское право на который принадлежит "Borland Software Corporation".

 

Последнее обновление ( 27.07.2013 г. )