Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Конструктор Create


Автор: omickron 25.8.2011, 19:45
Ребят, помогите, пожалуйста, разобраться с пониманием работы конструкторов.

Имеется форма класса TMyForm = class(TForm).
Как создать объект её типа?
Код

Form := TMyForm.Create(Owner);


Тут всё просто.

Я задался мыслью проверить, а не существует ли уже форма такого класса? Т.е. я хочу, чтобы в моём приложении форма класса TMyForm была только в одном экземпляре.

Я сделал глобальную переменную Forms класса-наследника TStringList, в которой храню имена типов форм и ссылки на сами экземпляры форм.
В конструкторе TMyForm я складываю форму в список, в деструкторе - выбрасываю из списка.

Таким образом конструктор формы TMyForm получается таким:
Код

constructor TForm.Create(AOwner: TComponent)
begin
  inherited Create(AOwner);
  Forms.AddObject(ClassName, Self);
end;


В деструктор - вставил удаление объекта из списка.

А теперь нужно в конструктор вставить проверку, не существует ли уже такой формы. Получаем:

Код

constructor TForm.Create(AOwner: TComponent)
begin
  if Forms.IndexOf(ClassName) >= 0 then
    begin
      //Что написать здесь, чтобы вызов Form := TMyForm.Create(Owner); вернул в Form не новый объект, а уже существующий?
    end
  else 
    begin
      inherited Create(AOwner);
      Forms.AddObject(ClassName, Self);
    end;
end;


P.S. В принципе, формы тут только для примера. На деле, у TMyForm ещё куча наследников, поэтому складывать в список имя класса нормально. Там могут быть и TMyDrawForm, и TMySimpleForm, и т.п. И каждая из них должна быть уникальна.
Вместо форм, на самом деле, можно использовать любые объекты, не обязательно визуальные.

Итого, главный вопрос: как в конструкторе проверить что-либо и вместо нового объекта вернуть другой?

Автор: rodnover 25.8.2011, 20:04
Сделать конструктор приватным и использовать классовую функцию. Шаблон называется http://ru.wikipedia.org/wiki/Singleton

Автор: bems 25.8.2011, 21:35
Цитата(rodnover @  25.8.2011,  20:04 Найти цитируемый пост)
Сделать конструктор приватным

толку в этом мало. Просто не вызывать его напрямую.

Автор: omickron 26.8.2011, 09:26
Цитата(rodnover @  25.8.2011,  20:04 Найти цитируемый пост)
Сделать конструктор приватным и использовать классовую функцию.

Ага, понял. Правда, для TForm это не прокатит - там виртуальный конструктор уже описан в public.

Цитата(bems @  25.8.2011,  21:35 Найти цитируемый пост)
толку в этом мало.

Ну почему мало? Если конструктор будет приватным, его вызвать не получится. И для создания объектов придётся использовать или классовую функцию, или фабрику.

Автор: superVad 26.8.2011, 10:55
omickron, а может лучше так спроектировать интерфейс программы, что бы просто нельзя было одну форму 2 раза вызвать?

Автор: bems 26.8.2011, 14:07
Цитата(omickron @  26.8.2011,  09:26 Найти цитируемый пост)
Если конструктор будет приватным, его вызвать не получится.
всегда для любого класса можно вызвать публичный конструктор унаследованный от TObject

Автор: sCreator 27.8.2011, 11:37
Где то так
Код

unit UCustomSingleForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TCustomSingleForm = class(TForm)
  private
    FIsDestroing: Boolean;
    FIsCreating: Boolean;
    function CheckDestroing(): Boolean;
    { Private declarations }
  protected
    property IsDestroing: Boolean read FIsDestroing;
    property IsCreating: Boolean read FIsCreating;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    // constructor CreateNew(AOwner: TComponent; Dummy: Integer  = 0); virtual;
    destructor Destroy; override;

    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
    procedure DestroyForce;
    procedure FreeInstance; override;
    class function NewInstance: TObject; override;
    // class function
  end;

implementation

{ TCustomSingleForm }

procedure TCustomSingleForm.AfterConstruction;
begin
  if IsCreating then
    inherited AfterConstruction();
  FIsCreating := false;
end;

procedure TCustomSingleForm.BeforeDestruction;
begin
  if CheckDestroing then
    inherited BeforeDestruction();
end;

constructor TCustomSingleForm.Create(AOwner: TComponent);
begin
  if IsCreating then
    inherited Create(Application);
end;

destructor TCustomSingleForm.Destroy;
begin
  if IsDestroing then
    inherited Destroy();
end;

procedure TCustomSingleForm.DestroyForce;
begin
  if CheckDestroing() then
    exit;
  FIsDestroing := true;
  Destroy();
end;

procedure TCustomSingleForm.FreeInstance;
begin
  if IsDestroing then
    inherited;
end;

class function TCustomSingleForm.NewInstance: TObject;
var
  i: Integer;
begin
  for i := 0 to Application.ComponentCount - 1 do
    if Application.Components[i].ClassInfo = Self.ClassInfo then
    begin
      Result := Application.Components[i];
      exit;
    end;

  Result := inherited NewInstance();
  TCustomSingleForm(Result).FIsCreating := true;
end;

function TCustomSingleForm.CheckDestroing(): Boolean;
begin
  if (csDestroying in ComponentState) then
    FIsDestroing := true;
  Result := FIsDestroing;
end;

end.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)