Patrones de Diseño — Singleton (con ejemplo en ABAP OO)
El patrón Singleton es un patrón de creación cuyo objetivo es garantizar que exista una sola instancia de una clase durante la ejecución de un programa y proveer un punto de acceso global a dicha instancia. Aunque es muy conocido y útil en ciertos escenarios, también es un patrón debatido por introducir estado global y acoplamiento si se usa indiscriminadamente.
En este artículo te explico el patrón en términos sencillos y, sobre todo, con un ejemplo práctico en ABAP OO usando CREATE PRIVATE
y un método de fábrica GET_INSTANCE
. También revisamos ventajas, riesgos, cuándo aplicarlo en sistemas SAP y alternativas modernas.
1) ¿Qué es exactamente un Singleton?
Un Singleton es una clase que controla su propia creación para asegurar que solo exista una instancia y que cualquier consumidor del sistema obtenga siempre esa misma instancia. Es especialmente útil cuando el objeto representa un recurso compartido y único (por ejemplo, una configuración de sistema, un logger central, un gestor de conexiones o un servicio de caché).
En ABAP, no “privatizamos” el constructor como en otros lenguajes; más bien declaramos la clase con CREATE PRIVATE
para impedir que el exterior instancie con NEW
y así forzar el uso de un método de acceso (normalmente GET_INSTANCE
). Esto está documentado en recursos oficiales y tutoriales de ABAP: CREATE PRIVATE
es la forma estándar de restringir la instanciación y crear fábricas/singletons en ABAP. [Referencia: SAP Help / Learning Journey sobre CREATE PRIVATE
]()
2) Analogía simple
Imagina que en una empresa hay un solo panel de configuración para todos los equipos. Si cada área tuviera su propia “copia” del panel con parámetros distintos, surgirían inconsistencias. Con un panel único (Singleton), todos leen y actualizan la misma fuente de verdad.
3) ¿Cuándo tiene sentido usarlo en SAP?
Casos típicos en proyectos ABAP:
- Parámetros globales de ejecución (por ej., modo de “simulación” o “productivo”).
- Gestor central de logging para toda la aplicación.
- Adaptador hacia un recurso compartido: leer un archivo de configuración, consulta a un servicio remoto, o un wrapper de RFC/HTTP que queremos reusar y configurar solo una vez.
- Cachés en memoria a nivel de proceso o petición para evitar recomputar resultados costosos.
Nota: En ABAP cada work process ejecuta un flujo de trabajo de usuario a la vez; por ello, el patrón no suele requerir sincronización de hilos como en Java/C#, pero sí debes pensar en el alcance de memoria (proceso actual, sesión, servidor de aplicaciones, memoria compartida SHM, etc.). Para singletons verdaderamente compartidos entre procesos, evalúa Shared Objects (SHM) y bloqueos apropiados.
4) Implementación en ABAP OO (Singleton con CREATE PRIVATE
)
A continuación un ejemplo completo y minimalista de un Singleton en ABAP OO. La instancia única se mantiene en un atributo estático de clase y se expone mediante un método de clase GET_INSTANCE
.
Escenario de ejemplo: un servicio de configuración que carga parámetros (de tabla Z o de constantes) y los ofrece al resto del sistema a través de un solo punto de acceso.
"======================================================================
" Clase: ZCL_APP_CONFIG
" Propósito: Servicio de configuración de aplicación como Singleton
"======================================================================
CLASS zcl_app_config DEFINITION
PUBLIC
FINAL
CREATE PRIVATE.
PUBLIC SECTION.
CLASS-METHODS get_instance RETURNING VALUE(ro_config) TYPE REF TO zcl_app_config.
METHODS get_param IMPORTING i_key TYPE string RETURNING VALUE(r_val) TYPE string.
METHODS set_param IMPORTING i_key TYPE string i_val TYPE string.
PRIVATE SECTION.
CLASS-DATA go_instance TYPE REF TO zcl_app_config.
DATA mt_params TYPE HASHED TABLE OF string WITH UNIQUE KEY table_line.
METHODS constructor.
ENDCLASS.
CLASS zcl_app_config IMPLEMENTATION.
METHOD constructor.
INSERT 'mode=PROD' INTO TABLE mt_params.
INSERT 'country=CO' INTO TABLE mt_params.
INSERT 'currency=COP' INTO TABLE mt_params.
ENDMETHOD.
METHOD get_instance.
IF go_instance IS NOT BOUND.
CREATE OBJECT go_instance.
ENDIF.
ro_config = go_instance.
ENDMETHOD.
METHOD get_param.
DATA(lv_key) = |{ i_key TO LOWER }|.
READ TABLE mt_params WITH TABLE KEY table_line = lv_key TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
r_val = lv_key.
ELSE.
r_val = ``.
ENDIF.
ENDMETHOD.
METHOD set_param.
DATA(lv_key) = |{ i_key TO LOWER }|.
DELETE TABLE mt_params WITH TABLE KEY table_line = lv_key.
INSERT lv_key INTO TABLE mt_params.
ENDMETHOD.
ENDCLASS.
Uso:
DATA(lo_cfg) = zcl_app_config=>get_instance( ).
lo_cfg->set_param( i_key = 'timezone' i_val = 'America/Bogota' ).
DATA(lv_mode) = lo_cfg->get_param( i_key = 'mode' ).
IF lv_mode = 'mode=PROD'.
" Lógica productiva
ENDIF.
Observaciones clave
CREATE PRIVATE
bloquea la creación directa conNEW
desde fuera de la clase; así obligas a consumir el métodoGET_INSTANCE
.- Se usa
CLASS-DATA
para almacenar la única referencia de clasego_instance
. - Hacemos lazy initialization (se crea al primer uso).
- Puedes añadir un
CLASS-CONSTRUCTOR
si debes preparar estado estático de clase antes de la primera llamada a cualquier método. - Si necesitas que el Singleton sobreviva más allá del proceso/solicitud (y sea compartido entre procesos), migra el almacenamiento a Shared Objects (SHM) o a una tablas bufferizadas según el caso.
5) Variantes útiles en ABAP
a) Singleton parametrizable (semi‑inmutable)
CLASS zcl_service_singleton DEFINITION
PUBLIC FINAL CREATE PRIVATE.
PUBLIC SECTION.
CLASS-METHODS get_instance RETURNING VALUE(ro) TYPE REF TO zcl_service_singleton.
CLASS-METHODS init IMPORTING i_http_client TYPE REF TO if_http_client RAISING cx_static_check.
METHODS call_api IMPORTING i_path TYPE string RETURNING VALUE(r_body) TYPE string.
PRIVATE SECTION.
CLASS-DATA go_inst TYPE REF TO zcl_service_singleton.
DATA mo_http TYPE REF TO if_http_client.
METHODS constructor.
ENDCLASS.
CLASS zcl_service_singleton IMPLEMENTATION.
METHOD constructor.
ENDMETHOD.
METHOD init.
IF go_inst IS BOUND AND go_inst->mo_http IS BOUND.
RAISE EXCEPTION TYPE cx_static_check.
ENDIF.
IF go_inst IS NOT BOUND.
CREATE OBJECT go_inst.
ENDIF.
go_inst->mo_http = i_http_client.
ENDMETHOD.
METHOD get_instance.
IF go_inst IS NOT BOUND.
CREATE OBJECT go_inst.
ENDIF.
ro = go_inst.
ENDMETHOD.
METHOD call_api.
" Usa mo_http aquí...
ENDMETHOD.
ENDCLASS.
b) Singleton con memoria compartida (SHM)
Si requieres compartir estado entre múltiples work processes, considera Shared Objects […]
c) Control de concurrencia
Aunque ABAP clásico no ejecuta múltiples hilos por proceso, si accedes a recursos compartidos, usa bloqueos SAP estándar.
6) Ventajas y riesgos
Ventajas
- Un único punto de acceso a un servicio compartido.
- Inicialización diferida (lazy).
- Menos duplicación, más control de configuración.
Riesgos
- Estado global = acoplamiento.
- Dificulta los tests unitarios.
- No es verdaderamente global entre procesos sin SHM.
- Puede violar SRP (un class hace demasiado).
Buenas prácticas
- Mantén el Singleton enfocado.
- Úsalo como punto de acceso, no como contenedor de lógica compleja.
- Considera IoC o DI excepcionales donde aplique.
- Evalúa alternativas según los requisitos.
7) Alternativas y cuándo no usarlo
Evita el Singleton si necesitas múltiples variantes, pruebas aisladas o soluciones desacopladas y dinámicas.
Alternativas:
- Fábricas + DI
- Contextos explícitos
- Shared Objects
8) Checklist de implementación en ABAP
- Define la clase con
CREATE PRIVATE
. - Declara
CLASS-DATA
para la referencia única. - Expón
GET_INSTANCE
. - Usa
CLASS-CONSTRUCTOR
si necesitas estado estático. - Considera SHM si es entre procesos.
- Diseña APIs simples y testeables.
9) Resumen rápido
| Concepto | Puntos clave |
|—|—|
| Propósito | Una instancia única + acceso global |
| Clave en ABAP | CREATE PRIVATE
+ CLASS-DATA
+ GET_INSTANCE
|
| Ventajas | Centralización, lazy init, menos duplicación |
| Riesgos | Estado global, pruebas más difíciles, alcance de memoria por proceso |
| Alternativas | DI/IoC, fábricas, SHM |
| Cuándo aplicarlo | Config, logging, cachés o adaptadores a recursos compartidos |
10) Referencias y lecturas recomendadas
- Singleton (visión general del patrón) — Refactoring.Guru
- Implementing Factory Methods — SAP Learning Journey
- SAP ABAP Help:
NEW
, visibilidades yCREATE PRIVATE
- Ejemplos en comunidad SAP:
- https://community.sap.com/t5/…/ba-p/13395199
- https://community.sap.com/t5/…/m-p/12269467
- https://zevolving.com/…/abap-objects-design-patterns-singleton-usage
Comentarios recientes