Так как Вы спросили о других базах данных, вот некоторая информация о Oracle.
Добавление столбца NULL к таблице Oracle является очень быстрой операцией, поскольку оно только обновляет словарь данных. Это содержит монопольную блокировку на таблице в течение очень короткого периода времени. Это будет однако, делать недействительным любые depedant хранимые процедуры, представления, триггеры, и т.д. Они будут перекомпилированы автоматически.
Оттуда при необходимости можно создать индекс с помощью пункта ОНЛАЙН. Снова, только очень короткие блокировки словаря данных. Это считает целую таблицу, ища вещи индексировать, но не блокирует никого при выполнении этого.
, Если необходимо добавить внешний ключ, можно сделать это и заставить Oracle доверять Вам, что данные корректны. Иначе это должно считать целую таблицу и проверить все значения, которые могут быть медленными (создайте свой индекс сначала).
, Если необходимо поместить значение по умолчанию или вычисленное значение в каждую строку нового столбца, необходимо будет выполнить крупное обновление или возможно немного утилиты, которая заполняет новые данные. Это может быть медленно, особенно если строки становятся намного больше и больше не помещаются в их блоки. Блокировка может быть организована во время этого процесса. Так как старый versino Вашего приложения, которое все еще работает, не знает об этом столбце, Вам, возможно, понадобился бы подлый триггер или определить значение по умолчанию.
Оттуда, можно сделать switcharoo на серверах приложений к новой версии кода, и это будет продолжать бежать. Отбросьте свой подлый триггер.
, С другой стороны, можно использовать DBMS_REDEFINITION, который является черным квадратом, разработанным, чтобы сделать этот вид вещи.
Все это - так много беспокойства для тестирования, и т.д. что у нас просто есть начало отключения электричества утра воскресенья каждый раз, когда мы выпускаем основную версию.
Этим можно было управлять, переопределив ИСТИННЫЕ методы распределения и освобождения памяти в Delphi, NewInstance и FreeInstance . Конструкторы и деструкторы в Delphi только инициализируются и завершаются соответственно, они не выделяют и не освобождают память, поэтому попытка скрыть конструкторы всегда была немного ошибочной.
т.е. можно было разрешить свободное использование любых и всех конструкторов, пока вы переопределил NewInstance таким образом, что он когда-либо возвращал ссылку только на одно выделение памяти для класса.
Но попытка навязать шаблон использования / поведения в базовом классе - ошибка imho. Не ВСЕ шаблоны являются или требуют определенных классов для инкапсуляции шаблона.
Если вам просто нужен простой синглтон, Самый простой способ - использовать конструкторы классов и методы классов, как предлагает 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;
В Delphi 2010, безусловно, лучший и безопасный способ - использовать конструкторы классов . См. здесь - особенно прочтите параграф под названием Улучшенная инкапсуляция .
HTH.
Я предпочитаю использовать интерфейсы, когда мне нужны синглтоны, и скрывать реализацию интерфейса в разделе реализации.
преимущества
недостатки
Примечание: я считаю, что использование синглтонов должно быть сведено к абсолютному минимуму. В общем, синглтоны - это не более чем прославленные глобальные переменные. Если и когда вы начнете модульное тестирование своего кода, они станут неприятностью.
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.
Для синглтона вы можете переопределить метод NewInstance и использовать переменную класса.
Я предпочитаю создавать одноэлементный класс с помощью генератора кода. Проблема с generic заключается в том, что весь код создается в памяти, а не в исходном файле. Это повысит сложность отладки.