Dos métodos para implementar el modo Singleton en Delphi
haozi
Resumen Este artículo describe dos implementaciones Delphi del modo Singleton y realiza un análisis comparativo.
Patrón de diseño de palabras clave, Singleton
El patrón Singleton es un patrón de diseño muy útil. Su intención es simplemente crear una instancia de una clase y proporcionarle un punto de acceso global. Las variables globales hacen que un objeto sea fácilmente accesible, pero no impiden que se creen instancias de varios objetos. El propósito del patrón singleton es garantizar que solo exista una instancia durante el ciclo de vida del programa.
Mira el código a continuación:
Procedimiento TForm1.Button1Click(Remitente: TObject);
var lS1: TSingleton;
S2: TSingleton;
comenzar
intente lS1 := TSingleton.Create; //// Llame al constructor de la clase
lS2 := TSingleton.Create; //// Llamar al constructor de la clase
//// ...otro código
finalmente
lS1.Free; ////Liberar el objeto
lS2.Free; ////Liberar el objeto
fin;
fin;
En el código anterior, se crea una instancia de la clase TSingleton cuando se llama a la función Crear por primera vez. lS1 apunta a la dirección de un objeto de almacenamiento de memoria. Cuando se llama a la función TSingleton.Create por segunda vez, el objeto TSingleton se vuelve a crear. -instanciado. lS2 apunta a la dirección de memoria asignada Otra dirección. El patrón Singleton consiste en dejar que la clase misma sea responsable de guardar su única instancia.
En el código anterior, cuando se crea ls2, también apunta al objeto señalado por ls1 (es decir, se le asigna la misma dirección de memoria). De manera similar, debemos evitar que la memoria se libere al liberar ls1, porque es único. ls2 también hace referencia al objeto. Esto garantiza que solo haya una instancia de clase durante el ciclo de vida del programa.
El código de muestra de C++ en "Patrón de diseño" usa variables miembro estáticas de C++ para guardar instancias y usa funciones de constructor protegidas. Sin embargo, dado que no hay variables miembro estáticas en Delphi, el método de este ejemplo de modo singleton no se puede utilizar tal cual. A continuación analizamos varias formas en que DELPHI implementa el modo Singleton.
uno. Método basado en anular dos funciones virtuales de Tobject
función de clase NewInstance: TObject;
procedimiento FreeInstance;
La función NewInstance es responsable de asignar memoria para el objeto cuando se crea el objeto de clase, mientras que FreeInstance libera la memoria por el contrario.
.
El primero se llama cuando se construye el objeto y el segundo se llama cuando se destruye el objeto.
Usamos dos variables globales para contener el objeto singleton y el recuento de referencia del objeto.
varInstancia: TSingleton = nil;
RefCount: Entero = 0;
Unidades de la clase TSingleton:
////---------------------------------------------- ----------------------------
////
unidad uSingleton;
interfaz
tipo
TSingleton = clase(TObjeto)
público
función de clase NewInstance: TObject; anular; //// Anular la función de clase base
procedimiento FreeInstance; override; //// Anular la función de clase base
función de clase RefCount: Integer;//// Devuelve el recuento de referencia actual
fin;
//// Declaración de variables globales
var
Instancia: TSingleton = nil;
RefCount: Entero = 0;
implementación
{TSingleton}
procedimiento TSingleton.FreeInstance;
comenzar
Dec( RefCount );////Disminuir el recuento de referencia
si (RefCount = 0) entonces //// ¿Es 0? Si es así, libere la memoria.
comenzar
Instancia: = nula;
//// Liberar las variables privadas de la clase singleton
////…
FreeInstance heredado;
fin;
fin;
función de clase TSingleton.NewInstance: TObject;
comenzar
si (no asignado (instancia)) entonces
comenzar
Instancia := TSingleton (Nueva Instancia heredada);
////Ejemplo de inicialización de variables privadas:
//// Instancia.NombreVariable := Valor;
fin;
Resultado:= Instancia;
Inc(RecuentoRef);
fin;
función de clase TSingleton.RefCount: entero;
comenzar
Resultado := RefCount;
fin;
fin.
////---------------------------------------------- ----------------------------
////
Cuando se llama al constructor de TSingleton, se llamará a nuestra función de anulación NewInstance, y NewInstance asignará memoria y la devolverá al constructor. De esta manera, a través de la función de anulación NewInstance, nos aseguramos de que la función Crear solo pueda crear una instancia de un objeto TSingleton. (No importa cuántas veces se llame, Crear solo devuelve la dirección de memoria asignada por primera vez). Al mismo tiempo, la variable RefCount contiene cuántas referencias tenemos al objeto.
Veamos el código de prueba.
procedimiento TForm1.Button1Click (Remitente: TObject);
var
lS1, lS2: TSingleton;
Ob1, Ob2: Objeto;
comenzar
lS1 := TSingleton.Crear;
ShowMessage(IntToStr(RefCount)); //// Ref_Count = 1
lS2 := TSingleton.Create;
ShowMessage(IntToStr(RefCount)); //// Ref_Count = 2
Ob1 := TObject.Crear;
Ob2 := Objeto.Crear;
si lS1 = lS2 entonces
ShowMessage('Las direcciones son iguales') //// lS1 = lS2
demás
ShowMessage('Las direcciones no son iguales');
si Ob1 = Ob2 entonces
ShowMessage('Las direcciones son iguales')
demás
ShowMessage('Las direcciones no son iguales'); //// Ob1 <> Ob2
fin;
Cuando el programa llama al destructor (es decir, cuando se llama a la función FREE), el destructor llamará a la función FreeInstance para liberar la memoria asignada por el constructor. La función FreeInstance de Override garantiza que la memoria del objeto en modo singleton se libere solo cuando el recuento de referencias llegue a cero.
Aquí está nuestro código de prueba:
var
lS1: TSingleton;
lS2: TSingleton;
comenzar
intentar
lS1 := TSingleton.Create; //// Llamar al constructor de la clase
lS2 := TSingleton.Create; //// Llamar al constructor de la clase
//// ...otro código
finalmente
lS1.Free; //// Aquí primero llamaremos a la FreeInstance definida por nuestra anulación,
//// Dado que RefCount es 1 después de disminuir 1 en este momento, el objeto singleton no se ha liberado.
lS2.Free; ////dec(RefCount)= 0 libera el objeto singleton
fin;
fin;
El método de implementación del patrón singleton anterior es una buena manera de darse cuenta de que la clase misma es responsable de guardar su propia instancia única (interceptando la solicitud para crear un nuevo objeto; consulte "Patrones de diseño". No tiene restricciones especiales en el uso). de la clase TSingleton: los programadores pueden llamar a las funciones Crear y Liberar a voluntad.
La desventaja de este modo es que la clase TSingleton no se puede heredar como clase principal para generar subclases. Si la herencia genera dos subclases, solo se generará un objeto durante la creación.
procedimiento TForm1.Button1Click (Remitente: TObject);
var
lS1: subcategoría uno;
lS2: subcategoría dos;
comenzar
lS1 := Subclase 1.Crear;
lS2 := Subclase 2.Create; //// La subclase 2 no se creará, lS2 apuntará a la memoria a la que apunta lS1,
////Es decir, lS1 = lS2end;
dos. Implementación en Delphi del ejemplo en "Patrones de diseño"
El ejemplo de implementación de "Patrón de diseño" es controlar solo una instancia de objeto a través de una función constructora privada. Sin embargo, la implementación del código C++ dada no proporciona cómo se libera el objeto. La función Crear no se puede privatizar en Delphi. Definimos una nueva función para reemplazar la función Crear y proteger la función Crear de la clase principal. El código es el siguiente.
:
////---------------------------------------------- ----------------------------
////
unidad uSingletonUnit;
interfaz
usos
Clases, SysUtils;
tipo
TCSingleton = class(TComponent) //// Heredado de la clase Tcomponent.
privado
constructor CreateInstance(AOwner: TComponent); ////Pasar el parámetro Propietario
//// De esta manera, el objeto de clase TCSingleton se destruirá junto con el propietario (el propietario es responsable de destruir el objeto TCSingleton)
público
constructor Crear (AOwner: TComponent);
Instancia de función de clase (AOwner: TComponent): TCSingleton;
fin;
var
gCSingleton: TCSingleton; //// Variables globales
implementación
{TCSingleton}
constructor TCSingleton.Create(AOwner: TComponent);
comenzar
//// Proteger la función de Crear función
elevar Exception.CreateFmt('acceder a la clase %s solo a través de la instancia',
[Nombre de clase]);
fin;
constructor TCSingleton.CreateInstance(AOwner: TComponent);
comenzar
////El constructor recién definido es privado
heredado Crear (AOwner);
fin;
función de clase TCSingleton.Instance(AOwner: TComponent): TCSingleton;
comenzar
si no está asignado (gCSingleton), entonces
gCSingleton := TCSingleton.CreateInstance(AOwner);
Resultado := gCSingleton;
fin;
fin.
////---------------------------------------------- -----------------------------/
/
Durante el uso de la clase de implementación anterior, los programadores no necesitan considerar la destrucción de objetos en modo singleton. Simplemente no puede llamar a Crear, debe llamar a la función Instancia para obtener una instancia del objeto y pasar el propietario singleton como parámetro a la función. Este método de implementación se puede heredar como clase base y usarse en un singleton del patrón de estado (ver Referencia 4) para lograr polimorfismo en tiempo de ejecución.
tres. Conclusión
La implementación de Delphi del modo Singleton también se puede encontrar en Internet. Hay otros métodos de implementación. Los dos métodos descritos en este artículo.
El más común y sencillo. Al mismo tiempo, las ideas de otros métodos también son muy similares a las de los dos métodos anteriores.