SingletonPattern (VFP)

From codeWiki
Jump to: navigation, search


Por VictorEspina

Contents

Introduccion

El patron Singleton permite definir una clase que devuelve una referencia a una unica instancia de la misma cada vez que se intenta crear una nueva instancia. Este patron es sumamente util cuando se desea manejar informacion comun a lo largo de la aplicacion y no se cuenta con clases estaticas, como es el caso de VFP.

Clase SingletonPattern

La clase SingletonPattern sirve como clase base para lograr convertir una clase cualquiera en un singleton. Lo unico que necesitamos es crear una clase basada en SingletonPattern que sera la que se instanciara a lo largo del progtrama, y la clase "real" que proporcionara la funcionalidad requerida.

Ejemplo:

* appContextClass es la clase real
DEFINE CLASS appContextClass AS Custom
 Usuario = ""
 Empresa = ""
ENDDEFINE
* appContext es la clase singleton que servira de puente para la clase real
DEFINE CLASS appContext AS SingletonPattern
 className = "appContextClass"
ENDDEFINE

Una vez hecho esto, toda instancia de appContext apuntara a una unica instancia de appContextClass:

LOCAL o1, o2
o1 = CREATE("appContext")
o2 = CREATE("appContext")
o1.Usuario = "VESPINA"
?o2.Usuario --> "VESPINA"

La idea de usar dos clases es una forma de permitir aplicar el patron a cualquier clase y no necesariamente una basada en Custom. Sin embargo, si nuestra clase puede heredar de Custom entonces podemos simplemente heredar directamente de SingletonPattern:

DEFINE CLASS appContext AS SingletonPattern
 Usuario = ""
 Empresa = ""
ENDDEFINE

Codigo Fuente

* SingletonPattern
* Clase para la implementacion del pattern Singleton en VFP
*
* Autor: Victor Espina
* Fecha: Abril 2012
*
* Uso:
* Para la implementacion de esta clase se requiere definir dos clases
* a) Una clase basada en SingletonPattern
* b) La clase real que se desea implementar como Singleton, la cual puede
*    estar basada en cualquier clase base o subclase.
*
* Ejemplo:
* Supongamos que tenemos una clase llamada AppContextClass que queremos
* implementar como singleton.  Lo unico que se debe hacer es declarar
* una clase basada en SingletonPattern y configurar su propiedad className:
*
* DEFINE CLASS appContext AS SingletonPattern
*  className = "appContextClass"
* ENDDEFINE
*
* Luego, cuando se desee crear una instancia de AppContextClass, se hace:
*
* oSingletonInstance = CREATE("appContext")
*
* Y se lograra el efecto de que todas las instancias de appContext apuntaran a
* una unica instancia de appContextClass.
*
* 
DEFINE CLASS SingletonPattern AS Custom
 *
 className = ""
 
 * Constructor
 * El parametro plInstance es utilizado por el metodo createInstance() en el caso
 * de que la clase real sea una subclase de SingletonPattern, para indicar que se
 * debe crear la instancia directamente
 PROCEDURE Init(plInstanceMode)
  IF plInstanceMode
   RETURN
  ENDIF
  IF EMPTY(THIS.className)      && Si no se indica una clase real se asume
   THIS.className = THIS.Class  && esta misma clase
  ENDIF
  IF NOT THIS.checkInstance()   && Se verifica si ya existe una instancia de
   THIS.createInstance()        && la clase. Si no es si, se crea
  ENDIF
 ENDPROC
 
 * checkInstance
 * Determina si ya existe una instancia creada para la clase real
 PROCEDURE checkInstance
  IF NOT ISNULL(THIS.getInstance())   && Si podemos obtener una referencia a la instancia
   RETURN .T.                         && es porque la misma existe
  ENDIF
  IF !PEMSTATUS(_Screen,THIS.className, 5)    && Si no existe la propiedad asociada a la clase
   _Screen.addProperty(THIS.className, NULL)  && en _Screen, se crea
  ENDIF
  RETURN .F.
 ENDPROC

 * createInstance
 * Crea una instancia de la clase real 
 PROCEDURE createInstance
  LOCAL oInstance
  IF LOWER(THIS.Class) == LOWER(THIS.className)   && La clase real es una subclase directa de SingletonPattern ?
   oInstance = CREATE(THIS.className, .T.)
  ELSE
   oInstance = CREATE(THIS.className)
  ENDIF
  STORE oInstance TO ("_Screen." + THIS.className)
 ENDPROC

 * getInstance
 * Devuelve una referencia a la instancia unica de la clase real 
 PROCEDURE getInstance
  IF !PEMSTATUS(_Screen,THIS.ClassName,5) OR TYPE("_Screen." + THIS.className)<>"O"
   RETURN NULL
  ENDIF
  RETURN EVAL("_Screen." + THIS.className)
 ENDPROC
 
 * releaseInstance
 * Libera la instancia unica de la clase real
 PROCEDURE releaseInstance
  IF THIS.checkInstance()
   STORE NULL TO ("_Screen." + THIS.className)
  ENDIF
 ENDPROC
 
 * Accesor para la propiedad THIS
 * Este accesor decide si devuelve una referencia al controlador Singleton o a la clase real
 PROCEDURE THIS_Access(cMember)
  IF INLIST(LOWER(cMember),"classname","checkinstance","createinstance","getinstance","class")
   RETURN THIS
  ELSE
   RETURN EVAL("_Screen." + THIS.className)
  ENDIF
 ENDPROC
 *
ENDDEFINE
Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox