Создание одиночного элемента в Delphi, использующем новые функции D2009 и D2010

Так как Вы спросили о других базах данных, вот некоторая информация о Oracle.

Добавление столбца NULL к таблице Oracle является очень быстрой операцией, поскольку оно только обновляет словарь данных. Это содержит монопольную блокировку на таблице в течение очень короткого периода времени. Это будет однако, делать недействительным любые depedant хранимые процедуры, представления, триггеры, и т.д. Они будут перекомпилированы автоматически.

Оттуда при необходимости можно создать индекс с помощью пункта ОНЛАЙН. Снова, только очень короткие блокировки словаря данных. Это считает целую таблицу, ища вещи индексировать, но не блокирует никого при выполнении этого.

, Если необходимо добавить внешний ключ, можно сделать это и заставить Oracle доверять Вам, что данные корректны. Иначе это должно считать целую таблицу и проверить все значения, которые могут быть медленными (создайте свой индекс сначала).

, Если необходимо поместить значение по умолчанию или вычисленное значение в каждую строку нового столбца, необходимо будет выполнить крупное обновление или возможно немного утилиты, которая заполняет новые данные. Это может быть медленно, особенно если строки становятся намного больше и больше не помещаются в их блоки. Блокировка может быть организована во время этого процесса. Так как старый versino Вашего приложения, которое все еще работает, не знает об этом столбце, Вам, возможно, понадобился бы подлый триггер или определить значение по умолчанию.

Оттуда, можно сделать switcharoo на серверах приложений к новой версии кода, и это будет продолжать бежать. Отбросьте свой подлый триггер.

, С другой стороны, можно использовать DBMS_REDEFINITION, который является черным квадратом, разработанным, чтобы сделать этот вид вещи.

Все это - так много беспокойства для тестирования, и т.д. что у нас просто есть начало отключения электричества утра воскресенья каждый раз, когда мы выпускаем основную версию.

10
задан Steve 11 September 2009 в 08:01
поделиться

6 ответов

Этим можно было управлять, переопределив ИСТИННЫЕ методы распределения и освобождения памяти в Delphi, NewInstance и FreeInstance . Конструкторы и деструкторы в Delphi только инициализируются и завершаются соответственно, они не выделяют и не освобождают память, поэтому попытка скрыть конструкторы всегда была немного ошибочной.

т.е. можно было разрешить свободное использование любых и всех конструкторов, пока вы переопределил NewInstance таким образом, что он когда-либо возвращал ссылку только на одно выделение памяти для класса.

Но попытка навязать шаблон использования / поведения в базовом классе - ошибка imho. Не ВСЕ шаблоны являются или требуют определенных классов для инкапсуляции шаблона.

3
ответ дан 3 December 2019 в 14:06
поделиться

Если вам просто нужен простой синглтон, Самый простой способ - использовать конструкторы классов и методы классов, как предлагает plainth. Но дженерики очень полезны, если вам нужны синглтоны с построением по запросу (то есть при первом доступе).

Следующий код взят из одного из моих служебных модулей; в основном он предоставляет общую фабрику синглтонов для Delphi 2009 г.

interface

type
  {$HINTS OFF}
  { TSingletonInstance<> implements lazy creation, which is sometimes useful for avoiding
    expensive initialization operations.
    If you do not require lazy creation and you target only Delphi 2010 onwards, you should
    use class constructors and class destructors instead to implement singletons. }
  TSingletonInstance<T: class, constructor> = record
  private
    FGuard: IInterface;
    FInstance: T;
    function GetInstance: T;
    function CreateInstance: TObject;
  public
    property Instance: T read GetInstance;
  end;
  {$HINTS ON}
  TSingletonFactoryFunction = function: TObject of object;

{ Private symbols (which are in the interface section because of known limitations of generics) }
procedure _AllocateSingletonInstance (InstanceRecord: Pointer; Factory: TSingletonFactoryFunction);

implementation

{ TSingleton }

var
  SingletonCriticalSection: TRTLCriticalSection;

type
  TSingletonGuard = class (TInterfacedObject)
  private
    FSingletonInstance: TObject;
  public
    constructor Create (AInstance: TObject);
    destructor Destroy; override;
  end;

  PUntypedSingletonInstance = ^TUntypedSingletonInstance;
  TUntypedSingletonInstance = record
    FGuard: IInterface;
    FInstance: TObject;
  end;

  // TODO: is a lock required for multiple threads accessing a single interface variable?
procedure _AllocateSingletonInstance (InstanceRecord: Pointer; Factory: TSingletonFactoryFunction);
var
  USI: PUntypedSingletonInstance;
begin
  USI := PUntypedSingletonInstance (InstanceRecord);
  EnterCriticalSection (SingletonCriticalSection);
  if USI.FInstance = nil then
  begin
    USI.FInstance := Factory ();
    USI.FGuard := TSingletonGuard.Create (USI.FInstance);
  end;
  LeaveCriticalSection (SingletonCriticalSection);
end;

constructor TSingletonGuard.Create (AInstance: TObject);
begin
  FSingletonInstance := AInstance;
end;

destructor TSingletonGuard.Destroy;
begin
  FSingletonInstance.Free;
  inherited;
end;

function TSingletonInstance<T>.GetInstance: T;
var
  Factory: TSingletonFactoryFunction;
begin
  if FInstance = nil then
  begin
    Factory := Self.CreateInstance; // TODO: associate QC report
    _AllocateSingletonInstance (@Self, Factory);
  end;
  Result := FInstance;
end;

function TSingletonInstance<T>.CreateInstance: TObject;
begin
  Result := T.Create;
end;

initialization
  InitializeCriticalSection (SingletonCriticalSection);
finalization
  DeleteCriticalSection (SingletonCriticalSection);

Использование следующим образом:

type
  TMySingleton = class
  public
    constructor Create;
    class function Get: TMySingleton; static;
  end;

var
  MySingletonInstance: TSingletonInstance<TMySingleton>;

class function TMySingleton.Get: TMySingleton;
begin
  Result := MySingletonInstance.Instance;
end;
12
ответ дан 3 December 2019 в 14:06
поделиться

В Delphi 2010, безусловно, лучший и безопасный способ - использовать конструкторы классов . См. здесь - особенно прочтите параграф под названием Улучшенная инкапсуляция .

HTH.

8
ответ дан 3 December 2019 в 14:06
поделиться

Я предпочитаю использовать интерфейсы, когда мне нужны синглтоны, и скрывать реализацию интерфейса в разделе реализации.

преимущества

  • Автоматическое уничтожение при завершении программы.
  • Невозможно случайно создать TMySingleton.

недостатки

  • Кто-то может решить реализовать IMySingleton самостоятельно.

Примечание: я считаю, что использование синглтонов должно быть сведено к абсолютному минимуму. В общем, синглтоны - это не более чем прославленные глобальные переменные. Если и когда вы начнете модульное тестирование своего кода, они станут неприятностью.

unit uSingleton;

interface

type
  ISingleton = interface
    ['{8A449E4B-DEF9-400E-9C21-93DFA2D5F662}']
  end;

function Singleton: ISingleton;

implementation

uses
  SyncObjs;

type
  TSingleton = class(TInterfacedObject, ISingleton);

var
  Lock: TCriticalSection;

function Singleton: ISingleton;
const
  _singleton: ISingleton = nil;
begin
  if not Assigned(_singleton) then
  begin
    Lock.Acquire;
    try
      if not Assigned(_singleton) then
        _singleton := TSingleton.Create();
    finally
      Lock.Release;
    end;
  end;
  Result := _singleton;
end;

initialization
  Lock := TCriticalSection.Create;
finalization
  Lock.Free;

end.
7
ответ дан 3 December 2019 в 14:06
поделиться

Для синглтона вы можете переопределить метод NewInstance и использовать переменную класса.

3
ответ дан 3 December 2019 в 14:06
поделиться

Я предпочитаю создавать одноэлементный класс с помощью генератора кода. Проблема с generic заключается в том, что весь код создается в памяти, а не в исходном файле. Это повысит сложность отладки.

0
ответ дан 3 December 2019 в 14:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: