TAW12 Programación ABAP - Avanzado Parte 1
.
.
MANUAL DEL PARTICIPANTE FORMACIÓN CON INSTRUCTOR
. Versión del curso: 10 Duración del curso: 5 Días Número de material: 50117660
Copyright y marcas registradas de SAP
© 2014 SAP AG. Reservados todos los derechos.
Queda prohibida la reproducción o difusión de parte o la totalidad de este programa sin el permiso expreso de SAP AG. La información aquí contenida puede modificarse sin previo aviso. Algunos productos de software comercializados por SAP AG y sus distribuidores contienen componentes de software propiedad de otros proveedores de software. ●
Microsoft, Windows, Excel, Outlook y PowerPoint son marcas registradas de Microsoft Corporation.
●
IBM, DB2, DB2 Universal Database, System i, System i5, System p, System p5, System x, System z, System z10, System z9, z10, z9, iSeries, pSeries, xSeries, zSeries, eServer, z/VM, z/OS, i5/OS, S/390, OS/390, OS/400, AS/400, S/390 Parallel Enterprise Server, PowerVM, Power Architecture, POWER6+, POWER6, POWER5+, POWER5, POWER, OpenPower, PowerPC, BatchPipes, BladeCenter, System Storage, GPFS, HACMP, RETAIN, DB2 Connect, RACF, Redbooks, OS/2, Parallel Sysplex, MVS/ESA, AIX, Intelligent Miner, WebSphere, Netfinity, Tivoli y Informix son marcas comerciales o marcas registradas de IBM Corporation.
●
●
Linux es la marca registrada de Linus Torvalds en EE. UU. y en otros países. Adobe, el logotipo de Adobe, Acrobat, PostScript y Reader son marcas comerciales o marcas registradas de Adobe Systems Incorporated en EE. UU. y/o en otros países.
●
Oracle es una marca registrada de Oracle Corporation.
●
UNIX, X/Open, OSF/1 y Motif son marcas registradas de Open Group.
●
Citrix, ICA, Program Neighborhood, MetaFrame, WinFrame, VideoFrame, y MultiWin son marcas o marcas registradas de Citrix Systems, Inc.
●
HTML, XML, XHTML y W3C son marcas o marcas registradas de W3C®, World Wide Web Consortium, Massachusetts Institute of Technology.
●
Java es una marca registrada de Sun Microsystems, Inc.
●
JavaScript es una marca registrada de Sun Microsystems, Inc., utilizada bajo licencia para la tecnología inventada e implementada por Netscape.
●
SAP, R/3, SAP NetWeaver, Duet, PartnerEdge, ByDesign, SAP BusinessObjects Explorer, StreamWork y otros productos y servicios de SAP aquí mencionados, así como sus respectivos logotipos, son marcas comerciales o marcas registradas de SAP AG en Alemania y en otros países.
●
Business Objects y el logotipo de Business Objects, BusinessObjects, Crystal Reports, Crystal Decisions, Web Intelligence, Xcelsius y otros productos y servicios de Business Objects aquí mencionados, así como sus respectivos logotipos, son marcas comerciales o marcas registradas de Business Objects Software Ltd. Business Objects es una empresa de SAP.
●
Sybase y Adaptive Server, iAnywhere, Sybase 365, SQL Anywhere, y otros productos y servicios Sybase aquí mencionados, así como sus respectivos logotipos son marcas comerciales o marcas registradas de Sybase Inc. Sybase es una empresa de SAP.
El resto de nombres de productos y servicios mencionados son marcas de sus respectivas empresas. Los datos contenidos en este documento son únicamente informativos. Las especificaciones nacionales del producto pueden variar. Este material está sujeto a cambios sin previo aviso. Este material está provisto por SAP AG y sus empresas afiliadas ("Grupo SAP") únicamente para fines informativos, sin representar garantía alguna; el Grupo SAP no será responsable de los errores u omisiones referentes a los materiales. Las únicas garantías para los productos y servicios del Grupo SAP son las especificadas explícitamente en las declaraciones de garantías que acompañan a los productos y servicios, si los hubiera. Nada de lo escrito en la presente debe tomarse como una constitución de garantía adicional.
© Copyright . Reservados todos los derechos.
iii
iv
© Copyright . Reservados todos los derechos.
Sobre este manual Este manual intenta complementar la presentación de la guía de instructores de este curso y servir como una fuente de referencia. No es adecuado como material de auto-estudio. Convenciones Tipográficas En este manual se usa el español de España como estándar. También se usan las siguientes convenciones tipográficas.
Esta información se visualiza en la presentación del instructor.
Demostración
Procedimiento
Advertencia o aviso
Consejo
Información relacionada o adicional
Discusión con moderador
Control de interfaz de usuario
Texto ejemplo
Título de ventana
Texto ejemplo
© Copyright . Reservados todos los derechos.
v
vi
© Copyright . Reservados todos los derechos.
Contenido xi
Resumen del curso
1
Capítulo 1: Introducción a la programación orientada a objetos
2 13 25 35 37 49 55 61 65 71 77 81 88 91 107 108 117 127 131 136 141 148 151 169 170 175 185 189 196 199
Lección: Explicación del modelo de programación orientado a objetos Lección: Análisis y diseño con lenguaje unificado de modelado (UML) Ejercicio 1: Crear diagramas de UML Capítulo 2: Sintaxis fundamental orientada a objetos Lección: Creación de clases locales Ejercicio 2: Crear clases locales Lección: Creación y trabajos con objetos Ejercicio 3: Crear objetos Lección: Acceso a métodos y atributos Ejercicio 4: Llamar métodos Lección: Implementación de constructores en clases locales Ejercicio 5: Crear y utilizar constructores Lección: Implementación de constructores de clases en clases locales Ejercicio 6: Crear y utilizar constructores estáticos Capítulo 3: Herencia y casting Lección: Implementación de la herencia Ejercicio 7: Implementar la herencia Lección: Implementación de conversiones Up-Cast mediante la herencia Ejercicio 8: Implementar up-casts Lección: Implementación de polimorfismo con herencia Ejercicio 9: Implementar el polimorfismo mediante la herencia Lección: Implementación down-casts mediante la herencia Ejercicio 10: Implementar down-casts Capítulo 4: Interfaces y casting Lección: Definición e implementación de las interfaces locales Ejercicio 11: Definir e implementar una interfaz local Lección: Implementar el polimorfismo mediante interfaces Ejercicio 12: Implementar el polimorfismo mediante interfaces Lección: Unión de modelos de clase con interfaces Ejercicio 13: Integre los modelos de clase con interfaces.
© Copyright . Reservados todos los derechos.
vii
217
Capítulo 5: Eventos orientados a objetos
218 227 240
Lección: Implementación de eventos en clases locales Ejercicio 14: Implementar eventos en las clases locales Lección: Implementación de eventos en interfaces locales
241
Ejercicio 15: Implementar el tratamiento de eventos para las interfaces
255
Capítulo 6: Objetos de Repository orientados a objetos
256 265 272
Lección: Crear clases globales Ejercicio 16: Implementar una clase global Lección: Definición e implementación de las interfaces globales
277 286 293
Ejercicio 17: Importar e implementar una interfaz global Lección: Implementación de la herencia en clases globales Ejercicio 18: Implementar la herencia en las clases globales
303
Capítulo 7: Ejemplos orientados a objetos de ABAP
304 311 317
Lección: Implementación de ABAP List Viewer (ALV) Ejercicio 19: Implementar el control Grid ALV Ejercicio 20: Implementar una ventana emergente con el control Grid ALV Lección: Implementación de add-ins empresariales (BAdI)
326 337
Capítulo 8: Patrones de diseño orientados a objetos
338
Lección: Implementación de técnicas especiales orientadas a objetos Lección: Implementación del patrón singleton Ejercicio 21: Implementar el patrón singleton Lección: Implementación de clases factory mediante amistad Ejercicio 22: Implementar una clase factory mediante amistad
345 349 358 361 377
Capítulo 9: Tratamiento de excepciones orientadas a objetos
378 384 391 405
Lección: Explicación de las excepciones basadas en clases Lección: Definición y emisión de excepciones Ejercicio 23: Implementar las excepciones basadas en clases Lección: Implementación de técnicas avanzadas de tratamiento de excepciones Ejercicio 24: Asignar excepciones unas a otras
413 433 434 451
viii
Capítulo 10:
Llamadas de programa y gestión de memoria Lección: Uso de objetos compartidos Ejercicio 25: Utilizar objetos compartidos
© Copyright . Reservados todos los derechos.
461
Capítulo 11: Programación dinámica
462 469
Lección: Uso de los tipos de datos genéricos Ejercicio 26: Utilizar Field Symbols tipificados de manera dinámica en sentencias SQL dinámicas
477
Ejercicio 27: Acceder a componentes de estructuras de manera dinámica Lección: Descripción de tipos de datos, objetos de datos y objetos en tiempo de ejecución Ejercicio 28: Proporcionar cabeceras de columna con la identificación de tipos en tiempo de ejecución Lección: Creación de tipos de datos, objetos de datos y objetos en tiempo de ejecución Ejercicio 29: Crear objetos de datos en tiempo de ejecución Ejercicio 30: Crear tipos de datos en tiempo de ejecución con la creación de tipos en tiempo de ejecución (RTTC)
486 497 507 513 523
© Copyright . Reservados todos los derechos.
ix
x
© Copyright . Reservados todos los derechos.
Resumen del curso PÚBLICO OBJETIVO Este curso está dirigido al siguiente público objetivo: ●
Consultor de aplicaciones
●
Consultor de desarrollo
●
Consultor de soporte
●
Programador
© Copyright . Reservados todos los derechos.
xi
xii
© Copyright . Reservados todos los derechos.
CAPÍTULO 1
Introducción a la programación orientada a objetos
Lección 1 Explicación del modelo de programación orientado a objetos
2
Lección 2 Análisis y diseño con lenguaje unificado de modelado (UML) Ejercicio 1: Crear diagramas de UML
13 25
OBJETIVOS DEL CAPÍTULO ●
Explicar las diferencias entre modelos de programación procedimental y orientada a objetos
●
Describir objetos ABAP
●
Clasificar objetos
●
Modelar objetos y clases en UML
© Copyright . Reservados todos los derechos.
1
Capítulo 1 Lección 1 Explicación del modelo de programación orientado a objetos
RESUMEN DE LA LECCIÓN Este módulo brinda un resumen de los conceptos clave de la programación ABAP con el modelo orientado a objetos. Ejemplo empresarial Necesita explicar el modelo de programación orientado a objetos y sus ventajas a su jefe de proyectos de desarrollo. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de la programación orientada a objetos y procedimental
●
Una buena comprensión de los objetos ABAP
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
●
Explicar las diferencias entre modelos de programación procedimental y orientada a objetos Describir objetos ABAP
Historial de lenguajes de programación seleccionados
Figura 1: Historial de lenguajes de programación seleccionados
Como puede ver en la figura, la programación orientada a objetos (como el lenguaje de programación Simula 67) y los modelos de programación lógica y procedimental (como se
2
© Copyright . Reservados todos los derechos.
Lección: Explicación del modelo de programación orientado a objetos
utilizan en lenguajes como C y Pascal), se desarrollaron prácticamente al mismo tiempo. Anteriormente, COBOL y el modelo de programación procedimental dominaban el desarrollo de aplicaciones empresariales. SAP utilizó un ensamblador de macros antes de ABAP. Incluso hoy, muchos programadores tienen más experiencia con la programación procedimental que con la programación orientada a objetos. Por lo tanto, esta introducción hace referencia al modelo procedimental cuando explica la programación orientada a objetos. ABAP se creó para mejorar el reporting. Se desarrolló de forma independiente como lenguaje de programación en la empresa. Fue influenciado por otros lenguajes de programación como COBOL y Pascal. ABAP fue ampliado entonces para formar objetos ABAP. Por ello, los objetos ABAP comprenden elementos orientados a objetos y de proceso en un lenguaje de programación. Para la parte de la programación orientada a objetos, los objetos ABAP adoptaron conceptos orientados a los objetos para el desarrollo de aplicaciones empresariales en otros lenguajes (por ejemplo, Java, C++ y Smalltalk).
El modelo de programación procedimental
Figura 2: Características del modelo de programación procedimental
Las variables globales de un programa contienen los datos, mientras que las subrutinas contienen las funciones. Cada subrutina puede acceder a todas las variables globales.
© Copyright . Reservados todos los derechos.
3
Capítulo 1: Introducción a la programación orientada a objetos
Componentes de un programa ABAP procedimental
Figura 3: Programa ABAP de proceso típico
Una programa ABAP procedimental típico está compuesto por definiciones de tipo y declaraciones de datos. Las declaraciones de datos describen la estructura de datos que el programa utiliza cuando se ejecuta. Es posible encapsular la lógica en las unidades de modularización (por ejemplo, las subrutinas o los módulos de función). Sin embargo, en el nivel de programa principal, no hay ninguna protección especial para los objetos de datos globales. Es posible leer y modificar las variables globales desde cualquier ubicación en el programa. Encapsulación de los grupos de funciones que utilizan datos
Figura 4: Encapsulación de grupos de funciones que utilizan datos
Cuando un módulo de funciones se llama en el programa principal, su grupo de funciones se carga en la sesión interna. El grupo de funciones sigue activo hasta que el programa principal
4
© Copyright . Reservados todos los derechos.
Lección: Explicación del modelo de programación orientado a objetos
haya terminado de ejecutarse. El sistema almacena el programa principal y los grupos de funciones llamados en áreas diferentes de la memoria. Incluso si los objetos de datos de los grupos de funciones tienen los mismos nombres de objetos de datos que en el programa de llamada, no comparten el mismo espacio de memoria. Nada se comparte, ni siquiera cuando los objetos de datos de los grupos de funciones tienen el mismo nombre. No es posible acceder a los datos globales de un grupo de función directamente desde el programa principal. Sólo puede solicitar los módulos de funciones de los grupos de funciones desde el programa principal. A su vez, los módulos de funciones pueden acceder a otros componentes, especialmente los datos globales de sus propios grupos de funciones. La encapsulación también utiliza la idea de que la implementación de un servicio puede ocultarse de otros componentes del sistema. Esto sucede porque los demás componentes no pueden realizar suposiciones con relación al estado interno de la unidad de modularización. De esta manera, el diseño de estos otros componentes no depende de las unidades de modularización que se implementan de alguna manera determinada. Un grupo de función reúne los datos y las funciones que administran los datos. El acceso encapsulado a los datos y los servicios es uno de varios conceptos del modelo de programación orientado a objetos. Por lo tanto, este modelo de programación y la parte procedimental de los objetos ABAP admite esta encapsulación. Cuando implementa la interfaz de programación de la aplicación empresarial (BAPI), las BAPI se implementan como módulos de funciones y los objetos empresariales, como grupos de funciones. Grupos de funciones
Figura 5: Ejemplo de un grupo de funciones
El grupo de funciones ficticio S_VEHICLE ofrece los servicios Inc_speed, dec_speed y get_speed a un usuario o cliente. Estos servicios son la interfaz del grupo de funciones. Todos tienen acceso a la velocidad del objeto de datos global que pertenece al grupo de funciones.
© Copyright . Reservados todos los derechos.
5
Capítulo 1: Introducción a la programación orientada a objetos
Ejemplo de uso del grupo de funciones
Figura 6: Ejemplo de uso del grupo de funciones
El programa principal no puede acceder directamente a la velocidad del objeto de datos del grupo de funciones.
Instanciación múltiple
Figura 7: Varias instancias de un grupo de funciones
Para que el programa principal funcione con varios vehículos, debe haber una programación adicional y esfuerzo administrativo. Un grupo de funciones solo puede hacer referencia a un vehículo a la vez.
6
© Copyright . Reservados todos los derechos.
Lección: Explicación del modelo de programación orientado a objetos
Instanciación múltiple en la programación orientada a objetos
Figura 8: Instanciación múltiple en la programación orientada a objetos
La posibilidad de crear diversas instancias en tiempo de ejecución utilizando el mismo contexto de programa es una de las características clave de la programación orientada a objetos. En este ejemplo, desarrollará un programa para crear cuatro vehículos, todos con distintas características. Sin embargo, todos los vehículos comparten la misma estructura de datos y el mismo conjunto de funciones. Todos tienen la capacidad de proteger sus datos del acceso exterior. Memoria principal ABAP y encapsulación
Figura 9: Memoria principal ABAP y encapsulación
Estas son las características de encapsulación que utilizan grupos de funciones y subrutinas: ● Utiliza unidades de modularización para encapsular funciones y datos. ●
Puede trabajar con datos globales del programa principal.
Estas son las características de encapsulación que utilizan objetos:
© Copyright . Reservados todos los derechos.
7
Capítulo 1: Introducción a la programación orientada a objetos
●
Puede utilizar objetos para encapsular funciones y datos.
●
Puede crear múltiples instancias (objetos).
Puede realizar la instanciación múltiple. Los objetos se almacenan en la misma sesión interna que el programa en uso. Todas las áreas de datos están separadas entre sí, lo cual las mantiene protegidas. La gestión de datos en modelos procedimentales y orientados a objetos
Figura 10: La gestión de datos en modelos procedimentales y orientados a objetos
A diferencia de lo habitual en la programación procedimental, usar la instanciación múltiple en la programación orientada a objetos le permite crear una abstracción directa de un objeto real. La encapsulación se amplió sistemáticamente en este modelo de programación.
Objetos ABAP Los conceptos orientados a objetos de los objetos ABAP comparten los mismos conceptos de los de otros lenguajes modernos orientados a objetos como C++ o Java. Los conceptos que no han funcionado de manera satisfactoria no se incluyeron en los objetos ABAP. Por otro lado, los objetos ABAP también tienen elementos lingüísticos útiles que C++ y Java no ofrecen. Algunas funciones determinadas de los objetos ABAP solo existen gracias a la compatibilidad superior garantizada de elementos lingüísticos ABAP anteriores. La diferencia de los objetos ABAP en comparación con otros lenguajes orientados a objetos se encuentra en el entorno de desarrollo. Puede utilizar el rango completo de funciones del Workbench ABAP con objetos ABAP. Puede utilizar las sentencias de objetos ABAP en los programas ABAP procedimental.
8
© Copyright . Reservados todos los derechos.
Lección: Explicación del modelo de programación orientado a objetos
Los objetos ABAP como una extensión compatible de ABAP
Figura 11: Los objetos ABAP como una extensión compatible de ABAP
Los objetos ABAP no son un nuevo lenguaje, sino que fueron diseñados como una extensión sistemática de ABAP. Todas las extensiones, incluyendo las partes de proceso antiguas, son compatibles hacia arriba. Los controles de tipos de los contextos orientados a objetos de objetos ABAP son más estrictos que los realizados en los contextos de proceso. Para desarrollar los objetos ABAP, SAP depuró el lenguaje ABAP en los contextos orientados a objetos. Esto significa que las referencias obsoletas conducen a errores sintácticos.
Nota: Sin embargo, también es aconsejable evitar las referencias obsoletas en el entorno puramente de proceso, ya que crea códigos fuente más seguros y flexibles. De todas maneras, debido a que el lenguaje es compatible hacia arriba, no es posible prevenir el uso de estas referencias por completo. Para ver una lista de los elementos de lenguaje obsoletos, consulte la documentación de palabras clave ABAP. ABAP prohíbe el uso de las sentencias obsoletas en el contexto orientado a objetos. Relaciones cliente/servidor entre objetos
Figura 12: Relaciones de cliente/servidor entre objetos
© Copyright . Reservados todos los derechos.
9
Capítulo 1: Introducción a la programación orientada a objetos
Los objetos se comportan como sistemas de cliente/servidor. Cuando un objeto manda un mensaje a otro objeto para pedirle que se comporte de una manera determinada, el primer objeto puede verse como un cliente y el segundo como un servidor. Para poder separar solicitudes y entregas de servicios, deben cumplirse las siguientes condiciones: ● El objeto de cliente debe adherirse al protocolo de objeto de servidor. ●
El protocolo del objeto de servidor debe ser lo suficientemente claro para que un cliente potencial lo siga sin problemas.
Los objetos pueden realizar ambos roles de manera simultánea. Pueden ofrecer servicios a otros objetos mientras solicitan servicios al mismo tiempo. En la programación orientada a objetos, los servicios se distribuyen entre los objetos de manera que no haya redundancias y que cada objeto ofrezca exactamente los servicios que están en su área de responsabilidad. Si un objeto necesita otros servicios, lo solicita de otros objetos. Este concepto se conoce como el principio de delegación. Relación cliente/servidor: ejemplo El desarrollador debería implementar la tarea común de recuperación de datos y producir al menos dos objetos. Un objeto es responsable de la recuperación de datos y otro objeto es responsable de la salida. Siempre que el objeto de recuperación de datos no modifique su protocolo, el desarrollador podrá alterar la implementación interna del objeto de recuperación sin cambiar el otro objeto. O bien, un objeto diferente podría reemplazar el objeto de recuperación de datos siempre que el nuevo objeto utilice el mismo protocolo. Estos cambios también pueden realizarse en tiempo de ejecución. Conceptos adicionales del modelo de programación orientado a objetos
Figura 13: Conceptos adicionales del modelo de programación orientado a objetos
Estos son algunos conceptos adicionales del modelo de programación orientada a objetos: ● Herencia
10
© Copyright . Reservados todos los derechos.
Lección: Explicación del modelo de programación orientado a objetos
La herencia define las relaciones de implementación entre clases, de manera que una clase (la subclase) adopta, adapta o extiende la estructura y el comportamiento de otra clase (clase superior). ●
Polimorfismo El polimorfismo es cuando las instancias de diferentes clases responden de manera distinta a los mismos mensajes.
●
Control de eventos En lugar de mandar mensajes directamente a objetos específicos, los objetos también pueden desencadenar eventos. Luego otros objetos reaccionan cuando el evento se desencadena.
Características de ABAP orientado a objetos Las características clave del modelo de programación orientado a objetos de objetos ABAP son las siguientes: ●
Los objetos son una abstracción directa del mundo real.
●
Los objetos son unidades conformadas por datos y funciones.
●
Los procesos pueden implementarse mejor que en la programación procedimental.
Estas son las ventajas del modelo de programación orientado a objetos en comparación con el modelo de programación procedimental: ●
Estructura y consistencia de software mejoradas en el proceso de desarrollo
●
Trabajo de mantenimiento reducido y menor susceptibilidad a errores
●
●
Mejor integración del cliente o del usuario en el proceso de análisis, diseño y mantenimiento Ampliación del software más simple y segura
Se utiliza un lenguaje estándar en las distintas fases de desarrollo del software (análisis, especificación, diseño e implementación). Debido a esta estandarización, la comunicación es más fácil cuando cambia de una fase a la otra.
© Copyright . Reservados todos los derechos.
11
Capítulo 1: Introducción a la programación orientada a objetos
El proceso de desarrollo del software
Figura 14: El proceso de desarrollo del software
En la programación orientada a objetos, las decisiones de análisis y diseño tienen un efecto mayor en la implementación que el que tienen en la programación procedimental. Por lo tanto, debería utilizar el lenguaje o las herramientas de modelación para estandarizar la fase de análisis y diseño. RESUMEN DE LA LECCIÓN Ahora podrá: ●
●
12
Explicar las diferencias entre modelos de programación procedimental y orientada a objetos Describir objetos ABAP
© Copyright . Reservados todos los derechos.
Capítulo 1 Lección 2 Análisis y diseño con lenguaje unificado de modelado (UML)
RESUMEN DE LA LECCIÓN Este módulo explica cómo se desarrolla una solución orientada a objetos para un problema de aplicación empresarial. También explica cómo se clasifican sus objetos y define las relaciones entre ellos con las partes del lenguaje unificado de modelado (UML) como ayuda visual. Ejemplo empresarial Es necesario modelar un requisito de aplicación empresarial antes de implementar la aplicación empresarial. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de los diagramas de clase
●
Una buena comprensión de los diagramas de objeto
●
Una buena comprensión de los diagramas de secuencia
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Clasificar objetos
●
Modelar objetos y clases en UML
Clasificación de objetos
Figura 15: Clasificación de objetos
© Copyright . Reservados todos los derechos.
13
Capítulo 1: Introducción a la programación orientada a objetos
La programación orientada a objetos ve el mundo real como una colección de objetos; por ejemplo, aviones, coches y personas. Algunos de estos objetos son similares. En otras palabras, los objetos pueden describirse de la misma manera si utilizan las mismas características y muestran el mismo comportamiento. Puede agrupar todas las características y comportamientos de estos objetos similares en una clase central. Esta clase se utiliza para describir todos los objetos derivados de ella. Por lo tanto, una clase es una descripción de una cantidad de objetos que muestra las mismas características y el mismo comportamiento. Por ejemplo, el vehículo (marca x, ... serie n), es un objeto de la clase coche. Este objeto es una instancia concreta de su clase. Por lo tanto, tiene una identidad, un estado (número de instancias características) y un comportamiento. Los conceptos de identidad y estado son diferentes entre sí. La identidad es un atributo que distingue cada objeto de entre el resto de objetos de su clase. Dos objetos pueden tener valores de atributo idénticos pero no ser idénticos. Por ejemplo, dos tazas de café son iguales en altura, diámetro, asa y color. Aunque sus estados son completamente idénticos, se trata de dos tazas de café diferentes. La bibliografía acerca del tema de la programación orientada a objetos habla de instancias. El término instancia significa objeto.
Nota: El significado literal de la instancia es un poco más específico. Significa que la instancia de una clase es identificable de forma única. En este capítulo, distinguirá entre instancia y objeto. Clases como formas de abstracción
Figura 16: Clases como formas de abstracción
En un contexto de software, las abstracciones son simplificaciones de relaciones complejas en el mundo real. Puede abstraer un objeto real existente a las dimensiones necesarias para simular una sección determinada del mundo real. En la figura, los vehículos se utilizan para explicar el concepto de la abstracción. El software para un entusiasta del motor y el software
14
© Copyright . Reservados todos los derechos.
Lección: Análisis y diseño con lenguaje unificado de modelado (UML)
para un chatarrero contienen diferentes abstracciones (clases) para objetos. Por lo tanto, en función del tipo de abstracción, una clase puede contener aspectos distintos de un objeto. Comparación de clases y objetos
Figura 17: Comparación de clases y objetos
Una buena comprensión de la relación entre las clases y los objetos es un requisito previo para completar los siguientes módulos de manera satisfactoria. Modelación en UML UML es un lenguaje de modelado estandarizado globalmente. Lo utiliza para la especificación, construcción, visualización y documentación de los modelos de sistema de software. UML permite la comunicación uniforme entre usuarios. El UML es un estándar de la industria desarrollado por Object Management Group (OMG) en septiembre de 1997. SAP utiliza UML como el estándar de la empresa para la modelación orientada a objetos. Para más información sobre las especificaciones de UML, consulte http://www.omg.org en la página de inicio de OMG.
Diagramas de UML Los distintos tipos de diagrama en UML representan distintas vistas de un sistema. Estos son los tres tipos de diagrama importantes que representan las distintas vistas de un sistema: ●
Diagramas de clases Los diagramas de clase muestran las relaciones entre las clases. Es una vista estática de un modelo.
●
Diagramas de comportamiento
© Copyright . Reservados todos los derechos.
15
Capítulo 1: Introducción a la programación orientada a objetos
Los diagramas de comportamiento muestran las secuencia en la cual los objetos se relacionan entre sí. ●
Diagramas de componentes Los diagramas de componentes muestran la organización y las dependencias entre componentes.
Puede usar los objetos ABAP para implementar diagramas de clase y de comportamiento desde una perspectiva de programación. Los diagramas de componentes pueden obtenerse con el paquete de objetos de repository. Representación UML de una clase
Figura 18: Representación de una clase
Una clase se representa con un rectángulo en notación UML. Una clase puede representarse de las siguientes maneras: Nombre de la clase
●
●
Atributos de la clase (opcional)
●
Métodos de la clase (opcional)
Los atributos describen los datos que pueden almacenarse en los objetos de una clase. También determinan el status de un objeto. Los métodos describen las funciones que un objeto puede realizar. Determinan cómo se comporta un objeto.
16
© Copyright . Reservados todos los derechos.
Lección: Análisis y diseño con lenguaje unificado de modelado (UML)
Ejemplo de un diagrama de clases
Figura 19: Un ejemplo de diagrama de clase
Un diagrama de clases describe todas las relaciones estáticas entre las clases. Las formas básicas de relaciones estáticas son las siguientes: ● Asociación Un cliente encarga un coche en una compañía de vehículos de alquiler. ●
Generalización y especialización Un coche, un autobús y un camión son todos vehículos.
Nota: Las clases también pueden mostrarse en diagramas de clases con sus atributos y métodos. En este ejemplo de un diagrama de clase, estos atributos y métodos se han omitido para mejorar la claridad.
© Copyright . Reservados todos los derechos.
17
Capítulo 1: Introducción a la programación orientada a objetos
Asociación
Figura 20: Asociación
Una asociación describe una relación semántica entre clases. La relación específica entre objetos en estas clases se conoce como un enlace de objetos. Por lo tanto, los enlaces del objeto indican asociaciones. Sin embargo, una asociación también puede ser recursiva. En ese caso, la clase tendría una relación consigo misma. En la mayoría de los casos, las asociaciones recursivas se usar para enlazar dos objetos diferentes en la misma clase. Cada asociación tiene dos roles: uno para cada dirección de la asociación. Cada rol se describe con un nombre de asociación. Cada rol tiene una cardinalidad que muestra cuántas instancias pueden participar en esta relación. La multiplicidad es el número de objetos participantes en una clase que tienen una relación con un objeto de la otra clase. Como los demás elementos del modelo, las cardinalidades dependen de la situación concreta que se está modelando. En este ejemplo, también podría necesitar una cardinalidad de al menos una, para indicar que solo una persona que realmente realiza una reserva se convierte en cliente de la compañía de vehículos de alquiler. Por otro lado, la cardinalidad de cualquier número permitiría una definición más general de un cliente. Estas son las características de la asociación: Debe representar una asociación entre símbolos de clase dibujando una línea entre ellos.
●
●
●
●
18
Debe especificar la cardinalidad (también llamada multiplicidad) de la relación en el extremo de cada línea. Debe usar flechas para indicar las opciones de navegación. Debe escribir el nombre de la asociación en cursiva arriba de la línea. El nombre puede contener una flecha para indicar la dirección de lectura.
© Copyright . Reservados todos los derechos.
Lección: Análisis y diseño con lenguaje unificado de modelado (UML)
●
Indique los nombres de roles al final de las líneas si el modelador define los roles para ambos interlocutores.
Asociación con roles: ejemplo
Figura 21: Ejemplos de la asociación con roles
Puede usar nombres de roles al final de las líneas de asociación para describir las relaciones entre las clases implicadas. En el ejemplo, una persona podría aparecer en el rol de un empleado o en el rol de director de una empresa. En la asociación recursiva que se muestra en el ejemplo, los roles de hijo y padre se definen con nombres de rol. Las dos instancias de la clase LCL_PERSON tienen una relación entre ellas y representan dos roles. Clases de asociación
Figura 22: Clases de asociación
© Copyright . Reservados todos los derechos.
19
Capítulo 1: Introducción a la programación orientada a objetos
Si la asociación se usa para enlazar dos clases, una clase especial puede representar esta relación. Las características de la relación se describen con los atributos de la clase de asociación. Una línea de puntos conecta esta clase con la línea de asociación. Agregación y composición
Figura 23: Agregación y composición
La agregación y la composición son especializaciones de asociación. La agregación y la composición muestran que un objeto puede contener otros objetos. La relación puede describirse con las frases "está formado por" o "es una parte de". Por ejemplo, un coche está formado por ruedas, un motor, entre otras cosas. La agregación y la composición aparecen como una línea entre las dos clases. Se etiquetan con un rombo pequeño. El rombo indica la agregación o la composición. Por lo demás, las convenciones de notación son las mismas que usa para las asociaciones. La composición es una especialización de la agregación. Composición significa que el objeto contenido no puede existir sin el agregado (p. ej., una reserva de un coche no puede existir sin la compañía de vehículos de alquiler). Por lo tanto, la cardinalidad de este tipo de agregado es al menos uno. La vida útil de las partes individuales está relacionada con la vida útil del agregado. Esto significa que las partes se crean al mismo tiempo que el agregado o después del agregado, y se destruyen al mismo tiempo que el agregado o antes del agregado. En la notación UML, un rombo pintado significa composición.
20
© Copyright . Reservados todos los derechos.
Lección: Análisis y diseño con lenguaje unificado de modelado (UML)
Generalización y especialización
Figura 24: Generalización y especialización
Las relaciones de generalización y especialización son siempre bidireccionales. Por ejemplo, la clase lcl_truck puede generalizarse como una clase especial de lcl_vehicle. Las relaciones de generalización y especialización se representan con una flecha triangular. Esta flecha siempre apunta de la clase especializada a la clase más general. El nivel de generalización aumenta en la dirección de la flecha. Pueden construirse árboles utilizando estas relaciones.
Diagramas de objetos
Figura 25: Un diagrama de objetos
Un diagrama de objetos es una captura de imagen que se toma durante la ejecución del programa. Describe instancias de clases y las relaciones entre ellas. No es un nuevo tipo de
© Copyright . Reservados todos los derechos.
21
Capítulo 1: Introducción a la programación orientada a objetos
diagrama, sino una variante del diagrama de clase. Solo es útil para representar un diagrama de clase complejo.
Diagrama de secuencias
Figura 26: Un diagrama de secuencias
Los diagramas de secuencias se utilizan para mostrar ciertos procesos o situaciones. Una diagrama de secuencias describe la secuencia en la cual los objetos se procesan y la interacción que tienen unos con otros. Los diagramas de secuencia pueden mostrar los siguientes procesos: Cuando los objetos se crean o eliminan
●
●
Cuando los objetos intercambian mensajes
En notación UML, la línea vital del objeto se representa con líneas verticales punteadas con un cuadro que contiene el nombre del objeto en la parte superior. Una X se usa para indicar el final de la línea vital. El foco de control aparece como un rectángulo vertical en la línea vital del objeto. El foco de control muestra el período activo del objeto. Los usos posibles de los objeto son los siguientes: Un objeto está activo cuando se ejecutan las acciones.
●
●
Un objeto está activo de manera indirecta si está esperando que termine un procedimiento subordinado.
Los mensajes aparecen como flechas horizontales entre las líneas de objeto. El mensaje se escribe encima de la flecha en el formato Mensaje (parámetro). Hay varias maneras de representar la respuesta. En este ejemplo, aparece como una flecha de regreso puntuada. También es posible incluir una descripción del proceso y añadir comentarios a la línea vital del objeto.
22
© Copyright . Reservados todos los derechos.
Lección: Análisis y diseño con lenguaje unificado de modelado (UML)
El principio de delegación
Figura 27: Principio de delegación en el diagrama de secuencias
En la delegación, dos objetos participan en el tratamiento de una solicitud. El destinatario de la solicitud asigna la ejecución de la solicitud a un representante. En este ejemplo, el conductor (objeto CONDUCTOR) envía el mensaje get_fuel_level ( ) al vehículo (objeto COCHE). Cuando el mensaje se recibe, el coche envía un mensaje al depósito (objeto DEPOSITO) para averiguar lo que contiene el depósito. En otras palabras, el coche delega la tarea al depósito. Si es necesario, el coche formatea la información que contiene el valor actual de los contenidos del depósito antes de enviarlo de regreso al conductor.
© Copyright . Reservados todos los derechos.
23
Capítulo 1: Introducción a la programación orientada a objetos
24
© Copyright . Reservados todos los derechos.
Capítulo 1 Ejercicio 1 Crear diagramas de UML
Ejemplo empresarial Usted es un fabricante de modelos para una empresa aérea propietaria de varias compañías aéreas. Necesita crear un modelo simple para administrar sus compañías aéreas y aviones. Por este motivo, debe tener la capacidad de diseñar diagramas de clase UML simples y modelar objetos básicos. En este modelo de administración de aviones, necesita crear clases relevantes con atributos y métodos, y definir la asociación entre las clases con tipos de asociación y cardinalidades adecuadas. Tarea 1 1. Cree un diagrama de clases UML con las siguientes clases: Nombre de clase
Descripción
LCL_CARRIER
Para las compañías aéreas
LCL_AIRPLANE
Para aviones (no especificado)
LCL_PASSENGER_PLANE
Para los aviones de pasajeros
LCL_CARGO_PLANE
Para los aviones de carga
2. Cree atributos y métodos adecuados para cada clase. 3. Defina las relaciones entre sus clases y elija los tipos de asociación adecuados. 4. Seleccione cardinalidades adecuadas. Tarea 2 Como modelador, decide si los diagramas de objeto de esta unidad son correctos. 1. La figura muestra un diagrama de clase. Se dibujan ocho diagramas de objetos para este diagrama de clases. Decida si un diagrama de objeto es correcto y marque la casilla de selección correspondiente para indicar su respuesta.
© Copyright . Reservados todos los derechos.
25
Capítulo 1: Introducción a la programación orientada a objetos
Figura 29: Diagramas de objetos posibles (1)
Consulte más diagramas en la figura Diagramas de objetos posibles (2).
Figura 30: Diagramas de objetos posibles (2)
26
© Copyright . Reservados todos los derechos.
Capítulo 1 Solución 1 Crear diagramas de UML
Ejemplo empresarial Usted es un fabricante de modelos para una empresa aérea propietaria de varias compañías aéreas. Necesita crear un modelo simple para administrar sus compañías aéreas y aviones. Por este motivo, debe tener la capacidad de diseñar diagramas de clase UML simples y modelar objetos básicos. En este modelo de administración de aviones, necesita crear clases relevantes con atributos y métodos, y definir la asociación entre las clases con tipos de asociación y cardinalidades adecuadas. Tarea 1 1. Cree un diagrama de clases UML con las siguientes clases: Nombre de clase
Descripción
LCL_CARRIER
Para las compañías aéreas
LCL_AIRPLANE
Para aviones (no especificado)
LCL_PASSENGER_PLANE
Para los aviones de pasajeros
LCL_CARGO_PLANE
Para los aviones de carga
a) Utilice la solución modelo como guía. 2. Cree atributos y métodos adecuados para cada clase. a) Asegúrese de definir los atributos generales y los métodos para aviones en LCL_AIRPLANE. b) Use la solución del modelo como guía para los atributos y los métodos de todas las clases requeridas. 3. Defina las relaciones entre sus clases y elija los tipos de asociación adecuados. a) Una relación de generalización y especialización entre LCL_AIRPLANE y LCL_PASSENGER_PLANE o LCL_CARGO_PLANE parece adecuada. Cree un agregado entre LCL_AIRPLANE y LCL_CARRIER. b) Utilice la solución modelo como guía. 4. Seleccione cardinalidades adecuadas. a) Puede usar distintas cardinalidades en este caso. Utilice las secciones relevantes de la unidad y la solución modelo como guía.
© Copyright . Reservados todos los derechos.
27
Capítulo 1: Introducción a la programación orientada a objetos
Figura 28: Diagrama de clases para ejercicio: CARRIER/AIRPLANE
Tarea 2 Como modelador, decide si los diagramas de objeto de esta unidad son correctos. 1. La figura muestra un diagrama de clase. Se dibujan ocho diagramas de objetos para este diagrama de clases. Decida si un diagrama de objeto es correcto y marque la casilla de selección correspondiente para indicar su respuesta.
Figura 29: Diagramas de objetos posibles (1)
Consulte más diagramas en la figura Diagramas de objetos posibles (2).
28
© Copyright . Reservados todos los derechos.
Lección: Análisis y diseño con lenguaje unificado de modelado (UML)
Figura 30: Diagramas de objetos posibles (2)
a) Los diagramas de objetos número 2; 4; 5; 6 y 8 son correctos.
© Copyright . Reservados todos los derechos.
29
Capítulo 1: Introducción a la programación orientada a objetos
RESUMEN DE LA LECCIÓN Ahora podrá:
30
●
Clasificar objetos
●
Modelar objetos y clases en UML
© Copyright . Reservados todos los derechos.
Capítulo 1 Evaluación de la formación
1. Los datos y las funciones se mantienen separados en el modelo de programación procedimental. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
2. Cuando el programa principal llama un módulo de función, solo este módulo de función se carga en la sesión interna. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
3. ¿Qué significa la instanciación múltiple? Seleccione la respuesta correcta. X
A Creación y gestión de instancias del tiempo de ejecución
X
B Implementación de relaciones entre las clases
X
C Creación de instancias de distintas clases
X
D Envío de mensaje directamente a los objetos específicos al desencadenar eventos
4. De las siguientes opciones, ¿cuál describe la forma en que las instancias de diferentes clases responden de manera distinta a los mismos mensajes? Seleccione la respuesta correcta. X
A Herencia
X
B Polimorfismo
X
C Encapsulación
X
D Control de eventos
© Copyright . Reservados todos los derechos.
31
Capítulo 1: Evaluación de la formación
5. De las siguientes opciones, ¿cuál es una simplificación de las relaciones complejas en el mundo real? Seleccione la respuesta correcta. X
A Herencia
X
B Abstracción
X
C Encapsulación
X
D Control de eventos
6. El diagrama ______________ presta atención especial a la secuencia en la que los objetos se relacionan entre sí. Seleccione la respuesta correcta. X
A clase
X
B de comportamiento
X
C componente
X
D objeto
7. Puede agrupar todas las características y conductas de objetos similares en una clase central. Indique si esta afirmación es verdadera o falsa.
32
X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
Capítulo 1 Respuestas a la Evaluación de la formación
1. Los datos y las funciones se mantienen separados en el modelo de programación procedimental. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
2. Cuando el programa principal llama un módulo de función, solo este módulo de función se carga en la sesión interna. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
3. ¿Qué significa la instanciación múltiple? Seleccione la respuesta correcta. X
A Creación y gestión de instancias del tiempo de ejecución
X
B Implementación de relaciones entre las clases
X
C Creación de instancias de distintas clases
X
D Envío de mensaje directamente a los objetos específicos al desencadenar eventos
4. De las siguientes opciones, ¿cuál describe la forma en que las instancias de diferentes clases responden de manera distinta a los mismos mensajes? Seleccione la respuesta correcta. X
A Herencia
X
B Polimorfismo
X
C Encapsulación
X
D Control de eventos
© Copyright . Reservados todos los derechos.
33
Capítulo 1: Respuestas a la Evaluación de la formación
5. De las siguientes opciones, ¿cuál es una simplificación de las relaciones complejas en el mundo real? Seleccione la respuesta correcta. X
A Herencia
X
B Abstracción
X
C Encapsulación
X
D Control de eventos
6. El diagrama ______________ presta atención especial a la secuencia en la que los objetos se relacionan entre sí. Seleccione la respuesta correcta. X
A clase
X
B de comportamiento
X
C componente
X
D objeto
7. Puede agrupar todas las características y conductas de objetos similares en una clase central. Indique si esta afirmación es verdadera o falsa.
34
X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
CAPÍTULO 2
Sintaxis fundamental orientada a objetos
Lección 1 Creación de clases locales Ejercicio 2: Crear clases locales
37 49
Lección 2 Creación y trabajos con objetos Ejercicio 3: Crear objetos
55 61
Lección 3 Acceso a métodos y atributos Ejercicio 4: Llamar métodos
65 71
Lección 4 Implementación de constructores en clases locales Ejercicio 5: Crear y utilizar constructores
77 81
Lección 5 Implementación de constructores de clases en clases locales Ejercicio 6: Crear y utilizar constructores estáticos
88 91
OBJETIVOS DEL CAPÍTULO ●
Definir clases locales
●
Definir atributos
●
Crear métodos
●
Crear objetos
●
Tratar objetos
●
Llamar métodos de instancia
●
Llamar métodos estáticos
●
Llamar métodos funcionales
© Copyright . Reservados todos los derechos.
35
Capítulo 2: Sintaxis fundamental orientada a objetos
36
●
Acceder a atributos públicos
●
Crear y utilizar constructores
●
Crear y utilizar constructores estáticos
© Copyright . Reservados todos los derechos.
Capítulo 2 Lección 1 Creación de clases locales
RESUMEN DE LA LECCIÓN Este módulo proporciona un resumen de las clases locales, los atributos y los métodos que son los elementos de sintaxis fundamentales orientados a objetos. Ejemplo empresarial Como desarrollador, desea implementar clases, objetos y asociaciones de su modelo en los objetos ABAP. OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Definir clases locales
●
Definir atributos
●
Crear métodos
Definición de clases locales
Figura 31: Un ejemplo de una clase
El concepto de clases es la base de la programación orientada a objetos. Una clase puede tener componentes públicos o componentes privados. Puede acceder a componentes públicos, como los métodos y los eventos, desde fuera de una clase. Sin embargo, no puede acceder a componentes privados, como los atributos y tipos de datos, desde fuera de una clase.
© Copyright . Reservados todos los derechos.
37
Capítulo 2: Sintaxis fundamental orientada a objetos
La figura muestra un vehículo como ejemplo de una clase. Características de una clase
Figura 32: Definición de clases
Estas son las características de una clase en la programación orientada a objetos: ● Una clase es un conjunto de objetos que tienen la misma estructura y presentan el mismo comportamiento. ●
●
●
Una clase proporciona un diagrama de todos los objetos basados en esta clase. Una clase está compuesta por componentes, como atributos, métodos, eventos, constantes, tipos e interfaces implementadas y definidas en la sección de definición. Solo puede implementar los métodos en la sección de implementación. Una sentencia de clase no puede anidarse; es decir, no puede definir una clase dentro de una clase. Sin embargo, puede definir las clases auxiliares locales para las clases globales.
Declaración de atributos de clase
Figura 33: Un ejemplo de atributos
Los atributos contienen los datos que pueden almacenarse en los objetos de una clase.
38
© Copyright . Reservados todos los derechos.
Lección: Creación de clases locales
Los tipos de atributos de clase son los siguientes: Elemental
●
●
Estructurado
●
Tipo de tabla
Los atributos pueden consistir en tipos de datos (locales o globales) o tipos de referencia. La tabla siguiente muestra algunos ejemplos de los atributos de la clase LCL_VEHICLE: Atributos
Descripción
MAKE
Marca del vehículo
MODEL
Tipo de modelo
SER_NO
Número de serie
COLOR
Color
MAX_SEATS
Número de asientos
R_MOTOR
Referencia a la clase LCL_MOTOR
Definición de atributos, tipos y constantes
Figura 34: Definición de atributos, tipos y constantes
En las sentencias DATA de las clases, solo puede utilizar el suplemento TYPE para hacer referencia a los tipos de datos. El suplemento LIKE solo está permitido para objetos de datos locales o campos SY (por ejemplo SY-DATE, SY-UNAME, etc.). El suplemento READ-ONLY indica si un atributo público declarado con DATA puede leerse desde el exterior. Sin embargo, el atributo solo puede modificarse mediante métodos en la misma clase. Actualmente, puede utilizar el suplemento READ-ONLY en la sección de
© Copyright . Reservados todos los derechos.
39
Capítulo 2: Sintaxis fundamental orientada a objetos
visibilidad pública (PUBLIC SECTION) de una declaración de clase o en una definición de interfaz. Con TYPE REF TO, puede indicar un atributo como una referencia. La sentencia CONSTANTS se utiliza en la definición de clase para definir los objetos de datos que tienen un valor constante. Si utiliza la sentencia TYPES en la definición de clase, declara un tipo local específico a la clase local. Puede crear un tipo local para que lo utilicen uno u más atributos dentro de la misma clase.
Visibilidad de los atributos
Figura 35: Secciones de visibilidad de atributos
Los atributos privados no pueden abordarse directamente desde la clase exterior y no son visibles para los usuarios externos. Puede proteger los atributos del acceso desde el exterior al caracterizarlos como atributos privados. Nota: El concepto de amistad es una excepción de esta regla. Los atributos públicos son atributos visibles para todos los usuarios y los usuarios externos pueden acceder directamente a ellos. Del mismo modo, las constantes y los tipos definidos por una clase pueden ser privados (para el uso dentro de la clase) o públicos (es posible acceder a ellos desde el exterior de la clase). Los componentes públicos de una clase se conocen de manera colectiva como la interfaz de la clase. El uso de la sección de visibilidad privada también se conoce como la supresión de información o encapsulación. La encapsulación protege al usuario de la clase al realizar cambios en los componentes privados que no puede ver el usuario externo. Puede modificar los componentes privados de una clase sin cambiar la interfaz. Asuma que los componentes privados de una clase se modifican en cierto punto con su interfaz igual, los
40
© Copyright . Reservados todos los derechos.
Lección: Creación de clases locales
usuarios externos pueden seguir trabajando con la clase tal como lo hacían antes. Los usuarios externos solo pueden acceder a los componentes a través de la interfaz de una clase y no notarán los cambios de implementación internos en las PRIVATE SECTIONS. Sin embargo, cuando cambian los componentes públicos de una clase, cada usuario externo debe tener en cuenta esos cambios. Por lo tanto, utilice los atributos públicos con moderación o evitando realizar cambios no compatibles en todos los componentes públicos. Acceso a atributos privados
Figura 36: Acceso a atributos privados
Los atributos privados se definen en la PRIVATE SECTION de una clase. Los atributos públicos se definen en la PUBLIC SECTION de una clase. Es sintácticamente imposible acceder directamente a atributos privados desde el exterior. Sin embargo, puede acceder a los atributos privados con métodos públicos que devuelven o cambian los valores de los atributos privados. El requisito de tiempo de ejecución ligeramente superior (llamadas de método en comparación con asignación directa de valor) se tiene en cuenta para satisfacer el concepto de encapsulación. La firma del método público establece claramente qué valores deben o pueden transferirse, y qué tipos deben ser asignados a cada valor. La firma de un método público obliga al usuario externo a utilizar los tipos correctos. Este método también garantiza que se trabaja de forma uniforme con todos los atributos privados. En el ejemplo de la figura, si los atributos MAKE y MODEL son públicos, será muy arriesgado porque el usuario puede olvidarse de suministrar los atributos o de especificar los atributos no uniformes. Para implementar esta situación, puede utilizar un método público SET_TYPE para asegurarse de que se especifican valores para ambos atributos. Una sintaxis estricta verifica las llamadas de método que prevalecen, lo cual garantiza la transferencia de todos los parámetros requeridos. Un método puede realizar una verificación de consistencia (para ver si un vehículo determinado produce el modelo seleccionado) y emitir una excepción si se produce un error. Para minimizar el tiempo de ejecución, pueden definirse atributos individuales en la sección de visibilidad pública, pero debe darles después el suplemento READ-ONLY.
© Copyright . Reservados todos los derechos.
41
Capítulo 2: Sintaxis fundamental orientada a objetos
Atributos estáticos y atributos de instancia
Figura 37: Comparación de atributos de instancia con atributos estáticos
A continuación se detallan distintos tipos de atributos: Atributos de instancia
●
Los atributos de instancia existen una vez por objeto, es decir, una vez por instancia de tiempo de ejecución de la clase. Define los atributos de instancia con el elemento sintáctico DATA. ●
Atributos estáticos Los atributos estáticos existen una vez para cada clase y son visibles para todas las instancias de tiempo de ejecución de esta clase. Define los atributos estáticos con el elemento sintáctico CLASS-DATA. Los atributos estáticos, por lo general, contienen la siguiente información que se aplica a todas las instancias: Tipos y constantes -
Memoria intermedia de datos de aplicación central
-
Información administrativa, como el contador de instancias
La documentación técnica hace referencia a los atributos estáticos como “atributos de clase” (utilizamos el elemento sintáctico CLASS-DATA). Al igual que en C++ y Java, los objetos ABAP utilizan el término oficial "atributo estático".
42
© Copyright . Reservados todos los derechos.
Lección: Creación de clases locales
Atributos de instancia y atributos estáticos en el contexto de programa
Figura 38: Atributos de instancia y atributos estáticos en el contexto de programa
La figura muestra un ejemplo de cómo el atributo estático N_O_VEHICLES se relaciona con otros elementos de programa en la memoria. El atributo estático solo existe una vez en la clase cargada sin tener en cuenta el número de instancias de LCL_VEHICLE. Por lo tanto, puede decir que las instancias comparten atributos estáticos.
Atención: Un objeto de datos enteros se define para contar las instancias. No es posible determinar la cantidad de instancias creadas desde el sistema.
© Copyright . Reservados todos los derechos.
43
Capítulo 2: Sintaxis fundamental orientada a objetos
Implementación de métodos
Figura 39: Sintaxis para métodos
Estas son algunas de las características clave de los métodos: ●
●
●
Los métodos son los procesos internos de las clases que determinan el comportamiento de los objetos. Pueden tener acceso a todos los atributos de su clase y, por lo tanto, pueden cambiar el estado de los atributos. Los métodos tienen una firma (parámetros y excepciones de interfaz) que les permite recibir valores cuando se llaman y devolver valores al programa de llamada. Los métodos pueden tener cualquier número de parámetros IMPORTING, EXPORTING y CHANGING. Todos los parámetros pueden ser transmitidos por valor o referencia.
Firma de método Un valor de retorno puede definirse en el método con el parámetro RETURN. Cuando utiliza un parámetro RETURNING, no puede utilizar EXPORTING y CHANGING de manera simultánea. También puede utilizar el parámetro RETURNING para definir métodos funcionales. Puede definir todos los parámetros de entrada (parámetros IMPORTING y CHANGING) como parámetros opcionales en la declaración mediante los suplementos OPTIONAL o DEFAULT. No es necesario transferir estos parámetros cuando llama el objeto. Al utilizar el suplemento OPTIONAL, el parámetro se inicializa según el tipo, mientras que el suplemento DEFAULT le permite introducir un valor de inicio. Los métodos también admiten el valor de retorno SY-SUBRC, pero solo cuando define las excepciones de firma con el uso de EXCEPTIONS. A partir de SAP AS 6.10, puede utilizar el suplemento RAISING en lugar de EXCEPTIONS para propagar las excepciones basadas en
44
© Copyright . Reservados todos los derechos.
Lección: Creación de clases locales
clase. El programa de llamada trata estas excepciones basadas en clases sin evaluar el código de retorno SY-SUBRC.
Nota: No utilice ambos conceptos juntos en un programa.
Visibilidad de métodos
Figura 40: Secciones de visibilidad de métodos
Asigna métodos a una sección de visibilidad para determinar si los métodos se llaman desde fuera o dentro de la clase. Los métodos privados permiten la modularización interna. Acceder a métodos privados
Figura 41: Acceso a métodos privados
© Copyright . Reservados todos los derechos.
45
Capítulo 2: Sintaxis fundamental orientada a objetos
Define los métodos privados en la PRIVATE SECTION y los métodos públicos en la PUBLIC SECTION de una clase. No es posible tener acceso directo a métodos privados desde el exterior. Sin embargo, un método privado puede ser llamado por un método público. En el ejemplo que se muestra en la figura, INIT_TYPE es un método privado que se llama con el método público SET_TYPE. Definir este método auxiliar privado es útil porque la instrucción para inicializar atributos puede utilizarse en otros métodos.
Nota: Se trata de un ejemplo introductorio. Más adelante, aprenderá más técnicas de programación para evaluar parámetros formales. En una clase, las declaraciones de nombres de atributo, los nombres de método, los nombres de evento, los nombres de constante, los nombres de tipo y los nombres alias comparten la misma área de nombres. Además, hay un área de nombres local dentro de los métodos. Las declaraciones locales dentro de un método anulan las declaraciones realizadas en la clase.
Métodos estáticos y métodos de instancia
Figura 42: Comparación de métodos de instancia con métodos estáticos
A continuación se detallan los distintos tipos de métodos: ● Métodos de instancia Define los métodos de instancia mediante la palabra clave METHODS. ●
Métodos estáticos Define los métodos estáticos mediante la palabra clave CLASS-METHODS. Define los métodos estáticos en el nivel de clase. Sin embargo, solo puede acceder a los componentes estáticos de la sección de implementación. Esto significa que los métodos estáticos no necesitan instancias y es posible acceder a ellos a través de la clase.
46
© Copyright . Reservados todos los derechos.
Lección: Creación de clases locales
En el ejemplo que se muestra en la figura, solo puede acceder al atributo estático N_O_VEHICLES dentro del método estático GET_N_O_VEHICLES. El resto de atributos son atributos de instancia y solo pueden aparecer dentro de los métodos de instancia. La documentación técnica se refiere a menudo a los atributos estáticos como “atributos de clase” (compárese con el elemento sintáctico CLASS-METHODS). En objetos ABAP el término oficial es "método estático" como en C++ y Java.
Comparación del diagrama de clase UML con la implementación
Figura 43: Secciones de visibilidad y notación UML
Un diagrama de clase del lenguaje unificado de modelado (UML) detalla el nombre de clase, los atributos de clase y los métodos. Los componentes de una clase se muestran en un UML con las siguientes notaciones: Signo más (+)
●
Un signo más (+) indica componentes públicos (visible para todos los usuarios). ●
Signo menos (-) Un signo menos (-) indica componentes privados (no visibles para usuarios externos).
●
Subrayado Un signo de nombre de componente subrayado (_) indica componentes estáticos.
O bien, pueden utilizarse las palabras clave público y privado como prefijo para los métodos. UML también permite a los fabricantes de herramientas de modelación crear sus propios símbolos de mayor visibilidad. El uso de características de visibilidad es opcional y se utiliza normalmente solo en modelos que están cerca de la implementación.
© Copyright . Reservados todos los derechos.
47
Capítulo 2: Sintaxis fundamental orientada a objetos
48
© Copyright . Reservados todos los derechos.
Capítulo 2 Ejercicio 2 Crear clases locales
Ejemplo empresarial Usted es un programador de una corporación aérea propietaria de varias compañías aéreas. Necesita desarrollar un programa orientado a objetos que pueda gestionar las compañías aéreas. Por este motivo, debe tener la capacidad de definir clases, atributos y métodos. Modelo: Ninguno Solución: SAPBC401_BAS_S1 Tarea 1 Cree un programa ejecutable sin include TOP (nombre sugerido:ZBC401_##_MAIN donde ## es su número de grupo de 2 dígitos). Tarea 2 Declare e implemente una clase para aviones. 1. Dentro de su programa, declare la clase local LCL_AIRPLANE. 2. Defina los siguientes atributos: Nombre de atributo/descripción
Tipo de datos
Tipo de atributo
MV_NAME (nombre del avión)
STRING
Atributo de instancia privada
MV_PLANETYPE (tipo de avión)
SAPLANE -PLANETYPE
Atributo de instancia privada
GV_N_O_AIRPLANES (contador de instancias)
I
Atributo estático privado
3. Defina el método de instancia público SET_ATTRIBUTES para fijar atributos de instancia privados. La firma del método debe de constar de dos parámetros import adecuados, compatibles con los dos atributos definidos. Implemente el método de manera que los dos atributos de instancia estén fijados. 4. Defina el método de instancia público DISPLAY_ATTRIBUTES para visualizar atributos de instancia privados. Implemente el método de manera que los valores de los dos atributos de instancia se emitan como una lista ABAP. También puede dar salida a iconos si el grupo de tipo ICON está cargado.
© Copyright . Reservados todos los derechos.
49
Capítulo 2: Sintaxis fundamental orientada a objetos
Consejo: Para cargar el grupo del tipo, utilice el icono de la sentencia TYPE-POOLS.
Nota: Para cumplir el principio de delegación, la lectura de los valores de atributo y su salida no deberían implementarse en el mismo método. Sin embargo, por razones de tiempo, puede ignorar el principio de delegación de este ejercicio. 5. Defina el método estático público DISPLAY_N_O_AIRPLANES para visualizar los atributos estáticos privados. Implemente el método de manera que el valor de los atributos estáticos se emita en la lista ABAP. Nota: Hasta aquí, su clase no dispone de un mecanismo para garantizar que el contador de instancias aumente cada vez que se crea un objeto. Decida si desea omitir el contador por ahora o controlar temporalmente los incrementos con el método SET_ATTRIBUTES. 6. Para mejorar la salida de la lista, organice la salida en dos columnas, una para el texto descriptivo y la otra para los valores de atributo. Consejo: Utilice el suplemento AT
de la sentencia WRITE para ubicar la salida en la columna determinada. Para facilitar los ajustes posteriores, no utilice un para el número. En cambio, defina la constante privada C_POS_1.
50
© Copyright . Reservados todos los derechos.
Capítulo 2 Solución 2 Crear clases locales
Ejemplo empresarial Usted es un programador de una corporación aérea propietaria de varias compañías aéreas. Necesita desarrollar un programa orientado a objetos que pueda gestionar las compañías aéreas. Por este motivo, debe tener la capacidad de definir clases, atributos y métodos. Modelo: Ninguno Solución: SAPBC401_BAS_S1 Tarea 1 Cree un programa ejecutable sin include TOP (nombre sugerido:ZBC401_##_MAIN donde ## es su número de grupo de 2 dígitos). Tarea 2 Declare e implemente una clase para aviones. 1. Dentro de su programa, declare la clase local LCL_AIRPLANE. a) Véase el extracto del código fuente de la solución modelo. 2. Defina los siguientes atributos: Nombre de atributo/descripción
Tipo de datos
Tipo de atributo
MV_NAME (nombre del avión)
STRING
Atributo de instancia privada
MV_PLANETYPE (tipo de avión)
SAPLANE -PLANETYPE
Atributo de instancia privada
GV_N_O_AIRPLANES (contador de instancias)
I
Atributo estático privado
a) Véase el extracto del código fuente de la solución modelo. 3. Defina el método de instancia público SET_ATTRIBUTES para fijar atributos de instancia privados. La firma del método debe de constar de dos parámetros import adecuados, compatibles con los dos atributos definidos. Implemente el método de manera que los dos atributos de instancia estén fijados. a) Véase el extracto del código fuente de la solución modelo. 4. Defina el método de instancia público DISPLAY_ATTRIBUTES para visualizar atributos de instancia privados.
© Copyright . Reservados todos los derechos.
51
Capítulo 2: Sintaxis fundamental orientada a objetos
Implemente el método de manera que los valores de los dos atributos de instancia se emitan como una lista ABAP. También puede dar salida a iconos si el grupo de tipo ICON está cargado. Consejo: Para cargar el grupo del tipo, utilice el icono de la sentencia TYPE-POOLS.
Nota: Para cumplir el principio de delegación, la lectura de los valores de atributo y su salida no deberían implementarse en el mismo método. Sin embargo, por razones de tiempo, puede ignorar el principio de delegación de este ejercicio. a) Véase el extracto del código fuente de la solución modelo. 5. Defina el método estático público DISPLAY_N_O_AIRPLANES para visualizar los atributos estáticos privados. Implemente el método de manera que el valor de los atributos estáticos se emita en la lista ABAP. Nota: Hasta aquí, su clase no dispone de un mecanismo para garantizar que el contador de instancias aumente cada vez que se crea un objeto. Decida si desea omitir el contador por ahora o controlar temporalmente los incrementos con el método SET_ATTRIBUTES. a) Véase el extracto del código fuente de la solución modelo. 6. Para mejorar la salida de la lista, organice la salida en dos columnas, una para el texto descriptivo y la otra para los valores de atributo. Consejo: Utilice el suplemento AT de la sentencia WRITE para ubicar la salida en la columna determinada. Para facilitar los ajustes posteriores, no utilice un para el número. En cambio, defina la constante privada C_POS_1. a) Véase el extracto del código fuente de la solución modelo. Solución: SAPBC401_BAS_S1 REPORT sapbc401_bas_s1. TYPE-POOLS icon. *--------------------------------------------------------* * CLASS lcl_airplane DEFINITION * *--------------------------------------------------------* CLASS lcl_airplane DEFINITION.
52
© Copyright . Reservados todos los derechos.
Lección: Creación de clases locales
PUBLIC SECTION. METHODS: set_attributes IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype, display_attributes. CLASS-METHODS: display_n_o_airplanes. PROTECTED SECTION. PRIVATE SECTION. CONSTANTS: c_pos_1 TYPE i VALUE 30. DATA: mv_name TYPE string, mv_planetype TYPE saplane-planetype. CLASS-DATA: gv_n_o_airplanes TYPE i. ENDCLASS. "lcl_airplane DEFINITION *--------------------------------------------------------* * CLASS lcl_airplane IMPLEMENTATION * *--------------------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. METHOD set_attributes. mv_name = iv_name. mv_planetype = iv_planetype. * doesn't make sense so much, only in order to get an effect * after calling display_n_o_airplanes: gv_n_o_airplanes = gv_n_o_airplanes + 1. ENDMETHOD. "set_attributes METHOD display_attributes. DATA: lv_weight TYPE saplane-weight, lv_cap TYPE saplane-tankcap. WRITE: / icon_ws_plane AS ICON, / 'Name of Airplane'(001) , AT c_pos_1 mv_name, / 'Type of Airplane:'(002), AT c_pos_1 mv_planetype. ENDMETHOD. "display_attributes METHOD display_n_o_airplanes. SKIP. WRITE: / 'Number of airplanes:'(ca1), AT c_pos_1 gv_n_o_airplanes LEFT-JUSTIFIED. ENDMETHOD. "display_n_o_airplanes ENDCLASS. "lcl_airplane IMPLEMENTATION
© Copyright . Reservados todos los derechos.
53
Capítulo 2: Sintaxis fundamental orientada a objetos
RESUMEN DE LA LECCIÓN Ahora podrá:
54
●
Definir clases locales
●
Definir atributos
●
Crear métodos
© Copyright . Reservados todos los derechos.
Capítulo 2 Lección 2 Creación y trabajos con objetos
RESUMEN DE LA LECCIÓN Este módulo explica el concepto de creación y tratamiento de objetos. Ejemplo empresarial Como desarrollador, desea crear múltiples instancias para la clase local que ha creado en su proyecto de objetos ABAP. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de cómo crear objetos
●
Una buena comprensión de cómo tratar objetos
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Crear objetos
●
Tratar objetos
Objetos como instancias de clases
Figura 44: Resumen de instancias de clases
Una clase tiene la descripción genérica de un objeto y describe todas las características que todos los objetos de la clase tienen en común. Durante el tiempo de ejecución del programa, usa la clase para crear objetos discretos (instancias) en la memoria. Este proceso se llama instanciación. Cuando accede a la clase por primera vez, se carga en la memoria. Consejo: Aunque puede usar clases y componentes estáticos para escribir aplicaciones completas, el motivo para usar programación orientada a objectos es para crear y trabajar con instancias de tiempo de ejecución de clases.
© Copyright . Reservados todos los derechos.
55
Capítulo 2: Sintaxis fundamental orientada a objetos
Definición de variables de referencia
Figura 45: Definición de variables de referencia
Para definir una variable de referencia, utilice DATA go_vehicle1 TYPE REF TO lcl_vehicle, que se indica como puntero de objetos del tipo lcl_vehicle. La referencia nula es el valor inicial de una variable de referencia. Creación de objetos
Figura 46: Creación de objetos
La sentencia CREATE OBJECT crea un objeto en la memoria. Los valores de atributo de objeto son iniciales o se asignan de acuerdo con la especificación VALUE.
56
© Copyright . Reservados todos los derechos.
Lección: Creación y trabajos con objetos
Semántica de referencia de referencias de objeto
Figura 47: Semántica de referencia de referencias de objeto
Las variables de referencia de objeto pueden asignarse unas a otras. La figura ilustra un ejemplo en el cual, después de la sentencia MOVE, GO_VEHICLE1 y GO_VEHICLE2 apuntan al mismo objeto.
Recolector de basura
Figura 48: El recolector de basura
Las referencias independientes son referencias que no han sido definidas dentro de una clase. El recolector de basura es una rutina que se inicia automáticamente siempre que el sistema de tiempo de ejecución no tenga tareas más importantes por realizar. En este ejemplo, la referencia al objeto (2)LCL_OBJECT está inicializada. Sin embargo, no hay un punto de referencia posterior a este objeto. Por ello, el recolector de basura borra el objeto
© Copyright . Reservados todos los derechos.
57
Capítulo 2: Sintaxis fundamental orientada a objetos
que no tiene referencia. Debido a que no hay un punto de referencia para el objeto (4) LCL_OBJECT, también se elimina. Puede utilizar la consulta lógica IF go_obj IS INITIAL para determinar si r_obj tiene la referencia nula o si no apunta a ningún objeto.
Instancias múltiples
Figura 49: Administración de referencia con instanciación múltiple
Para mantener varios objetos de la misma clase en su programa, puede definir una tabla interna que contenga una columna con las referencias de objeto para esta clase. Para actualizar estos objetos en la tabla, puede utilizar las sentencias para tablas internas, como APPEND, READ o LOOP.
58
© Copyright . Reservados todos los derechos.
Lección: Creación y trabajos con objetos
Ejemplo de agregación
Figura 50: Ejemplo de agregación
Los objetos de la clase LCL_WHEEL tienen su propia identidad. Puede crear objetos, sin importar la existencia de un objeto en la clase LCL_VEHICLE. Las referencias se transfieren a objetos de la clase LCL_VEHICLE para crear la asociación deseada.
© Copyright . Reservados todos los derechos.
59
Capítulo 2: Sintaxis fundamental orientada a objetos
60
© Copyright . Reservados todos los derechos.
Capítulo 2 Ejercicio 3 Crear objetos
Ejemplo empresarial Como desarrollador, crea instancias de su clase de avión y asegúrese de que no se pierdan las referencias a los objetos. Modelo: SAPBC401_BAS_S1 Solución: SAPBC401_BAS_S2 Tarea 1 Defina una variable de referencia. 1. Complete el programa ZBC401_##_MAIN o copie la solución modelo del ejercicio anterior. Defina una variable de referencia para las instancias de la clase LCL_AIRPLANE. 2. Defina una tabla interna para grabar las referencias de las instancias de la clase LCL_AIRPLANE.
Tarea 2 Cree objetos de avión. 1. Cree varias instancias de la clase local LCL_AIRPLANE y grabe sus referencias en la tabla interna. Consejo: Utilice la palabra clave ABAP START-OF-SELECTION para especificar, donde comienza la parte ejecutable del programa principal. De lo contrario, las sentencias ejecutables se clasifican como inaccesibles por la verificación de sintaxis. 2. Observe la ejecución del programa en el ABAP Debugger.
© Copyright . Reservados todos los derechos.
61
Capítulo 2 Solución 3 Crear objetos
Ejemplo empresarial Como desarrollador, crea instancias de su clase de avión y asegúrese de que no se pierdan las referencias a los objetos. Modelo: SAPBC401_BAS_S1 Solución: SAPBC401_BAS_S2 Tarea 1 Defina una variable de referencia. 1. Complete el programa ZBC401_##_MAIN o copie la solución modelo del ejercicio anterior. Defina una variable de referencia para las instancias de la clase LCL_AIRPLANE. a) Véase el extracto del código fuente de la solución modelo. 2. Defina una tabla interna para grabar las referencias de las instancias de la clase LCL_AIRPLANE. a) Véase el extracto del código fuente de la solución modelo.
Tarea 2 Cree objetos de avión. 1. Cree varias instancias de la clase local LCL_AIRPLANE y grabe sus referencias en la tabla interna. Consejo: Utilice la palabra clave ABAP START-OF-SELECTION para especificar, donde comienza la parte ejecutable del programa principal. De lo contrario, las sentencias ejecutables se clasifican como inaccesibles por la verificación de sintaxis. a) Véase el extracto del código fuente de la solución modelo. 2. Observe la ejecución del programa en el ABAP Debugger. a) Realice este paso de la forma habitual. Para más información, consulte la biblioteca SAP.
62
© Copyright . Reservados todos los derechos.
Lección: Creación y trabajos con objetos
Solución: SAPBC401_BAS_S2 REPORT sapbc401_bas_s2. TYPE-POOLS icon. *--------------------------------------------------------* * CLASS lcl_airplane DEFINITION *--------------------------------------------------------* CLASS lcl_airplane DEFINITION. * ... ENDCLASS. "lcl_airplane DEFINITION *--------------------------------------------------------* * CLASS lcl_airplane IMPLEMENTATION *--------------------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. * ... ENDCLASS. "lcl_airplane IMPLEMENTATION DATA: DATA:
go_airplane TYPE REF TO lcl_airplane. gt_airplanes TYPE TABLE OF REF TO lcl_airplane.
START-OF-SELECTION. CREATE OBJECT go_airplane. APPEND go_airplane TO gt_airplanes. CREATE OBJECT go_airplane. APPEND go_airplane TO gt_airplanes. CREATE OBJECT go_airplane. APPEND go_airplane TO gt_airplanes.
© Copyright . Reservados todos los derechos.
63
Capítulo 2: Sintaxis fundamental orientada a objetos
RESUMEN DE LA LECCIÓN Ahora podrá:
64
●
Crear objetos
●
Tratar objetos
© Copyright . Reservados todos los derechos.
Capítulo 2 Lección 3 Acceso a métodos y atributos
RESUMEN DE LA LECCIÓN Este módulo explica el proceso de acceso a los métodos y atributos. Ejemplo empresarial Como desarrollador, necesita explicar las distintas maneras de acceder a los métodos y atributos de una clase. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de la llamada a métodos
●
Una buena comprensión del acceso a los atributos
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Llamar métodos de instancia
●
Llamar métodos estáticos
●
Llamar métodos funcionales
●
Acceder a atributos públicos
Llamar métodos de instancia
Figura 51: Métodos de llamada
Esta sección explica el uso de las clases y sus instancias, desde las conexiones estáticas de diversas instancias hasta sus efectos prácticos.
© Copyright . Reservados todos los derechos.
65
Capítulo 2: Sintaxis fundamental orientada a objetos
El ejemplo de la figura muestra la sintaxis más breve para llamadas admitidas desde SAP NetWeaver AS 6.10, en las que se omite el prefijo CALL-METHOD. Sintaxis para llamar los métodos de instancia
Figura 52: Llamada de métodos de instancia – Sintaxis
CALL METHOD ref->method_name es la sintaxis utilizada para llamar métodos de instancia. Cuando llama un método de instancia desde dentro de otro método de instancia, puede omitir la ref. de nombre de instancia. El método se ejecuta automáticamente para el objeto actual. Una sintaxis más corta también está permitida a partir de SAP Web AS 6.10. En esta versión, omita CALL METHOD y pase los parámetros entre paréntesis. No debe haber ningún espacio antes de los paréntesis, pero debe haber al menos un espacio después de los paréntesis. Cuando se llama a un método que sólo tiene un parámetro de importación, se puede especificar el parámetro real en los paréntesis sin la necesidad de otros suplementos. Cuando se llama a un método que sólo tiene parámetros de importación, se puede omitir el suplemento EXPORTING.
66
© Copyright . Reservados todos los derechos.
Lección: Acceso a métodos y atributos
Llamada de métodos estáticos
Figura 53: Llamada de métodos estáticos – Sintaxis
El uso del suplemento RECEIVING excluye el uso de suplementos IMPORTING y CHANGING. Además, son válidas las mismas reglas que rigen para llamar a un módulo de funciones. Utilice CALLMETHOD classname=>method_name para llamar los métodos estáticos (también denominados métodos de clase). Como los atributos estáticos, los métodos estáticos se llaman por su nombre de clase, ya que no necesitan instancias. Como con los métodos de instancia, cuando llama un método estático desde dentro de una clase, puede omitir el nombre de la clase. Por lo demás son válidas las mismas reglas que rigen para llamar a un método de instancia.
© Copyright . Reservados todos los derechos.
67
Capítulo 2: Sintaxis fundamental orientada a objetos
Llamada de métodos funcionales
Figura 54: Métodos funcionales
Los métodos que tienen un parámetro RETURNING se describen como métodos funcionales. Los métodos funcionales no pueden tener un parámetro EXPORTING o CHANGING. También debe pasar un valor al parámetro RETURNING con el suplemento VALUE. Puede llamar los métodos funcionales directamente en las siguientes expresiones: ● Expresiones lógicas: IF, ELSEIF, WHILE, CHECK, WAIT ●
Expresiones aritméticas y expresiones de bit: COMPUTE
●
Condiciones de caso: CASE, WHEN
●
Fuentes de valores como una copia local: MOVE
●
68
Buscar cláusulas para tablas internas, suponiendo que el operando no es un componente de la entrada en tabla: LOOP AT ... WHERE
© Copyright . Reservados todos los derechos.
Lección: Acceso a métodos y atributos
Métodos funcionales – Ejemplos
Figura 55: Métodos funcionales – Ejemplos
En la primera parte del ejemplo, las dos llamadas de métodos de instancia funcional representan los dos sumandos de un suplemento. El segundo ejemplo muestra la llamada de un método estático funcional en forma corta. El objeto de datos NUMBER es el parámetro real para el parámetro RETURNING del método. La sintaxis detallada es la siguiente: DATA gv_number TYPE i. ... CALL METHOD lcl_vehicle=>get_n_o_vehicles RECEIVING rv_count = gv_number.
© Copyright . Reservados todos los derechos.
69
Capítulo 2: Sintaxis fundamental orientada a objetos
Acceso a los Atributos Públicos
Figura 56: Acceso a atributos públicos
Pueden acceder a atributos públicos desde fuera de la clase de la misma manera que las llamadas de método. Puede acceder a los atributos estáticos con classname=>static_attribute. Acceda a los atributos de instancia con ref->instance_attribute.
70
© Copyright . Reservados todos los derechos.
Capítulo 2 Ejercicio 4 Llamar métodos
Ejemplo empresarial Como desarrollador, debe completar los atributos de los objetos con valores adecuados. Debe saber cómo se definen y llaman los métodos. Modelo: SAPBC401_BAS_S2 Solución: SAPBC401_BAS_S3 Tarea 1 Llame los métodos de su clase. 1. Complete el programa ZBC401_##_MAIN o copie la solución modelo del ejercicio anterior. Llame el método estático DISPLAY_N_O_AIRPLANES dos veces; antes y después de las instanciaciones. 2. Utilice el método SET_ATTRIBUTES para fijar los atributos de todos los objetos. Elija un nombre único para cada tipo de avión (por ejemplo, 747-400). Cuando asigne tipos de avión, utilice la información en la tabla SAPLANE como guía. 3. Visualice los valores de atributo de todos los aviones en un loop en la lista ABAP con el método DISPLAY_ATTRIBUTES.
Tarea 2 Añada un método funcional a su clase. 1. Defina el método funcional estático público GET_N_O_AIRPLANES en la clase. La firma del Método solo debe estar compuesta por el parámetro de retorno RV_COUNT, que debe ser un número entero. 2. Llame este método en el programa principal y emita el valor en la lista ABAP.
© Copyright . Reservados todos los derechos.
71
Capítulo 2 Solución 4 Llamar métodos
Ejemplo empresarial Como desarrollador, debe completar los atributos de los objetos con valores adecuados. Debe saber cómo se definen y llaman los métodos. Modelo: SAPBC401_BAS_S2 Solución: SAPBC401_BAS_S3 Tarea 1 Llame los métodos de su clase. 1. Complete el programa ZBC401_##_MAIN o copie la solución modelo del ejercicio anterior. Llame el método estático DISPLAY_N_O_AIRPLANES dos veces; antes y después de las instanciaciones. a) Véase el extracto del código fuente de la solución modelo. Atención: Por los motivos que se explican en el ejercicio Crear diagramas UML, no notará ningún efecto por el momento. 2. Utilice el método SET_ATTRIBUTES para fijar los atributos de todos los objetos. Elija un nombre único para cada tipo de avión (por ejemplo, 747-400). Cuando asigne tipos de avión, utilice la información en la tabla SAPLANE como guía. a) Véase el extracto del código fuente de la solución modelo. 3. Visualice los valores de atributo de todos los aviones en un loop en la lista ABAP con el método DISPLAY_ATTRIBUTES. a) Véase el extracto del código fuente de la solución modelo.
Tarea 2 Añada un método funcional a su clase. 1. Defina el método funcional estático público GET_N_O_AIRPLANES en la clase. La firma del Método solo debe estar compuesta por el parámetro de retorno RV_COUNT, que debe ser un número entero. a) Véase el extracto del código fuente de la solución modelo.
72
© Copyright . Reservados todos los derechos.
Lección: Acceso a métodos y atributos
2. Llame este método en el programa principal y emita el valor en la lista ABAP. a) Véase el extracto del código fuente de la solución modelo. Solución: SAPBC401_BAS_S3 Report SAPBC401_BAS_S3. TYPE-POOLS icon. *----------------------------------------------* * CLASS lcl_airplane DEFINITION *----------------------------------------------* CLASS lcl_airplane DEFINITION. PUBLIC SECTION. METHODS: set_attributes IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype, display_attributes. CLASS-METHODS: display_n_o_airplanes, get_n_o_airplanes RETURNING value(rv_count) TYPE i. PROTECTED SECTION. PRIVATE SECTION. CONSTANTS:
c_pos_1 TYPE i VALUE 30.
DATA: mv_name TYPE string, mv_planetype TYPE saplane-planetype. CLASS-DATA: gv_n_o_airplanes TYPE i. ENDCLASS. "lcl_airplane DEFINITION *----------------------------------------------* * CLASS lcl_airplane IMPLEMENTATION *----------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. METHOD
set_attributes.
mv_planetype = iv_planetype. * doesn't make sense so much, * only in order to get an effect * after calling display_n_o_airplanes: gv_n_o_airplanes = gv_n_o_airplanes + 1. ENDMETHOD. "set_attributes METHOD
display_attributes.
DATA: lv_weight TYPE saplane-weight, lv_cap TYPE saplane-tankcap.
© Copyright . Reservados todos los derechos.
73
Capítulo 2: Sintaxis fundamental orientada a objetos
WRITE: / icon_ws_plane AS ICON, / 'Name of Airplane'(001) , AT c_pos_1 mv_name, / 'Type of Airplane:'(002), AT c_pos_1 mv_planetype. ENDMETHOD. "display_attributes METHOD display_n_o_airplanes. SKIP. WRITE: / 'Number of airplanes:'(ca1), AT c_pos_1 gv_n_o_airplanes LEFT-JUSTIFIED. ENDMETHOD. "display_n_o_airplanes METHOD get_n_o_airplanes. rv_count = gv_n_o_airplanes. ENDMETHOD. "get_n_o_airplanes ENDCLASS. "lcl_airplane IMPLEMENTATION DATA: go_airplane TYPE REF TO lcl_airplane, gt_airplanes TYPE TABLE OF REF TO lcl_airplane, gv_count TYPE i. START-OF-SELECTION. lcl_airplane=>display_n_o_airplanes( ). CREATE OBJECT go_airplane. APPEND go_airplane TO gt_airplanes. go_airplane->set_attributes( iv_name = 'LH Berlin' iv_planetype = 'A321' ). CREATE OBJECT go_airplane. APPEND go_airplane TO gt_airplanes. go_airplane->set_attributes( iv_name = 'AA New York' iv_planetype = '747-400' ). CREATE OBJECT go_airplane. APPEND go_airplane TO gt_airplanes. go_airplane->set_attributes( iv_name = 'US Hercules' iv_planetype = '747-200F' ). LOOP AT gt_airplanes INTO go_airplane. go_airplane->display_attributes( ). ENDLOOP. * * * * * * * * * *
74
long syntax for functional call: CALL METHOD lcl_airplane=>get_n_o_airplanes RECEIVING rv_count = gv_count. a little bit shorter: lcl_airplane=>get_n_o_airplanes( RECEIVING rv_count = gv_count ). the shortest syntax for functional call:
© Copyright . Reservados todos los derechos.
Lección: Acceso a métodos y atributos
gv_count = lcl_airplane=>get_n_o_airplanes( ). SKIP 2. WRITE: / 'Number of airplanes'(ca1), gv_count.
© Copyright . Reservados todos los derechos.
75
Capítulo 2: Sintaxis fundamental orientada a objetos
RESUMEN DE LA LECCIÓN Ahora podrá:
76
●
Llamar métodos de instancia
●
Llamar métodos estáticos
●
Llamar métodos funcionales
●
Acceder a atributos públicos
© Copyright . Reservados todos los derechos.
Capítulo 2 Lección 4 Implementación de constructores en clases locales
RESUMEN DE LA LECCIÓN Este módulo explica la implementación de los métodos de constructor en las clases locales. Ejemplo empresarial Como desarrollador, debe explicar la creación y el uso de constructores de instancia para la clase en su proyecto de objetos ABAP. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de los constructores de instancia
●
Una buena comprensión de cómo usar los constructores de instancia
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Crear y utilizar constructores
Constructor
Figura 57: Constructor (instancia)
© Copyright . Reservados todos los derechos.
77
Capítulo 2: Sintaxis fundamental orientada a objetos
Existen dos tipos de métodos en objetos ABAP. Los objetos ABAP pueden llamarse de manera implícita o explícita con la sintaxis CALL METHOD. Los constructores son el primer tipo de método. El constructor de instancias es un método de instancia especial en una clase y siempre se denomina CONSTRUCTOR. El constructor se llama automáticamente en tiempo de ejecución con la sentencia CREATE OBJECT. Cuando define los constructores, siempre debe tener en cuenta los puntos siguientes: Ninguna clase puede tener más de un constructor.
●
●
Un constructor debe definirse en el área pública.
●
La firma del constructor solo puede incluir parámetros de importación y excepciones.
●
●
Cuando se emiten excepciones en el constructor, no se crean instancias, de manera que no se ocupa espacio de memoria principal. Con la excepción de un caso, no se puede llamar el constructor de forma explícita.
Nota: No hay destructores en los objetos ABAP; es decir, no existe ningún método de instancia que se llame de manera automática desde la memoria inmediatamente antes de que se borre el objeto. Los comentarios correspondientes en la biblioteca SAP y los accesos vía menús fuera de Workbench ABAP solo existen en las llamadas de sistema internas. Constructor – Ejemplo
Figura 58: Constructor – Ejemplo
Después de la instanciación de una clase, se necesita un constructor cuando se presente alguna de las siguientes condiciones:
78
© Copyright . Reservados todos los derechos.
Lección: Implementación de constructores en clases locales
●
●
Debe asignar recursos. Debe inicializar atributos que no pueden cubrirse con el suplemento VALUE en la sentencia DATA.
●
Modifica atributos estáticos.
●
Debe informar a otros objetos sobre la creación de objetos.
© Copyright . Reservados todos los derechos.
79
Capítulo 2: Sintaxis fundamental orientada a objetos
80
© Copyright . Reservados todos los derechos.
Capítulo 2 Ejercicio 5 Crear y utilizar constructores
Ejemplo empresarial Define e implementa constructores de instancia. Crea instancias de clases que contengan un constructor de instancia. Define, emite y trata excepciones clásicas, no basadas en clases. Modelo: SAPBC401_BAS_S3 Solución: SAPBC401_BAS_S4 Tarea 1 Defina un constructor de instancia. 1. Complete el programa ZBC401_##_MAIN o copie la solución modelo del ejercicio anterior, donde ## es su número de grupo de dos cifras. Defina un constructor con una firma adecuada para las instancias de su clase LCL_AIRPLANE. Implemente el constructor de manera que los dos atributos de instancia estén fijados y que el contador de instancias N_O_AIRPLANES aumente en uno. 2. Elimine la definición y la implementación del método SET_ATTRIBUTES para garantizar que un atributo de una instancia pueda establecerse una vez durante su creación.
Tarea 2 Cree objetos de avión. 1. Sus sentencias CREATE OBJECT del ejercicio anterior son ahora incorrectas desde el punto de vista sintáctico. Adáptelas y corríjalas. 2. Elimine las llamadas del método SET_ATTRIBUTES. 3. Siga la ejecución del programa en el ABAP Debugger. Tarea 3 Defina atributos de instancia adicionales con la información técnica sobre el avión. Establezca estos atributos en su constructor accediendo a la tabla de base de datos SAPLANE. Emita una excepción si no encuentra el tipo específico de avión en la base de datos. 1. En su clase, defina los atributos de instancia privada MV_WEIGHT (tipos de datos SAPLANE-WEIGHT) y MV_TANKCAP (tipos de datos SAPLANE_TANKCAP). 2. Amplíe la definición de constructor de instancia al añadir una excepción clásica, no basada en clases WRONG_PLANETYPE.
© Copyright . Reservados todos los derechos.
81
Capítulo 2: Sintaxis fundamental orientada a objetos
3. Amplíe la implementación del constructor. Lea un registro individual de la tabla de base de datos SAPLANE para el tipo específico de avión y establezca los nuevos atributos según corresponda. Presente una excepción si no se encuentran datos para el tipo de avión dado. 4. Ajuste las sentencias CREATE OBJECT para tratar la excepción. Solo almacene la referencia de objeto en su tabla si la creación fue exitosa. 5. Siga la ejecución del programa en el ABAP Debugger. Por razones de prueba, especifique un tipo de avión no existente para ver cómo funciona el tratamiento de excepciones.
82
© Copyright . Reservados todos los derechos.
Capítulo 2 Solución 5 Crear y utilizar constructores
Ejemplo empresarial Define e implementa constructores de instancia. Crea instancias de clases que contengan un constructor de instancia. Define, emite y trata excepciones clásicas, no basadas en clases. Modelo: SAPBC401_BAS_S3 Solución: SAPBC401_BAS_S4 Tarea 1 Defina un constructor de instancia. 1. Complete el programa ZBC401_##_MAIN o copie la solución modelo del ejercicio anterior, donde ## es su número de grupo de dos cifras. Defina un constructor con una firma adecuada para las instancias de su clase LCL_AIRPLANE. Implemente el constructor de manera que los dos atributos de instancia estén fijados y que el contador de instancias N_O_AIRPLANES aumente en uno. a) Véase el extracto del código fuente de la solución modelo. 2. Elimine la definición y la implementación del método SET_ATTRIBUTES para garantizar que un atributo de una instancia pueda establecerse una vez durante su creación. a) Véase el extracto del código fuente de la solución modelo.
Tarea 2 Cree objetos de avión. 1. Sus sentencias CREATE OBJECT del ejercicio anterior son ahora incorrectas desde el punto de vista sintáctico. Adáptelas y corríjalas. a) Véase el extracto del código fuente de la solución modelo. 2. Elimine las llamadas del método SET_ATTRIBUTES. a) Véase el extracto del código fuente de la solución modelo. 3. Siga la ejecución del programa en el ABAP Debugger. a) Realice este paso de la forma habitual. Para más información sobre el ABAP Debugger, consulte en la biblioteca SAP. Tarea 3
© Copyright . Reservados todos los derechos.
83
Capítulo 2: Sintaxis fundamental orientada a objetos
Defina atributos de instancia adicionales con la información técnica sobre el avión. Establezca estos atributos en su constructor accediendo a la tabla de base de datos SAPLANE. Emita una excepción si no encuentra el tipo específico de avión en la base de datos. 1. En su clase, defina los atributos de instancia privada MV_WEIGHT (tipos de datos SAPLANE-WEIGHT) y MV_TANKCAP (tipos de datos SAPLANE_TANKCAP). a) Véase el extracto del código fuente de la solución modelo. 2. Amplíe la definición de constructor de instancia al añadir una excepción clásica, no basada en clases WRONG_PLANETYPE. a) Véase el extracto del código fuente de la solución modelo. 3. Amplíe la implementación del constructor. Lea un registro individual de la tabla de base de datos SAPLANE para el tipo específico de avión y establezca los nuevos atributos según corresponda. Presente una excepción si no se encuentran datos para el tipo de avión dado. a) Véase el extracto del código fuente de la solución modelo. 4. Ajuste las sentencias CREATE OBJECT para tratar la excepción. Solo almacene la referencia de objeto en su tabla si la creación fue exitosa. a) Véase el extracto del código fuente de la solución modelo. 5. Siga la ejecución del programa en el ABAP Debugger. Por razones de prueba, especifique un tipo de avión no existente para ver cómo funciona el tratamiento de excepciones. a) Realice este paso de la forma habitual. Para más información sobre el ABAP Debugger, consulte en la biblioteca SAP. Solución: SAPBC401_BAS_S4 REPORT
sapbc401_bas_s4.
TYPE-POOLS icon. *-------------------------------------------------* * CLASS lcl_airplane DEFINITION * *-------------------------------------------------* CLASS lcl_airplane DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype EXCEPTIONS wrong_planetype, display_attributes. CLASS-METHODS: display_n_o_airplanes, get_n_o_airplanes RETURNING value(rv_count) TYPE i. PRIVATE SECTION.
84
© Copyright . Reservados todos los derechos.
Lección: Implementación de constructores en clases locales
CONSTANTS: c_pos_1 TYPE i VALUE 30. DATA: mv_name mv_planetype mv_weight mv_tankcap
TYPE TYPE TYPE TYPE
string, saplane-planetype, saplane-weight, saplane-tankcap.
CLASS-DATA: gv_n_o_airplanes TYPE i. ENDCLASS.
"lcl_airplane DEFINITION
*--------------------------------------------------* * CLASS lcl_airplane IMPLEMENTATION * *--------------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. METHOD constructor. DATA: ls_planetype TYPE saplane. mv_name = iv_name. mv_planetype = iv_planetype. SELECT SINGLE * FROM saplane INTO ls_planetype WHERE planetype = iv_planetype. IF sy-subrc <> 0. RAISE wrong_planetype. ELSE. mv_weight = ls_planetype-weight. mv_tankcap = ls_planetype-tankcap. gv_n_o_airplanes = gv_n_o_airplanes + 1. ENDIF. ENDMETHOD.
"constructor
METHOD display_attributes. WRITE: / icon_ws_plane AS ICON, / 'Name of Airplane'(001) , / 'Type of Airplane:'(002), / 'Weight:'(003), LEFT-JUSTIFIED, / 'Tank capacity:'(004), LEFT-JUSTIFIED. ENDMETHOD.
AT c_pos_1 mv_name, AT c_pos_1 mv_planetype, AT c_pos_1 mv_weight AT c_pos_1 mv_tankcap
"display_attributes
METHOD display_n_o_airplanes. SKIP. WRITE: / 'Number of airplanes:'(ca1), AT c_pos_1 gv_n_o_airplanes LEFT-JUSTIFIED. ENDMETHOD. "display_n_o_airplanes METHOD get_n_o_airplanes. rv_count = gv_n_o_airplanes.
© Copyright . Reservados todos los derechos.
85
Capítulo 2: Sintaxis fundamental orientada a objetos
ENDMETHOD. ENDCLASS.
"get_n_o_airplanes "lcl_airplane IMPLEMENTATION
DATA: go_airplane TYPE REF TO lcl_airplane, gt_airplanes TYPE TABLE OF REF TO lcl_airplane, gv_count TYPE i. START-OF-SELECTION. ******************* lcl_airplane=>display_n_o_airplanes( ). CREATE OBJECT go_airplane EXPORTING iv_name = 'LH Berlin' iv_planetype = 'A321' EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. APPEND go_airplane TO gt_airplanes. ENDIF. CREATE OBJECT go_airplane EXPORTING iv_name = 'AA New York' iv_planetype = '747-400' EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. APPEND go_airplane TO gt_airplanes. ENDIF. CREATE OBJECT go_airplane EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. APPEND go_airplane TO gt_airplanes. ENDIF. LOOP AT gt_airplanes INTO go_airplane. go_airplane->display_attributes( ). ENDLOOP. gv_count = lcl_airplane=>get_n_o_airplanes( ). SKIP 2. WRITE: / 'Number of airplanes'(ca1), gv_count.
86
© Copyright . Reservados todos los derechos.
Lección: Implementación de constructores en clases locales
RESUMEN DE LA LECCIÓN Ahora podrá: ●
Crear y utilizar constructores
© Copyright . Reservados todos los derechos.
87
Capítulo 2 Lección 5 Implementación de constructores de clases en clases locales
RESUMEN DE LA LECCIÓN Este módulo explica la creación y el uso de constructores estáticos y autorreferencias. Ejemplo empresarial Como desarrollador, necesita explicar la creación y el uso de constructores estáticos para las clases en su proyecto de objetos ABAP. ●
Una buena comprensión del constructor estático
●
Una buena comprensión de la autorreferencia
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Crear y utilizar constructores estáticos
Constructor estático
Figura 59: Ejemplo de un constructor estático
El constructor estático es un método estático especial y siempre se llama CLASS_CONSTRUCTOR. El constructor estático se ejecuta solo una vez por programa.
88
© Copyright . Reservados todos los derechos.
Lección: Implementación de constructores de clases en clases locales
El sistema llama el constructor estático de manera automática antes de que se accede a la clase por primera vez y antes de la primera ejecución de las siguientes acciones: ● Cuando se crea una instancia de la clase (CREATE OBJECT). ●
Cuando se accede a un atributo estático de la clase.
●
Cuando se llama un método estático de la clase.
●
Cuando se registra un método de programa de control de eventos para un evento en la clase.
Cuando define los constructores estáticos, siempre debe tener en cuenta los puntos siguientes: ● Cada clase no tiene más que un constructor estático. ●
El constructor estático debe definirse en el área pública.
●
La firma del constructor no puede tener parámetros de importación ni excepciones.
●
El constructor estático no puede llamarse de forma explícita.
Autorreferencia
Figura 60: Autorreferencia
En algunos casos, también debe tener una autorreferencia disponible. En objetos ABAP, las autorreferencias siempre están predefinidas, pero solo son útiles en ciertos contextos y están disponibles sintácticamente. Es posible dirigirse a un objeto en sí mediante la variable de referencia predefinida ME dentro de sus métodos de instancia. No es necesario utilizar el prefijo me->as en estos casos, pero se puede utilizar para mejorar la facilidad de lectura. Sin embargo, debe utilizar el prefijo me-> cuando distingue entre objetos de datos locales y atributos de instancia con el mismo nombre.
© Copyright . Reservados todos los derechos.
89
Capítulo 2: Sintaxis fundamental orientada a objetos
Un uso importante de la autorreferencia se observa cuando llama un método extranjero y un objeto de cliente debe exportarse una referencia. En este caso, puede usar ME como parámetro real con EXPORTING o CHANGING.
90
© Copyright . Reservados todos los derechos.
Capítulo 2 Ejercicio 6 Crear y utilizar constructores estáticos
Ejemplo empresarial Por cuestiones de rendimiento, no desea acceder a la base de datos cada vez que se crea una instancia. Por lo tanto, lee todos lo datos solo una vez en el constructor estático y lo almacena en un atributo estático. Modelo: SAPBC401_BAS_S4 Solución: SAPBC401_BAS_S5 Tarea 1 Defina la tabla interna como un atributo estático privado. Defina un constructor estático en el que llene el atributo con el contenido completo de la tabla de base de datos SAPLANE. Utilice el ABAP Debugger para analizar la llamada del constructor estático. 1. Complete el programa ZBC401_##_MAIN o copie la solución modelo del ejercicio anterior. Defina la tabla interna GT_PLANETYPES como atributo de clase privado. Para especificar el tipo de la tabla interna GT_PLANETYPES, defina el tipo de tabla privada TY_PLANETYPES en la definición de clase. Utilice el campo PLANETYPE como una clave para la tabla interna. 2. Defina el constructor estático en la clase LCL_AIRPLANE. Implemente el constructor de manera que la tabla interna GT_PLANETYPES se rellene con todas las filas de la tabla de base de datos SAPLANE. Para este fin puede utilizar la técnica ARRAY FETCH. 3. Utilice ABAP Debugger para comprobar que el constructor estático se llama correctamente y que la tabla interna se ha completado en el programa principal. ¿Dónde se ha llamado el constructor estático en el programa principal? Tarea 2 Declare e implemente un método estático privado para derivar el peso y la capacidad del tanque de un tipo de avión desde la tabla GT_PLANETYPES. 1. Dentro de la clase LCL_AIRPLANE, defina el método estático privado GET_TECHNICAL_ATTRIBUTES. La firma debe estar formada por un parámetro de importación del tipo de avión y dos parámetros de exportación de peso y capacidad del depósito. Utilice la tabla transparente SAPLANE como guía para especificar estos tipos de parámetros formales.
© Copyright . Reservados todos los derechos.
91
Capítulo 2: Sintaxis fundamental orientada a objetos
La firma también debe contener una excepción clásica, que se emite si no se encuentran datos para el tipo específico de avión. Utilice una excepción no basada en clase. 2. Implemente el método de manera que los valores de los parámetros de exportación se determinen con el acceso de registro individual a la tabla interna GT_PLANETYPES. Cuando la tabla no contiene ningún valor para el tipo de avión, el método emite una excepción. Nota: La unidad de medida correcta también debería seleccionarse y exportarse. Sin embargo, por razones de tiempo, no hace falta que lo incluya en este ejercicio. Tarea 3 Reemplace el acceso a la base de datos en el constructor de instancia llamando el método GET_TECHNICAL_ATTRIBUTES. 1. ¿Es posible llamar al nuevo método desde el programa principal? ¿Por qué no? 2. Llame el método GET_TECHNICAL_ATTRIBUTES desde el constructor para obtener datos técnicos adicionales. Según el resultado, establezca los atributos privados correspondientes o emita la excepción del constructor. 3. Observe la ejecución del programa en el ABAP Debugger. 4. ¿Qué soluciones alternativas podrían utilizarse para resolver las tareas?
92
© Copyright . Reservados todos los derechos.
Capítulo 2 Solución 6 Crear y utilizar constructores estáticos
Ejemplo empresarial Por cuestiones de rendimiento, no desea acceder a la base de datos cada vez que se crea una instancia. Por lo tanto, lee todos lo datos solo una vez en el constructor estático y lo almacena en un atributo estático. Modelo: SAPBC401_BAS_S4 Solución: SAPBC401_BAS_S5 Tarea 1 Defina la tabla interna como un atributo estático privado. Defina un constructor estático en el que llene el atributo con el contenido completo de la tabla de base de datos SAPLANE. Utilice el ABAP Debugger para analizar la llamada del constructor estático. 1. Complete el programa ZBC401_##_MAIN o copie la solución modelo del ejercicio anterior. Defina la tabla interna GT_PLANETYPES como atributo de clase privado. Para especificar el tipo de la tabla interna GT_PLANETYPES, defina el tipo de tabla privada TY_PLANETYPES en la definición de clase. Utilice el campo PLANETYPE como una clave para la tabla interna. a) Véase el extracto del código fuente de la solución modelo. 2. Defina el constructor estático en la clase LCL_AIRPLANE. Implemente el constructor de manera que la tabla interna GT_PLANETYPES se rellene con todas las filas de la tabla de base de datos SAPLANE. Para este fin puede utilizar la técnica ARRAY FETCH. a) Véase el extracto del código fuente de la solución modelo. 3. Utilice ABAP Debugger para comprobar que el constructor estático se llama correctamente y que la tabla interna se ha completado en el programa principal. ¿Dónde se ha llamado el constructor estático en el programa principal? a) Antes de acceder a la clase por primera vez (antes de DISPLAY_N_O_AIRPLANES, en este caso). Tarea 2 Declare e implemente un método estático privado para derivar el peso y la capacidad del tanque de un tipo de avión desde la tabla GT_PLANETYPES. 1. Dentro de la clase LCL_AIRPLANE, defina el método estático privado GET_TECHNICAL_ATTRIBUTES.
© Copyright . Reservados todos los derechos.
93
Capítulo 2: Sintaxis fundamental orientada a objetos
La firma debe estar formada por un parámetro de importación del tipo de avión y dos parámetros de exportación de peso y capacidad del depósito. Utilice la tabla transparente SAPLANE como guía para especificar estos tipos de parámetros formales. La firma también debe contener una excepción clásica, que se emite si no se encuentran datos para el tipo específico de avión. Utilice una excepción no basada en clase. a) Véase el extracto del código fuente de la solución modelo. 2. Implemente el método de manera que los valores de los parámetros de exportación se determinen con el acceso de registro individual a la tabla interna GT_PLANETYPES. Cuando la tabla no contiene ningún valor para el tipo de avión, el método emite una excepción. a) Véase el extracto del código fuente de la solución modelo.
Nota: La unidad de medida correcta también debería seleccionarse y exportarse. Sin embargo, por razones de tiempo, no hace falta que lo incluya en este ejercicio. Tarea 3 Reemplace el acceso a la base de datos en el constructor de instancia llamando el método GET_TECHNICAL_ATTRIBUTES. 1. ¿Es posible llamar al nuevo método desde el programa principal? ¿Por qué no? a) Solo puede llamar el nuevo método del programa principal si el método es público. Debido a que el nuevo método en este caso es un método privado, solo puede llamarse desde la clase LCL_AIRPLANE. 2. Llame el método GET_TECHNICAL_ATTRIBUTES desde el constructor para obtener datos técnicos adicionales. Según el resultado, establezca los atributos privados correspondientes o emita la excepción del constructor. a) Véase el extracto del código fuente de la solución modelo. 3. Observe la ejecución del programa en el ABAP Debugger. a) Realice este paso de la forma habitual. Para más información sobre el ABAP Debugger, consulte en la biblioteca SAP. 4. ¿Qué soluciones alternativas podrían utilizarse para resolver las tareas? a) Defina GET_TECHNCAL_ATTRIBUTES como método de instancia sin el parámetro de importación PLANETYPE. Si el método se define como un método de instancia, puede acceder directamente al atributo MV_PLANETYPE (como ME->MV_PLANETYPE). En este caso, el parámetro de importación no es necesario. b) No utilice un método para leer GT_PLANETYPES. En el constructor de instancia, puede acceder de manera directa al atributo de clase GT_PLANETYPES (como ME->GT_PLANETYPES). Solución: SAPBC401_BAS_S5 REPORT
94
sapbc401_bas_s5.
© Copyright . Reservados todos los derechos.
Lección: Implementación de constructores de clases en clases locales
TYPE-POOLS icon. *-------------------------------------------------* * CLASS lcl_airplane DEFINITION *-------------------------------------------------* CLASS lcl_airplane DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype EXCEPTIONS wrong_planetype, display_attributes. CLASS-METHODS: class_constructor, display_n_o_airplanes, get_n_o_airplanes RETURNING value(rv_count) TYPE i. PRIVATE SECTION. TYPES: ty_planetypes TYPE STANDARD TABLE OF saplane WITH NON-UNIQUE KEY planetype. CONSTANTS: c_pos_1 TYPE i VALUE 30. DATA: mv_name mv_planetype mv_weight mv_tankcap
TYPE TYPE TYPE TYPE
string, saplane-planetype, saplane-weight, saplane-tankcap.
CLASS-DATA: gv_n_o_airplanes TYPE i, gt_planetypes TYPE ty_planetypes. CLASS-METHODS: get_technical_attributes IMPORTING iv_type TYPE saplane-planetype EXPORTING ev_weight TYPE saplane-weight ev_tankcap TYPE saplane-tankcap EXCEPTIONS wrong_planetype. ENDCLASS.
"lcl_airplane DEFINITION
*------------------------------------------------* * CLASS lcl_airplane IMPLEMENTATION *------------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. METHOD class_constructor.
© Copyright . Reservados todos los derechos.
95
Capítulo 2: Sintaxis fundamental orientada a objetos
SELECT * FROM saplane INTO TABLE gt_planetypes. ENDMETHOD. "class_constructor *
METHOD constructor. DATA: ls_planetype TYPE saplane. mv_name = iv_name. mv_planetype = iv_planetype.
* * *
* *
SELECT SINGLE * FROM saplane INTO ls_planetype WHERE planetype = iv_planetype. get_technical_attributes( EXPORTING iv_type = iv_planetype IMPORTING ev_weight = mv_weight ev_tankcap = mv_tankcap EXCEPTIONS wrong_planetype = 1 ). IF sy-subrc <> 0. RAISE wrong_planetype. ELSE. mv_weight = ls_planetype-weight. mv_tankcap = ls_planetype-tankcap. gv_n_o_airplanes = gv_n_o_airplanes + 1. ENDIF. ENDMETHOD.
"constructor
METHOD display_attributes. WRITE: / icon_ws_plane AS ICON, / 'Name of Airplane'(001) , / 'Type of Airplane:'(002), / 'Weight:'(003), LEFT-JUSTIFIED, / 'Tank capacity:'(004), LEFT-JUSTIFIED. ENDMETHOD.
AT c_pos_1 mv_name, AT c_pos_1 mv_planetype, AT c_pos_1 mv_weight AT c_pos_1 mv_tankcap
"display_attributes
METHOD display_n_o_airplanes. SKIP. WRITE: / 'Number of airplanes:'(ca1), AT c_pos_1 gv_n_o_airplanes LEFT-JUSTIFIED. ENDMETHOD. "display_n_o_airplanes METHOD get_n_o_airplanes. rv_count = gv_n_o_airplanes. ENDMETHOD. "get_n_o_airplanes METHOD get_technical_attributes. DATA: ls_planetype TYPE saplane. READ TABLE gt_planetypes INTO ls_planetype WITH TABLE KEY planetype = iv_type TRANSPORTING weight tankcap. IF sy-subrc = 0. ev_weight = ls_planetype-weight.
96
© Copyright . Reservados todos los derechos.
Lección: Implementación de constructores de clases en clases locales
ev_tankcap = ls_planetype-tankcap. ELSE. RAISE wrong_planetype. ENDIF. ENDMETHOD. "get_technical_attributes ENDCLASS. "lcl_airplane IMPLEMENTATION DATA: go_airplane TYPE REF TO lcl_airplane, gt_airplanes TYPE TABLE OF REF TO lcl_airplane, gv_count TYPE i. START-OF-SELECTION. ******************* lcl_airplane=>display_n_o_airplanes( ). CREATE OBJECT go_airplane EXPORTING iv_name = 'LH Berlin' iv_planetype = 'A321' EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. APPEND go_airplane TO gt_airplanes. ENDIF. CREATE OBJECT go_airplane EXPORTING iv_name = 'AA New York' iv_planetype = '747-400' EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. APPEND go_airplane TO gt_airplanes. ENDIF. CREATE OBJECT go_airplane EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. APPEND go_airplane TO gt_airplanes. ENDIF. LOOP AT gt_airplanes INTO go_airplane. go_airplane->display_attributes( ). ENDLOOP. gv_count = lcl_airplane=>get_n_o_airplanes( ). SKIP 2. WRITE: / 'Number of airplanes'(ca1), gv_count.
© Copyright . Reservados todos los derechos.
97
Capítulo 2: Sintaxis fundamental orientada a objetos
RESUMEN DE LA LECCIÓN Ahora podrá: ●
98
Crear y utilizar constructores estáticos
© Copyright . Reservados todos los derechos.
Capítulo 2 Evaluación de la formación
1. La sentencia CLASS puede anidarse; es decir, puede definir una clase dentro de una clase. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
2. De los siguientes elementos de sintaxis, ¿cuál se utiliza para definir los atributos estáticos? Seleccione la respuesta correcta. X
A CLASS-DATA
X
B DATA
X
C LIKE
3. De las siguientes opciones, ¿cuál se utiliza para crear un objeto? Seleccione la respuesta correcta. X
A CREATE OBJECT ref_name
X
B APPEND ref_name
X
C CLASS ref_name
4. El recolector de basura es una rutina de sistema que se inicia de manera automática si el sistema de tiempo de ejecución no tiene tareas más importantes para realizar. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
99
Capítulo 2: Evaluación de la formación
5. Las referencias independientes son referencias que han sido definidas en una clase. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
6. No puede crear y dirigirse a objetos con variables de referencia. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
7. Durante el tiempo de ejecución de programa, crea los objetos discretos (instancias) en la memoria para una clase existente. Este proceso se denomina instanciación. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
8. Cuando llama un método estático desde dentro de una clase, puede omitir el nombre de la clase. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
9. ¿En cuáles de las siguientes expresiones pueden llamarse directamente métodos funcionales? Seleccione las respuestas correctas.
100
X
A IF
X
B COMPUTE
X
C MOVE
X
D WHILE
© Copyright . Reservados todos los derechos.
Capítulo 2: Evaluación de la formación
10. Puede describir los métodos que tienen un parámetro _________ como método funcional. Seleccione la respuesta correcta. X
A EXPORTING
X
B CHANGING
X
C RETURNING
11. Debe definir los parámetros RETURNING con el suplemento VALUE, es decir, deben pasarse por valor. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
12. El _____________ es un método de instancia especial en una clase. Seleccione la respuesta correcta. X
A constructor
X
B función
X
C atributos
13. El constructor se llama automáticamente en tiempo de ejecución con la sentencia CREATE OBJECT. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
14. De los siguientes puntos, ¿cuáles deberán tenerse en cuenta al definir constructores estáticos? Seleccione la respuesta correcta. X
A Cada clase tiene, como máximo, un constructor estático.
X
B El constructor estático debe definirse en el área privada.
X
C La firma del constructor puede tener parámetros de importación o excepciones.
X
D El constructor estático debe llamarse de forma explícita desde la clase.
© Copyright . Reservados todos los derechos.
101
Capítulo 2: Evaluación de la formación
15. La firma del constructor de instancia puede tener parámetros de importación o excepciones. Indique si esta afirmación es verdadera o falsa.
102
X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
Capítulo 2 Respuestas a la Evaluación de la formación
1. La sentencia CLASS puede anidarse; es decir, puede definir una clase dentro de una clase. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
2. De los siguientes elementos de sintaxis, ¿cuál se utiliza para definir los atributos estáticos? Seleccione la respuesta correcta. X
A CLASS-DATA
X
B DATA
X
C LIKE
3. De las siguientes opciones, ¿cuál se utiliza para crear un objeto? Seleccione la respuesta correcta. X
A CREATE OBJECT ref_name
X
B APPEND ref_name
X
C CLASS ref_name
4. El recolector de basura es una rutina de sistema que se inicia de manera automática si el sistema de tiempo de ejecución no tiene tareas más importantes para realizar. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
103
Capítulo 2: Respuestas a la Evaluación de la formación
5. Las referencias independientes son referencias que han sido definidas en una clase. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
6. No puede crear y dirigirse a objetos con variables de referencia. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
7. Durante el tiempo de ejecución de programa, crea los objetos discretos (instancias) en la memoria para una clase existente. Este proceso se denomina instanciación. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
8. Cuando llama un método estático desde dentro de una clase, puede omitir el nombre de la clase. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
9. ¿En cuáles de las siguientes expresiones pueden llamarse directamente métodos funcionales? Seleccione las respuestas correctas.
104
X
A IF
X
B COMPUTE
X
C MOVE
X
D WHILE
© Copyright . Reservados todos los derechos.
Capítulo 2: Respuestas a la Evaluación de la formación
10. Puede describir los métodos que tienen un parámetro _________ como método funcional. Seleccione la respuesta correcta. X
A EXPORTING
X
B CHANGING
X
C RETURNING
11. Debe definir los parámetros RETURNING con el suplemento VALUE, es decir, deben pasarse por valor. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
12. El _____________ es un método de instancia especial en una clase. Seleccione la respuesta correcta. X
A constructor
X
B función
X
C atributos
13. El constructor se llama automáticamente en tiempo de ejecución con la sentencia CREATE OBJECT. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
14. De los siguientes puntos, ¿cuáles deberán tenerse en cuenta al definir constructores estáticos? Seleccione la respuesta correcta. X
A Cada clase tiene, como máximo, un constructor estático.
X
B El constructor estático debe definirse en el área privada.
X
C La firma del constructor puede tener parámetros de importación o excepciones.
X
D El constructor estático debe llamarse de forma explícita desde la clase.
© Copyright . Reservados todos los derechos.
105
Capítulo 2: Respuestas a la Evaluación de la formación
15. La firma del constructor de instancia puede tener parámetros de importación o excepciones. Indique si esta afirmación es verdadera o falsa.
106
X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
CAPÍTULO 3
Herencia y casting
Lección 1 Implementación de la herencia Ejercicio 7: Implementar la herencia
108 117
Lección 2 Implementación de conversiones Up-Cast mediante la herencia Ejercicio 8: Implementar up-casts
127 131
Lección 3 Implementación de polimorfismo con herencia Ejercicio 9: Implementar el polimorfismo mediante la herencia
136 141
Lección 4 Implementación down-casts mediante la herencia Ejercicio 10: Implementar down-casts
148 151
OBJETIVOS DEL CAPÍTULO ●
Explicar la generalización y la especialización
●
Implementar la herencia
●
Acceder a los elementos de las clases en la herencia
●
Implementar conversiones Up-Cast mediante la herencia
●
Explicar el polimorfismo
●
Implementar el polimorfismo mediante la herencia
●
Implementar conversiones down-cast con la herencia
●
Modelar jerarquías de clases
© Copyright . Reservados todos los derechos.
107
Capítulo 3 Lección 1 Implementación de la herencia
RESUMEN DE LA LECCIÓN Este módulo explica el concepto de herencia y su implementación. Ejemplo empresarial Como desarrollador, necesita implementar herencias para la clase en su proyecto de objetos ABAP. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de la herencia
●
Una buena comprensión de la generalización y la especialización
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Explicar la generalización y la especialización
●
Implementar la herencia
●
Acceder a los elementos de las clases en la herencia
Generalización y especialización
Figura 61: Ejemplo de generalización y especialización
La especialización describe una relación en la que una clase (la subclase) hereda todas las características principales de otra clase (la clase superior). La subclase también puede añadir componentes nuevos (atributos, métodos, etc.) y sustituir las implementaciones con los
108
© Copyright . Reservados todos los derechos.
Lección: Implementación de la herencia
métodos heredados. En el segundo caso, el nombre de método en el diagrama de lenguaje unificado de modelado (UML) se renombra dentro de la subclase. Especialización es una relación de implementación que destaca las similitudes de las clases. En el ejemplo anterior, los componentes comunes de las clases LCL_CAR, LCL_TRUCK y LCL_BUS se definen en el modelo UML de la clase superior, LCL_VEHICLE. Los componentes comunes de las subclases solo deben definirse e implementarse en la clase superior, y son heredados por todas las subclases. La especialización se describe como una relación "es un" semánticamente. Por ejemplo, un camión es un vehículo específico. Invertir el punto de vista opuesto es una generalización. Características de la generalización y la especialización
Figura 62: Características de la generalización/especialización
La generalización y la especialización proporciona una estructura significativamente mejor para su software, porque los elementos comúnmente utilizados solo deben almacenarse una vez en una ubicación central (en la clase superior). Estos elementos están disponibles automáticamente para todas las subclases. Los cambios realizados en una etapa posterior tienen un efecto inmediato en las subclases. Por lo tanto, no altere la semántica al modificar una clase superior. Se requieren conocimientos de la implementación de la clase superior para decidir si los componentes heredados de la clase superior son suficientes para la subclase o si deben ser ampliados. La generalización/especialización ofrece, por lo tanto, enlaces fuertes entre la clase superior y la subclase. Cuando desarrolla las subclases adicionales, adapte también las clases superiores. La creación de una subclase a veces conduce a requisitos adicionales para la clase superior. Por ejemplo, cuando una subclase requiere ciertos componentes protegidos o cuando se requieren cambios en los detalles de la implementación de la clase superior debido a las implementaciones de métodos en las subclases. El desarrollador de la clase superior no puede predecir todos los requisitos que las subclases necesitan de la clase superior.
© Copyright . Reservados todos los derechos.
109
Capítulo 3: Herencia y casting
Implementación de la herencia
Figura 63: Herencia – Sintaxis
En los objetos ABAP, una relación de herencia se define para una subclase utilizando el suplemento INHERITING FROM, seguido de la clase superior que se encuentra directamente por encima de la subclase. Por lo general, las jerarquías de herencia de complejidad variable pueden crearse cuando una clase superior hereda de otra; pero no hay herencia múltiple en los objetos ABAP, es decir, solo una clase superior puede especificarse directamente por encima de una clase. Sin embargo, puede utilizar las interfaces en los objetos ABAP para simular la herencia múltiple. La herencia debe utilizarse para implementar relaciones de generalización y especialización. Una clase superior es una generalización de sus subclases. Las subclases son, a su vez, diferentes especializaciones de sus clases superiores. Por lo tanto, se permiten suplementos o cambios en las subclases, pero nunca podrá eliminar nada de una clase superior en una subclase. La herencia es una relación unilateral. En otras palabras, las subclases reconocen sus clases superiores directas, pero las clases superiores no reconocen sus subclases. En este ejemplo, la subclase también contiene el método set_type. La subclase también define el método get_cargo.
110
© Copyright . Reservados todos los derechos.
Lección: Implementación de la herencia
Redefinición de métodos
Figura 64: Redefinición de métodos
La redefinición aparece cuando la implementación de un método de instancia heredado se modifica para una subclase sin cambiar la firma. Debido a que la sección de visibilidad de la clase superior debe permanecer igual, la redefinición no es posible en la PRIVATE SECTION. Si se utiliza el suplemento REDEFINITION, se deberá especificar una nueva parte de implementación para el método heredado. Dado que cabe la posibilidad de que la firma no haya cambiado, no es necesario definir de nuevo los parámetros y excepciones de método. En la parte de implementación redefinida del método, puede utilizar el prefijo predefinido “super->...” para acceder a los componentes de la clase superior. Es probable que deba recurrir a ello cuando se desea redefinir un método para que llame al método original de la clase superior. Mantenimiento de la semántica durante la redefinición
Figura 65: Mantenimiento de la semántica durante la redefinición
© Copyright . Reservados todos los derechos.
111
Capítulo 3: Herencia y casting
En este ejemplo, los dos métodos redefinidos proporcionan información completamente diferente. La semántica del método permanece igual.
Definición de constructores de subclase
Figura 66: Definición del constructor en las subclases
Una redefinición, como se describe para los métodos de arriba, no resulta útil en el caso del constructor. En la subclase, el constructor de la clase superior puede utilizarse sin cambios, o la subclase se amplía y se requieren nuevos parámetros en la firma del constructor. En los objetos ABAP, el constructor no se hereda como los métodos normales. Cualquier clase puede definir su propio constructor que es totalmente independiente de la definición del constructor en su clase superior. Una subclase incluso puede definir un constructor si no hay constructor en la clase superior. Sin embargo, cuando implementa el constructor de subclase, es obligatorio hacer referencia al constructor de la clase superior inmediata. Al hacer esto, se garantiza que el constructor de la clase se ejecutará siempre, no importa si el objeto creado es una instancia de la clase en sí o una instancia de una de sus subclases. Debido a esta llamada exigida del constructor de clase superior, el constructor de subclase normalmente añadirá los parámetros a la firma del constructor de la clase superior en lugar de cambiarla completamente.
Consejo: En este contexto, el concepto de sobrecarga es relevante. Con la sobrecarga, un método puede tener varias definiciones con distintas firmas y también distintas implementaciones. El concepto de la sobrecarga no se admite en los objetos ABAP. La solución alternativa frecuente es una firma con diferentes sets de parámetros opcionales. A diferencia de los constructores de instancia, el entorno de tiempo de ejecución garantiza de manera automática que los constructores estáticos de todas sus clases superiores ya se han
112
© Copyright . Reservados todos los derechos.
Lección: Implementación de la herencia
ejecutado antes de que el constructor estático, en una clase determinada, se ejecute en el sistema del tiempo de ejecución. Reglas para llamar al constructor
Figura 67: Reglas para llamar al constructor
Si una subclase no ha modificado su constructor de instancia, el constructor se adopta de la clase superior. La implementación también se hereda de la clase superior.
Herencia y visibilidad
Figura 68: Herencia y visibilidad
La herencia proporciona una ampliación del concepto de visibilidad a través de los componentes protegidos (PROTECTED SECTION). La visibilidad de los componentes
© Copyright . Reservados todos los derechos.
113
Capítulo 3: Herencia y casting
protegidos se encuentra entre los componentes públicos y privados. Los componentes protegidos son visibles para todas las subclases y para la clase en sí misma. Al definir clases locales en objetos ABAP, siga la secuencia sintáctica de PUBLIC SECTION, PROTECTED SECTION y PRIVATE SECTION. Sección de visibilidad – Protegida frente a privada
Figura 69: Sección protegida frente a sección privada
Es probable que los componentes heredados de la clase superior no sean visibles en la subclase. Una subclase puede recibir componentes privados de su clase superior que no pueden tratarse en la sintaxis de la subclase. Los componentes privados de las clases superiores solo pueden tratarse de forma indirecta con métodos públicos o protegidos de la clase superior que, a la vez, pueden acceder a los atributos privados. Estas restricciones son necesarias para garantizar que la actualización centralizada es posible. En este ejemplo, es posible acceder a la constante protegida C_POS_1 en la clase superior LCL_VEHICLE directamente desde su subclase LCL_BUS. Por otro lado, la única manera de acceder a los atributos privados MV_MAKE y MV_MODEL desde las subclases de LCL_VEHICLE es llamando los métodos de LCL_VEHICLE. Estos métodos deben ser públicos o deben estar protegidos. Mediante PRIVATE SECTION, es posible modificar clases superiores sin necesidad de conocer las subclases. Siempre que los cambios realizados no afecten a la semántica, no será necesario adaptar las subclases. Esto es debido a que estas solo acceden indirectamente a los componentes privados de la clase superior.
Herencia y componentes estáticos A continuación se detalla un resumen de componentes estáticos y herencia: ●
●
114
Una clase que define un atributo estático público o protegido comparte este atributo con todas sus subclases. Los métodos estáticos no pueden redefinirse.
© Copyright . Reservados todos los derechos.
Lección: Implementación de la herencia
●
●
●
El constructor estático de una clase superior se ejecuta cuando se accede por primera vez a la clase superior o a una de sus subclases. Una subclase siempre puede tener un constructor estático independientemente de la clase superior. Si una subclase y su clase superior tienen un constructor estático, ambos constructores se ejecutan cuando accedemos a la subclase por primera vez. En este caso, el primer acceso a la subclase es también el primer acceso a la clase superior.
© Copyright . Reservados todos los derechos.
115
Capítulo 3: Herencia y casting
116
© Copyright . Reservados todos los derechos.
Capítulo 3 Ejercicio 7 Implementar la herencia
Ejemplo empresarial Debe ajustar su programa de gestión de aviones. Cree las clases para aviones específicos con relación a una clase general de avión. Modelo SAPBC401_BAS_S5 Solución SAPBC401_INH_S1 Tarea 1 Defina la clase local LCL_PASSENGER_PLANE para los aviones de pasajeros. Defina la clase como subclase de LCL_AIRPLANE. Añada atributos y métodos específicos y redefina el método DISPLAY_ATTRIBUTES. 1. Complete el programa ZBC401_##_MAIN (donde ## es el número de grupo de dos cifras) o copie el programa modelo. Defina una nueva clase local LCL_PASSENGER_PLANE y defínala como una subclase de la ya existente LCL_AIRPLANE. 2. ¿Existe una secuencia específica en la cual debe definir las clases en el código fuente?
3. La clase debe tener un atributo de instancia privado, MV_SEATS, con el mismo tipo que el campo de tabla SFLIGHT-SEATSMAX. 4. Defina e implemente un constructor de instancia que asigne valores para todos los atributos de instancia de la clase. 5. Redefina el método DISPLAY_ATTRIBUTES de manera que se visualicen todos los atributos de instancia utilizando la sentencia WRITE. Asegúrese de que la presentación de los atributos específicos esté alineada con la presentación de la clase superior. Por lo tanto, cambie la visibilidad de la constante C_POS_1 para que pueda utilizarla en su subclase.
Tarea 2 En la clase LCL_AIRPLANE, defina la subclase local LCL_CARGO_PLANE para aviones de carga.
© Copyright . Reservados todos los derechos.
117
Capítulo 3: Herencia y casting
1. La clase debe tener un atributo de instancia privado, MV_CARGO, con el mismo tipo que el campo de tabla SCPLANE-CARGOMAX. 2. Defina e implemente un constructor de instancia que asigne valores para todos los atributos de instancia de la clase. 3. Redefina DISPLAY_ATTRIBUTES de manera que se visualicen todos los atributos de instancia utilizando la sentencia WRITE.
Tarea 3 Cree instancias de sus nuevas clases y visualice sus atributos. 1. En el programa principal, defina una variable de referencia tipificada correctamente para cada una de sus clases nuevas. 2. Antes de la instanciación de algún objeto, llame el método estático DISPLAY_N_O_AIRPLANES. 3. Utilice las dos referencias para crear una instancia de cada una de las subclases LCL_PASSENGER_PLANE y LCL_CARGO_PLANE. Decida cómo rellenar los atributos. 4. Llame el método DISPLAY_ATTRIBUTES para ambas instancias. 5. Llame el método estático DISPLAY_ATTRIBUTES por segunda vez.
Tarea 4 Depure su programa. 1. ¿Podría llamarse directamente el método GET_TECHNICAL_ATTRIBUTES desde el método redefinido DISPLAY_ATTRIBUTES de las subclases?
2. Observe el flujo de programa en el ABAP Debugger, prestando una especial atención a la llamada del método DISPLAY_ATTRIBUTES.
118
© Copyright . Reservados todos los derechos.
Capítulo 3 Solución 7 Implementar la herencia
Ejemplo empresarial Debe ajustar su programa de gestión de aviones. Cree las clases para aviones específicos con relación a una clase general de avión. Modelo SAPBC401_BAS_S5 Solución SAPBC401_INH_S1 Tarea 1 Defina la clase local LCL_PASSENGER_PLANE para los aviones de pasajeros. Defina la clase como subclase de LCL_AIRPLANE. Añada atributos y métodos específicos y redefina el método DISPLAY_ATTRIBUTES. 1. Complete el programa ZBC401_##_MAIN (donde ## es el número de grupo de dos cifras) o copie el programa modelo. Defina una nueva clase local LCL_PASSENGER_PLANE y defínala como una subclase de la ya existente LCL_AIRPLANE. a) Véase el extracto del código fuente de la solución modelo. 2. ¿Existe una secuencia específica en la cual debe definir las clases en el código fuente? Una clase superior debe definirse en primer lugar. De lo contrario, la verificación de sintaxis no la reconocerá cuando se refiera a la clase superior en la parte INHERITING FROM de la definición de subclase. 3. La clase debe tener un atributo de instancia privado, MV_SEATS, con el mismo tipo que el campo de tabla SFLIGHT-SEATSMAX. a) Véase el extracto del código fuente de la solución modelo. 4. Defina e implemente un constructor de instancia que asigne valores para todos los atributos de instancia de la clase. a) Véase el extracto del código fuente de la solución modelo. 5. Redefina el método DISPLAY_ATTRIBUTES de manera que se visualicen todos los atributos de instancia utilizando la sentencia WRITE. Asegúrese de que la presentación de los atributos específicos esté alineada con la presentación de la clase superior. Por lo tanto, cambie la visibilidad de la constante C_POS_1 para que pueda utilizarla en su subclase. a) Véase el extracto del código fuente de la solución modelo.
© Copyright . Reservados todos los derechos.
119
Capítulo 3: Herencia y casting
Tarea 2 En la clase LCL_AIRPLANE, defina la subclase local LCL_CARGO_PLANE para aviones de carga. 1. La clase debe tener un atributo de instancia privado, MV_CARGO, con el mismo tipo que el campo de tabla SCPLANE-CARGOMAX. a) Véase el extracto del código fuente de la solución modelo. 2. Defina e implemente un constructor de instancia que asigne valores para todos los atributos de instancia de la clase. a) Véase el extracto del código fuente de la solución modelo. 3. Redefina DISPLAY_ATTRIBUTES de manera que se visualicen todos los atributos de instancia utilizando la sentencia WRITE. a) Véase el extracto del código fuente de la solución modelo.
Tarea 3 Cree instancias de sus nuevas clases y visualice sus atributos. 1. En el programa principal, defina una variable de referencia tipificada correctamente para cada una de sus clases nuevas. a) Véase el extracto del código fuente de la solución modelo. 2. Antes de la instanciación de algún objeto, llame el método estático DISPLAY_N_O_AIRPLANES. a) Véase el extracto del código fuente de la solución modelo. 3. Utilice las dos referencias para crear una instancia de cada una de las subclases LCL_PASSENGER_PLANE y LCL_CARGO_PLANE. Decida cómo rellenar los atributos. a) Véase el extracto del código fuente de la solución modelo. 4. Llame el método DISPLAY_ATTRIBUTES para ambas instancias. a) Véase el extracto del código fuente de la solución modelo. 5. Llame el método estático DISPLAY_ATTRIBUTES por segunda vez. a) Véase el extracto del código fuente de la solución modelo.
Tarea 4 Depure su programa. 1. ¿Podría llamarse directamente el método GET_TECHNICAL_ATTRIBUTES desde el método redefinido DISPLAY_ATTRIBUTES de las subclases? No, porque el método es privado en la clase superior.
2. Observe el flujo de programa en el ABAP Debugger, prestando una especial atención a la llamada del método DISPLAY_ATTRIBUTES.
120
© Copyright . Reservados todos los derechos.
Lección: Implementación de la herencia
a) Realice este paso de la forma habitual. Solución: SAPBC401_INH_S1 REPORT
sapbc401_inh_s1.
TYPE-POOLS icon. *------------------------------------------------* * CLASS lcl_airplane DEFINITION *------------------------------------------------* CLASS lcl_airplane DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype EXCEPTIONS wrong_planetype, display_attributes. CLASS-METHODS: class_constructor, display_n_o_airplanes, get_n_o_airplanes RETURNING value(rv_count) TYPE i. PROTECTED SECTION. CONSTANTS: c_pos_1 TYPE i VALUE 30. PRIVATE SECTION. TYPES: ty_planetypes TYPE STANDARD TABLE OF saplane WITH NON-UNIQUE KEY planetype. DATA: mv_name mv_planetype mv_weight mv_tankcap
TYPE TYPE TYPE TYPE
string, saplane-planetype, saplane-weight, saplane-tankcap.
CLASS-DATA: gv_n_o_airplanes TYPE i, gt_planetypes TYPE ty_planetypes. CLASS-METHODS: get_technical_attributes IMPORTING iv_type TYPE saplane-planetype EXPORTING ev_weight TYPE saplane-weight ev_tankcap TYPE saplane-tankcap EXCEPTIONS wrong_planetype. ENDCLASS.
"lcl_airplane DEFINITION
© Copyright . Reservados todos los derechos.
121
Capítulo 3: Herencia y casting
*-------------------------------------------------* * CLASS lcl_airplane IMPLEMENTATION *-------------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. METHOD class_constructor. SELECT * FROM saplane INTO TABLE gt_planetypes. ENDMETHOD. "class_constructor METHOD constructor. mv_name = iv_name. mv_planetype = iv_planetype. get_technical_attributes( EXPORTING iv_type = iv_planetype IMPORTING ev_weight = mv_weight ev_tankcap = mv_tankcap EXCEPTIONS wrong_planetype = 1 ). IF sy-subrc <> 0. RAISE wrong_planetype. ELSE. gv_n_o_airplanes = gv_n_o_airplanes + 1. ENDIF. ENDMETHOD.
"constructor
METHOD display_attributes. WRITE: / icon_ws_plane AS ICON, / 'Name of Airplane'(001) , / 'Type of Airplane:'(002), / 'Weight:'(003), LEFT-JUSTIFIED, / 'Tank capacity:'(004), LEFT-JUSTIFIED. ENDMETHOD.
AT c_pos_1 mv_name, AT c_pos_1 mv_planetype, AT c_pos_1 mv_weight AT c_pos_1 mv_tankcap
"display_attributes
METHOD display_n_o_airplanes. SKIP. WRITE: / 'Number of airplanes:'(ca1), AT c_pos_1 gv_n_o_airplanes LEFT-JUSTIFIED. ENDMETHOD. "display_n_o_airplanes METHOD get_n_o_airplanes. rv_count = gv_n_o_airplanes. ENDMETHOD. "get_n_o_airplanes METHOD get_technical_attributes. DATA: ls_planetype TYPE saplane. READ TABLE gt_planetypes INTO ls_planetype WITH TABLE KEY planetype = iv_type TRANSPORTING weight tankcap. IF sy-subrc = 0.
122
© Copyright . Reservados todos los derechos.
Lección: Implementación de la herencia
ev_weight = ls_planetype-weight. ev_tankcap = ls_planetype-tankcap. ELSE. RAISE wrong_planetype. ENDIF. ENDMETHOD. "get_technical_attributes ENDCLASS.
"lcl_airplane IMPLEMENTATION
*------------------------------------------------* * CLASS lcl_cargo_plane DEFINITION *------------------------------------------------* CLASS lcl_cargo_plane DEFINITION INHERITING FROM lcl_airplane. PUBLIC SECTION. METHODS: constructor IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype iv_cargo TYPE s_plan_car EXCEPTIONS wrong_planetype, display_attributes REDEFINITION. PRIVATE SECTION. DATA: mv_cargo TYPE s_plan_car. ENDCLASS.
"lcl_cargo_plane DEFINITION
*------------------------------------------------* * CLASS lcl_cargo_plane IMPLEMENTATION *------------------------------------------------* CLASS lcl_cargo_plane IMPLEMENTATION. METHOD constructor. super->constructor( EXPORTING iv_name = iv_name iv_planetype = iv_planetype EXCEPTIONS wrong_planetype = 1 ). IF sy-subrc <> 0. RAISE wrong_planetype. ENDIF. mv_cargo = iv_cargo. ENDMETHOD. "constructor METHOD display_attributes. super->display_attributes( ). WRITE: / 'Max Cargo:'(005), AT c_pos_1 mv_cargo LEFT-JUSTIFIED. ULINE. ENDMETHOD. "display_attributes
© Copyright . Reservados todos los derechos.
123
Capítulo 3: Herencia y casting
ENDCLASS.
"lcl_cargo_plane IMPLEMENTATION
*------------------------------------------------* * CLASS lcl_passenger_plane DEFINITION *------------------------------------------------* CLASS lcl_passenger_plane DEFINITION INHERITING FROM lcl_airplane. PUBLIC SECTION. METHODS: constructor IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype iv_seats TYPE s_seatsmax EXCEPTIONS wrong_planetype, display_attributes REDEFINITION. PRIVATE SECTION. DATA: mv_seats TYPE s_seatsmax. ENDCLASS.
"lcl_passenger_plane DEFINITION
*------------------------------------------------* * CLASS lcl_passenger_plane IMPLEMENTATION *------------------------------------------------* CLASS lcl_passenger_plane IMPLEMENTATION. METHOD constructor. super->constructor( EXPORTING iv_name = iv_name iv_planetype = iv_planetype EXCEPTIONS wrong_planetype = 1 ). IF sy-subrc <> 0. RAISE wrong_planetype. ENDIF. mv_seats = iv_seats. ENDMETHOD. "constructor METHOD display_attributes. super->display_attributes( ). WRITE: / 'Max Seats:'(006), AT c_pos_1 mv_seats LEFT-JUSTIFIED. ULINE. ENDMETHOD. "display_attributes ENDCLASS. "lcl_passenger_plane IMPLEMENTATION DATA: go_airplane go_cargo go_passenger gt_airplanes gv_count
124
TYPE TYPE TYPE TYPE TYPE
REF TO lcl_airplane, REF TO lcl_cargo_plane, REF TO lcl_passenger_plane, TABLE OF REF TO lcl_airplane, i.
© Copyright . Reservados todos los derechos.
Lección: Implementación de la herencia
START-OF-SELECTION. ******************* lcl_airplane=>display_n_o_airplanes( ). CREATE OBJECT go_passenger EXPORTING iv_name = 'LH BERLIN' iv_planetype = '747-400' iv_seats = 345 EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. * do nothing for now ENDIF. CREATE OBJECT go_cargo EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' iv_cargo = 533 EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. * do nothing just now ENDIF. go_passenger->display_attributes( ). go_cargo->display_attributes( ). gv_count = lcl_airplane=>get_n_o_airplanes( ). SKIP 2. WRITE: / 'Number of airplanes'(ca1), gv_count.
© Copyright . Reservados todos los derechos.
125
Capítulo 3: Herencia y casting
RESUMEN DE LA LECCIÓN Ahora podrá:
126
●
Explicar la generalización y la especialización
●
Implementar la herencia
●
Acceder a los elementos de las clases en la herencia
© Copyright . Reservados todos los derechos.
Capítulo 3 Lección 2 Implementación de conversiones Up-Cast mediante la herencia
RESUMEN DE LA LECCIÓN Este módulo explica el concepto de los up-casts y los tipos de variable de referencia dinámicos y estáticos. Este módulo también explica el método de implementación de up -casts. Ejemplo empresarial Como desarrollador, necesita implementar el concepto de up-cast para sus clases de objeto ABAP. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de la herencia
●
Una buena comprensión de los up-casts
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Implementar conversiones Up-Cast mediante la herencia
La conversión Up-Cast
Figura 70: Conversión Up-Cast (widening cast) con referencias de objeto
Si se asigna una referencia de subclase a una referencia de clase superior, esta subclase garantiza que todos los componentes a los que puede acceder sintácticamente después de la asignación cast están disponibles en la instancia. La subclase siempre contiene, al menos, los
© Copyright . Reservados todos los derechos.
127
Capítulo 3: Herencia y casting
mismos componentes que la clase superior, y el nombre y la firma de los métodos redefinidos son idénticos. El usuario solo puede dirigirse a estos métodos y atributos desde la instancia de subclase a la que pueden desde la instancia de clase superior.
Consejo: Tenga en cuenta que con los métodos redefinidos, se debe tener en cuenta que la implementación de la subclase se ejecuta mediante el tipo estático de clase superior de referencia. En este ejemplo, tras la asignación, solo podrá acceder a los métodos GET_MAKE, GET_COUNT, DISPLAY_ATTRIBUTES, SET_ATTRIBUTES y ESTIMATE_FUEL de la instancia LCL_TRUCK mediante la referencia GO_VEHICLE. Si hay restricciones de visibilidad, no se modificarán. No es posible acceder a los componentes específicos desde la clase LCL_TRUCK de la instancia GET_CARGO del ejemplo mediante la referencia GO_VEHICLE. Se restringe o no se modifica la vista o el posible acceso a los métodos. Hay un cambio de una vista de varios componentes a una vista de pocos componentes. Dado que la variable destino puede aceptar más tipos dinámicos en comparación con la variable fuente, esta asignación también se denomina widening cast.
Tipo estático y dinámico
Figura 71: Tipos estáticos y dinámicos de referencias
Tipos de una variable de referencia en el tiempo de ejecución en la programación orientada a objetos: ● Estática ●
Dinámica
En el ejemplo, LCL_VEHICLE es el tipo estático de la variable GO_VEHICLE. En función de la asignación cast, el tipo dinámico es LCL_BUS o LCL_TRUCK. En el ABAP Debugger, el tipo dinámico se especifica en la forma siguiente: object_id<\PROGRAM=program_name\CLASS=dynamic_type>
128
© Copyright . Reservados todos los derechos.
Lección: Implementación de conversiones Up-Cast mediante la herencia
Nota: Las asignaciones entre variables de referencia son posibles siempre que el tipo estático de las variables destino sea más general o equivalente al tipo dinámico de las variables fuente.
© Copyright . Reservados todos los derechos.
129
Capítulo 3: Herencia y casting
130
© Copyright . Reservados todos los derechos.
Capítulo 3 Ejercicio 8 Implementar up-casts
Ejemplo empresarial Como desarrollador, su programa de gestión de aviones debería visualizar los atributos de los objetos de avión de manera genérica, es decir, debería estar abierto a futuras ampliaciones con clases de avión adicionales. Modelo SAPBC401_INH_S1 Solución SAPBC401_INH_S2 Tarea 1 Grabe las referencias de avión en memoria intermedia en un tipo adecuado de tabla interna. 1. Complete su programa ZBC401_##_MAIN (## es su número de grupo de dos cifras) o copie la el programa de la solución modelo del ejercicio anterior. 2. En el programa principal, defina una tabla interna para grabar en memoria intermedia referencias de avión, si es que aún no tiene una. El tipo de línea de la tabla interna debería ser REF TO LCL_AIRPLANE.
Tarea 2 Visualice los atributos de todos los tipos de aviones que se han creado hasta ahora. 1. Inserte las referencias a los aviones de pasajeros y de carga en la tabla interna. 2. Programe un loop a través de los contenidos de la tabla interna. Llame el método DISPLAY_ATTRIBUTES cada vez que se ejecute el loop.
Tarea 3 Analice el programa. 1. ¿Qué pasaría si el método DISPLAY_ATTRIBUTES no hubiera sido redefinido en las subclases?
2. Siga el flujo de programa en el ABAP Debugger, prestando especial atención a la llamada del método DISPLAY_ATTRIBUTES.
© Copyright . Reservados todos los derechos.
131
Capítulo 3 Solución 8 Implementar up-casts
Ejemplo empresarial Como desarrollador, su programa de gestión de aviones debería visualizar los atributos de los objetos de avión de manera genérica, es decir, debería estar abierto a futuras ampliaciones con clases de avión adicionales. Modelo SAPBC401_INH_S1 Solución SAPBC401_INH_S2 Tarea 1 Grabe las referencias de avión en memoria intermedia en un tipo adecuado de tabla interna. 1. Complete su programa ZBC401_##_MAIN (## es su número de grupo de dos cifras) o copie la el programa de la solución modelo del ejercicio anterior. a) Lleve a cabo este paso de la manera habitual. Encontrará información adicional en la biblioteca SAP. 2. En el programa principal, defina una tabla interna para grabar en memoria intermedia referencias de avión, si es que aún no tiene una. El tipo de línea de la tabla interna debería ser REF TO LCL_AIRPLANE. a) Véase el extracto del código fuente de la solución modelo.
Tarea 2 Visualice los atributos de todos los tipos de aviones que se han creado hasta ahora. 1. Inserte las referencias a los aviones de pasajeros y de carga en la tabla interna. a) Véase el extracto del código fuente de la solución modelo. 2. Programe un loop a través de los contenidos de la tabla interna. Llame el método DISPLAY_ATTRIBUTES cada vez que se ejecute el loop. a) Véase el extracto del código fuente de la solución modelo.
Tarea 3 Analice el programa.
132
© Copyright . Reservados todos los derechos.
Lección: Implementación de conversiones Up-Cast mediante la herencia
1. ¿Qué pasaría si el método DISPLAY_ATTRIBUTES no hubiera sido redefinido en las subclases? La implementación se ejecutaría desde la clase superior. Su programa no tendría polimorfismo. 2. Siga el flujo de programa en el ABAP Debugger, prestando especial atención a la llamada del método DISPLAY_ATTRIBUTES. a) Lleve a cabo este paso de la manera habitual. Encontrará información adicional en la biblioteca SAP. SAPBC401_INH_S2 REPORT sapbc401_inh_s2. TYPE-POOLS icon. *-----------------------------------------------* * CLASS lcl_airplane DEFINITION *-----------------------------------------------* CLASS lcl_airplane DEFINITION. ... ENDCLASS. "lcl_airplane DEFINITION *-----------------------------------------------* * CLASS lcl_airplane IMPLEMENTATION *-----------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. ... ENDCLASS. "lcl_airplane IMPLEMENTATION *-----------------------------------------------* * CLASS lcl_cargo_plane DEFINITION *-----------------------------------------------* CLASS lcl_cargo_plane DEFINITION INHERITING FROM lcl_airplane. ... ENDCLASS. "lcl_cargo_plane DEFINITION *-----------------------------------------------* *CLASS lcl_cargo_plane IMPLEMENTATION *-----------------------------------------------* CLASS lcl_cargo_plane IMPLEMENTATION. ... ENDCLASS. "lcl_cargo_plane IMPLEMENTATION *-----------------------------------------------* * CLASS lcl_passenger_plane DEFINITION *-----------------------------------------------* CLASS lcl_passenger_plane DEFINITION INHERITING FROM lcl_airplane. ... ENDCLASS. "lcl_passenger_plane DEFINITION *-----------------------------------------------* * CLASS lcl_passenger_plane IMPLEMENTATION *-----------------------------------------------* CLASS lcl_passenger_plane IMPLEMENTATION. ... ENDCLASS. "lcl_passenger_plane IMPLEMENTATION
© Copyright . Reservados todos los derechos.
133
Capítulo 3: Herencia y casting
DATA: go_airplane TYPE REF TO lcl_airplane, go_cargo TYPE REF TO lcl_cargo_plane, go_passenger TYPE REF TO lcl_passenger_plane, gt_airplanes TYPE TABLE OF REF TO lcl_airplane, gv_count TYPE i.
START-OF-SELECTION. ******************* lcl_airplane=>display_n_o_airplanes( ). CREATE OBJECT go_passenger EXPORTING iv_name = 'LH BERLIN' iv_planetype = '747-400' iv_seats = 345 EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. APPEND go_passenger TO gt_airplanes. ENDIF. CREATE OBJECT go_cargo EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' iv_cargo = 533 EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. APPEND go_cargo TO gt_airplanes. ENDIF. LOOP AT gt_airplanes INTO go_airplane. go_airplane->display_attributes( ). ENDLOOP. gv_count = lcl_airplane=>get_n_o_airplanes( ). SKIP 2. WRITE: / 'Number of airplanes'(ca1), gv_count.
134
© Copyright . Reservados todos los derechos.
Lección: Implementación de conversiones Up-Cast mediante la herencia
RESUMEN DE LA LECCIÓN Ahora podrá: ●
Implementar conversiones Up-Cast mediante la herencia
© Copyright . Reservados todos los derechos.
135
Capítulo 3 Lección 3 Implementación de polimorfismo con herencia
RESUMEN DE LA LECCIÓN Este módulo explica el polimorfismo y la implementación del polimorfismo con la herencia. Ejemplo empresarial Como desarrollador, necesita implementar el polimorfismo con la herencia. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión del polimorfismo
●
Una buena comprensión del acceso genérico y las asignaciones upcast
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Explicar el polimorfismo
●
Implementar el polimorfismo mediante la herencia
Acceso genérico
Figura 72: Acceso genérico después de asignaciones up cast
Un uso típico de asignaciones up cast es la preparación para el acceso genérico. Un usuario que no tiene interés en los puntos concretos de las instancias de las subclases, pero simplemente quiere dirigirse a los componentes compartidos, puede utilizar una referencia de clase superior para este acceso.
136
© Copyright . Reservados todos los derechos.
Lección: Implementación de polimorfismo con herencia
En el ejemplo, una agencia de viajes LCL_RENTAL necesita gestionar todo tipo de vehículos en una lista. Para gestionar todos los vehículos de una lista, necesita crear una tabla interna y asignarla con un tipo adecuado para las referencias a las instancias de vehículos. La compañía de vehículos de alquiler también necesita poder calcular solo la cantidad necesaria de combustible para todos sus vehículos. En este caso, el método DISPLAY_ATTRIBUTES se define en la clase superior LCL_VEHICLE y se redefine en todas las subclases. Tipo de línea de la tabla interna en la aplicación: ejemplo
Figura 73: Tipo de línea de la tabla interna en la aplicación: ejemplo
Cuando los objetos de distintas clases (LCL_BUS, LCL_TRUCK y LCL_CAR) se especifican como referencias de clase superior de tipo (LCL_VEHICLE), se pueden almacenar en una tabla interna. Así, se podrá acceder a los componentes compartidos de los objetos de subclase de forma uniforme. Para este ejemplo, necesita el método ADD_VEHICLE para copiar las referencias a los tipos de vehículos en la tabla interna. El parámetro de importación de este método ya está indicado como la referencia a la clase superior. Up cast y acceso genérico en la aplicación: ejemplo
Figura 74: Up cast y acceso genérico en la aplicación: ejemplo
© Copyright . Reservados todos los derechos.
137
Capítulo 3: Herencia y casting
En este ejemplo, la asignación up cast se produce cuando la referencia del vehículo se transfiere al parámetro formal del método ADD_VEHICLE. Genéricamente se accede al componente compartido dentro del loop de la tabla interna que contiene todas las referencias de vehículo. El método DISPLAY_ATTRIBUTES ha sido heredado de la clase superior LCL_VEHICLE y cabe la posibilidad de que se haya redefinido.
Polimorfismo
Figura 75: Polimorfismo: acceso genérico mediante la referencia de clase superior
La implementación que se ejecutará cuando se llama DISPLAY_ATTRIBUTES depende de a qué objeto hace referencia la clase superior LO_VEHICLE. Se utiliza el tipo dinámico (y no el tipo estático) de la variable de referencia para buscar la implementación de un método. Por lo tanto, cuando se llama lo_vehicle->display_attributes, la implementación no se ejecuta desde LCL_VEHICLE (tipo estático de LO_VEHICLE), dado que el método ha sido redefinido en todas las clases de vehículo. Cuando una instancia recibe un mensaje para que ejecute un método concreto, se ejecuta el método que implementó la clase de esta instancia. Si la clase no se ha redefinido en el método, se ejecuta la implementación desde la clase superior. Características del polimorfismo Cuando los objetos de distintas clases reaccionan de manera distinta a las mismas llamadas del método, hablamos de polimorfismo. La posibilidad de polimorfismo es uno de los puntos fuertes principales de la herencia. Un cliente puede tratar diferentes clases de manera uniforme, independientemente de su implementación. El sistema de tiempo de ejecución busca la implementación correcta de un método con la ayuda del cliente. El polimorfismo puede utilizarse para escribir programas altamente genéricos, es decir, que no necesitan cambiarse de manera significativa si se añaden casos de uso. Por ejemplo, con el polimorfismo, resulta muy fácil añadir motocicletas a este ejemplo. Solo debe definir una nueva subclase de LCL_VEHICLE, que podría denominar LCL_MOTORBIKE. También se debe redefinir el método heredado DISPLAY_ATTRIBUTES. Sin necesidad de realizar más cambios, su sistema de gestión de vehículos podrá trabajar también con motocicletas y calcular también los niveles de combustible necesarios para ellas.
138
© Copyright . Reservados todos los derechos.
Lección: Implementación de polimorfismo con herencia
Llamadas genéricas en el modelo de programación procedimental
Figura 76: Llamadas genéricas en el modelo de programación procedimental
Mediante el uso de las llamadas de módulos de funciones dinámicos, es posible programar de manera genérica en objetos ABAP, incluso sin un modelo de programación orientado a objetos. Cuando compara el módulo de función dinámica con el polimorfismo a través de la herencia, el código fuente es menos sencillo y más susceptible a los errores en la llamada del módulo de función dinámico. Por ejemplo, la verificación de sintaxis solo puede verificar si el modelo de función se llama de manera correcta o no. La verificación de sintaxis no puede verificar si la tabla interna tiene, o no, un nombre de módulo de función válido para cada vehículo.
© Copyright . Reservados todos los derechos.
139
Capítulo 3: Herencia y casting
140
© Copyright . Reservados todos los derechos.
Capítulo 3 Ejercicio 9 Implementar el polimorfismo mediante la herencia
Ejemplo empresarial Necesita encapsular la administración de las instancias de aviones en una clase nueva en lugar de en el programa principal. Modelo SAPBC401_INH_T3 Solución SAPBC401_INH_S3 Tarea 1 Defina una clase local para compañías aéreas. 1. Complete el programa ZBC401_##_MAIN (donde ## es el número de grupo de dos cifras) o copie el programa modelo. Si copia el programa modelo, puede acceder directamente al próximo paso. De lo contrario, copie la clase local LCL_CARRIER con la definición e implementación de la clase del programa modelo y péguela en su propio programa. 2. Defina un atributo de instancia privada MT_AIRPLANES para almacenar las referencias de aviones. 3. Defina e implemente el método público ADD_AIRPLANE para que las referencias de aviones puedan añadirse a la lista MT_AIRPLANES definida anteriormente. El método debe tener un parámetro de importación: IO_PLANE. 4. Defina e implemente un método de instancia privada DISPLAY_AIRPLANES. En este método, establezca un bucle en la lista de aviones y llame al método DISPLAY_ATTRIBUTES para cada avión. 5. Amplíe la implementación del método DISPLAY_ATTRIBUTES de modo que no solo muestre la información sobre la compañía aérea sino también sobre sus aviones. Utilice el método definido anteriormente DISPLAY_AIRPLANES_METHOD.
Tarea 2 En el programa principal, cree una instancia de línea aérea. Transfiérale algunas referencias de avión a la instancia de la compañía aérea y visualice los atributos. 1. Elimine todas las sentencias del programa principal que definen la tabla interna global de referencias de avión y sus inserciones. 2. En el programa principal, defina una variable de referencia tipificada correctamente para su nueva clase de compañía aérea.
© Copyright . Reservados todos los derechos.
141
Capítulo 3: Herencia y casting
3. Mediante la referencia, genere una instancia de la clase LCL_CARRIER. Decida cómo rellenar los atributos. 4. Llame al método ADD_AIRPLANE para transferir cada instancia de avión a la compañía aérea. También puede crear y transferir aviones adicionales. 5. Visualice los atributos de la compañía aérea llamando su método DISPLAY_ATTRIBUTES.
142
© Copyright . Reservados todos los derechos.
Capítulo 3 Solución 9 Implementar el polimorfismo mediante la herencia
Ejemplo empresarial Necesita encapsular la administración de las instancias de aviones en una clase nueva en lugar de en el programa principal. Modelo SAPBC401_INH_T3 Solución SAPBC401_INH_S3 Tarea 1 Defina una clase local para compañías aéreas. 1. Complete el programa ZBC401_##_MAIN (donde ## es el número de grupo de dos cifras) o copie el programa modelo. Si copia el programa modelo, puede acceder directamente al próximo paso. De lo contrario, copie la clase local LCL_CARRIER con la definición e implementación de la clase del programa modelo y péguela en su propio programa. a) Realice este paso de la forma habitual. Encontrará información adicional en la biblioteca SAP. b) Consulte el extracto del código fuente de la solución modelo. 2. Defina un atributo de instancia privada MT_AIRPLANES para almacenar las referencias de aviones. a) Consulte el extracto del código fuente de la solución modelo. 3. Defina e implemente el método público ADD_AIRPLANE para que las referencias de aviones puedan añadirse a la lista MT_AIRPLANES definida anteriormente. El método debe tener un parámetro de importación: IO_PLANE. a) Consulte el extracto del código fuente de la solución modelo. 4. Defina e implemente un método de instancia privada DISPLAY_AIRPLANES. En este método, establezca un bucle en la lista de aviones y llame al método DISPLAY_ATTRIBUTES para cada avión. a) Consulte el extracto del código fuente de la solución modelo. 5. Amplíe la implementación del método DISPLAY_ATTRIBUTES de modo que no solo muestre la información sobre la compañía aérea sino también sobre sus aviones. Utilice el método definido anteriormente DISPLAY_AIRPLANES_METHOD. a) Consulte el extracto del código fuente de la solución modelo.
© Copyright . Reservados todos los derechos.
143
Capítulo 3: Herencia y casting
Tarea 2 En el programa principal, cree una instancia de línea aérea. Transfiérale algunas referencias de avión a la instancia de la compañía aérea y visualice los atributos. 1. Elimine todas las sentencias del programa principal que definen la tabla interna global de referencias de avión y sus inserciones. a) Consulte el extracto del código fuente de la solución modelo. 2. En el programa principal, defina una variable de referencia tipificada correctamente para su nueva clase de compañía aérea. a) Consulte el extracto del código fuente de la solución modelo. 3. Mediante la referencia, genere una instancia de la clase LCL_CARRIER. Decida cómo rellenar los atributos. a) Consulte el extracto del código fuente de la solución modelo. 4. Llame al método ADD_AIRPLANE para transferir cada instancia de avión a la compañía aérea. También puede crear y transferir aviones adicionales. a) Consulte el extracto del código fuente de la solución modelo. 5. Visualice los atributos de la compañía aérea llamando su método DISPLAY_ATTRIBUTES. a) Consulte el extracto del código fuente de la solución modelo. SAPBC401_INH_S3 REPORT sapbc401_inh_s3. TYPE-POOLS icon. *------------------------------------------------* * CLASS lcl_airplane DEFINITION *------------------------------------------------* CLASS lcl_airplane DEFINITION. ... ENDCLASS. "lcl_airplane DEFINITION *------------------------------------------------* * CLASS lcl_airplane IMPLEMENTATION *------------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. ... ENDCLASS. "lcl_airplane IMPLEMENTATION *------------------------------------------------* * CLASS lcl_cargo_plane DEFINITION *------------------------------------------------* CLASS lcl_cargo_plane DEFINITION INHERITING FROM lcl_airplane. ... ENDCLASS. "lcl_cargo_plane DEFINITION *------------------------------------------------* * CLASS lcl_cargo_plane IMPLEMENTATION *------------------------------------------------* CLASS lcl_cargo_plane IMPLEMENTATION. ... ENDCLASS. "lcl_cargo_plane IMPLEMENTATION
144
© Copyright . Reservados todos los derechos.
Lección: Implementación de polimorfismo con herencia
*------------------------------------------------* * CLASS lcl_passenger_plane DEFINITION *------------------------------------------------* CLASS lcl_passenger_plane DEFINITION INHERITING FROM lcl_airplane. ... ENDCLASS. "lcl_passenger_plane DEFINITION *------------------------------------------------* * CLASS lcl_passenger_plane IMPLEMENTATION *------------------------------------------------* CLASS lcl_passenger_plane IMPLEMENTATION. ... ENDCLASS. "lcl_passenger_plane IMPLEMENTATION *------------------------------------------------* * CLASS lcl_carrier DEFINITION *------------------------------------------------* CLASS lcl_carrier DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING iv_name TYPE string, display_attributes, add_airplane IMPORTING io_plane TYPE REF TO lcl_airplane. PRIVATE SECTION. DATA: mv_name TYPE string, mt_airplanes TYPE TABLE OF REF TO lcl_airplane. METHODS: display_airplanes. ENDCLASS. "lcl_carrier DEFINITION *------------------------------------------------* * CLASS lcl_carrier IMPLEMENTATION *------------------------------------------------* CLASS lcl_carrier IMPLEMENTATION. METHOD constructor. mv_name = iv_name. ENDMETHOD. "constructor METHOD display_attributes. SKIP 2. WRITE: icon_flight AS ICON, mv_name. ULINE. ULINE. me->display_airplanes( ). ENDMETHOD. "display_attributes METHOD add_airplane. APPEND io_plane TO mt_airplanes. ENDMETHOD. "add_airplane METHOD display_airplanes. DATA: lo_plane TYPE REF TO lcl_airplane. LOOP AT mt_airplanes INTO lo_plane. lo_plane->display_attributes( ). ENDLOOP.
© Copyright . Reservados todos los derechos.
145
Capítulo 3: Herencia y casting
ENDMETHOD. "display_airplanes ENDCLASS. "lcl_carrier IMPLEMENTATION DATA: go_carrier TYPE REF TO lcl_carrier, go_airplane TYPE REF TO lcl_airplane, go_cargo TYPE REF TO lcl_cargo_plane, go_passenger TYPE REF TO lcl_passenger_plane, gv_count TYPE i. START-OF-SELECTION. ******************* ***** Create Carrier CREATE OBJECT go_carrier EXPORTING iv_name = 'Smile&Fly-Travel'. ***** Passenger Plane CREATE OBJECT go_passenger EXPORTING iv_name = 'LH BERLIN' iv_planetype = '747-400' iv_seats = 345 EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. go_carrier->add_airplane( go_passenger ). ENDIF. ***** cargo Plane CREATE OBJECT go_cargo EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' iv_cargo = 533 EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. go_carrier->add_airplane( go_cargo ). ENDIF. ***** output carrier (including list of airplanes) go_carrier->display_attributes( ).
146
© Copyright . Reservados todos los derechos.
Lección: Implementación de polimorfismo con herencia
RESUMEN DE LA LECCIÓN Ahora podrá: ●
Explicar el polimorfismo
●
Implementar el polimorfismo mediante la herencia
© Copyright . Reservados todos los derechos.
147
Capítulo 3 Lección 4 Implementación down-casts mediante la herencia
RESUMEN DE LA LECCIÓN Este módulo explica el concepto de las asignaciones down-cast (narrowing cast). Ejemplo empresarial Como desarrollador, necesita crear una subclase de la clase de avión y luego usar casting para acceder a los distintos atributos. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de los down-casts
●
Una buena comprensión de la herencia
●
Una buena comprensión de la implementación de down-casts con la herencia
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Implementar conversiones down-cast con la herencia
●
Modelar jerarquías de clases
Down-cast
Figura 77: Down-cast (narrowing cast) con referencias de objeto
148
© Copyright . Reservados todos los derechos.
Lección: Implementación down-casts mediante la herencia
Las variables de referencia de la clase superior también pueden hacer referencia a las instancias de subclase en tiempo de ejecución. Puede copiar esta referencia nuevamente a una variable de referencia del tipo de subclase. Para asignar una referencia de clase superior a una referencia de subclase, debe utilizar el operador de asignación down-cast MOVE ... ?TO ... o su forma breve ?=. Sino, obtendrá un mensaje indicando que no es seguro que todos los componentes a los que se puede acceder sintácticamente después de la asignación cast estén disponibles en la actualidad en la instancia. Como regla, la clase de subclase contiene más componentes que la clase superior. Después de asignar este tipo de referencia de vuelta a una referencia de subclase de la clase de implementación, los clientes ya no estarán limitados a componentes heredados. En el ejemplo expuesto aquí, puede acceder de nuevo a todos los componentes de la instancia LCL_TRUCK después de la asignación mediante la referencia GO_TRUCK2. Por lo tanto, la vista suele ampliarse o no modificarse. Este tipo de asignación de variables de referencia se conoce como down-cast. Existe un cambio de una vista de algunos componentes a una vista de varios componentes. Ya que la variable destino puede aceptar menos tipos dinámicos después de la asignación, esta asignación también se denomina narrowing cast. Acceso específico después de asignaciones down-cast
Figura 78: Acceso específico después de asignaciones down-cast
Las asignaciones down-cast se usan cuando necesita abordar componentes específicos de las instancias y mantener las referencias de estos componentes en variables que se indican en la clase superior. Un usuario que tiene interés en los puntos concretos de las instancias de una subclase no puede utilizar la referencia de clase superior para este acceso porque solo permite el acceso a los componentes compartidos.
© Copyright . Reservados todos los derechos.
149
Capítulo 3: Herencia y casting
Tratamiento de excepciones para down-casts
Figura 79: Down cast y tratamiento de excepciones en la aplicación: ejemplo
En este ejemplo, una compañía de vehículos de alquiler (LCL_RENTAL) debe determinar la capacidad máxima de sus camiones, pero almacena todos los tipos de referencias de vehículo en una tabla interna LCL_VEHICLE. Podría haber un problema si no hay ninguna referencia de camión en la referencia de clase superior LO_VEHICLE en tiempo de ejecución, pero el operador de asignación down-cast intenta copiar la referencia a la referencia no válida LO_TRUCK. Al contrario que la asignación up-cast, es posible que el tipo estático de la variable destino (LO_TRUCK) no sea ni más general ni igual que el tipo dinámico de la variable fuente (LO_VEHICLE), cuando LO_VEHICLE contiene referencias de bus o de coche deportivo. Esta es la razón por la que, con esta clase de cast, el sistema de tiempo de ejecución verifica, antes de la asignación, si el contenido actual de la variable fuente corresponde a los requisitos de tipo de la variable destino. Si no es así, se desencadena una excepción que puede tratarse, y el valor original de la variable destino seguirá siendo el mismo. Puede identificar esta excepción de clase de error CX_SY_MOVE_CAST_ERROR mediante TRY-ENDTRY y la sentencia CATCH. Otra manera de prevenir este error de tiempo de ejecución es utilizar clases de identificación de tipo de tiempo de ejecución (RTTI). Pueden utilizar clases RTTI para determinar el tipo dinámico en el tiempo de ejecución y fijar una condición para el cast.
150
© Copyright . Reservados todos los derechos.
Capítulo 3 Ejercicio 10 Implementar down-casts
Ejemplo empresarial Como desarrollador, diseñe una aplicación donde desea saber cuál es la mayor carga de todos los aviones de carga sin conocer los detalles. Modelo: SAPBC401_INH_S3 Solución: SAPBC401_INH_S3_OPT Determine el valor de carga máxima. 1. En la clase LCL_CARGO_PLANE, defina e implemente el método público y funcional GET_CARGO para devolver el valor de carga. Defina el parámetro de retorno RV_CARGO. 2. En la clase LCL_CARRIER, defina e implemente el método funcional privado GET_MAX_CARGO para calcular el valor de carga máxima (capacidad de carga) de todos los aviones de carga. Establezca un bucle en la lista de aviones y utilice una técnica de down cast para identificar a los aviones de carga. Para aquellos aviones para los que el down cast fue exitoso, puede llamar al método GET_CARGO que definió e implementó en el paso anterior. 3. Llame al método GET_MAX_CARGO desde el método DISPLAY_ATTRIBUTES de la clase LCL_CARRIER y visualice el resultado.
© Copyright . Reservados todos los derechos.
151
Capítulo 3 Solución 10 Implementar down-casts
Ejemplo empresarial Como desarrollador, diseñe una aplicación donde desea saber cuál es la mayor carga de todos los aviones de carga sin conocer los detalles. Modelo: SAPBC401_INH_S3 Solución: SAPBC401_INH_S3_OPT Determine el valor de carga máxima. 1. En la clase LCL_CARGO_PLANE, defina e implemente el método público y funcional GET_CARGO para devolver el valor de carga. Defina el parámetro de retorno RV_CARGO. a) Véase el extracto del código fuente de la solución modelo. 2. En la clase LCL_CARRIER, defina e implemente el método funcional privado GET_MAX_CARGO para calcular el valor de carga máxima (capacidad de carga) de todos los aviones de carga. Establezca un bucle en la lista de aviones y utilice una técnica de down cast para identificar a los aviones de carga. Para aquellos aviones para los que el down cast fue exitoso, puede llamar al método GET_CARGO que definió e implementó en el paso anterior. a) Véase el extracto del código fuente de la solución modelo. 3. Llame al método GET_MAX_CARGO desde el método DISPLAY_ATTRIBUTES de la clase LCL_CARRIER y visualice el resultado. a) Véase el extracto del código fuente de la solución modelo. SAPBC401_INH_S3_OPT REPORT
sapbc401_inh_s3_opt.
TYPE-POOLS icon. ... *---------------------------------------------------* * CLASS lcl_cargo_plane DEFINITION *---------------------------------------------------* CLASS lcl_cargo_plane DEFINITION INHERITING FROM lcl_airplane. PUBLIC SECTION. METHODS:
152
© Copyright . Reservados todos los derechos.
Lección: Implementación down-casts mediante la herencia
constructor IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype iv_cargo TYPE s_plan_car EXCEPTIONS wrong_planetype, display_attributes REDEFINITION, get_cargo RETURNING value(rv_cargo) TYPE s_plan_car. PRIVATE SECTION. DATA: mv_cargo TYPE s_plan_car. ENDCLASS.
"lcl_cargo_plane DEFINITION
*----------------------------------------------------* * CLASS lcl_cargo_plane IMPLEMENTATION *----------------------------------------------------* CLASS lcl_cargo_plane IMPLEMENTATION. METHOD constructor. super->constructor( EXPORTING iv_name = iv_name iv_planetype = iv_planetype EXCEPTIONS wrong_planetype = 1 ). IF sy-subrc <> 0. RAISE wrong_planetype. ENDIF. mv_cargo = iv_cargo. ENDMETHOD. "constructor METHOD display_attributes. super->display_attributes( ). WRITE: / 'Max Cargo:'(005), AT c_pos_1 mv_cargo LEFT-JUSTIFIED. ULINE. ENDMETHOD. "display_attributes METHOD get_cargo. rv_cargo = mv_cargo. ENDMETHOD. ENDCLASS.
"get_cargo
"lcl_cargo_plane IMPLEMENTATION
... *---------------------------------------------------* * CLASS lcl_carrier DEFINITION *---------------------------------------------------* CLASS lcl_carrier DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING iv_name TYPE string,
© Copyright . Reservados todos los derechos.
153
Capítulo 3: Herencia y casting
display_attributes, add_airplane IMPORTING io_plane TYPE REF TO lcl_airplane. PRIVATE SECTION. DATA: mv_name TYPE string, mt_airplanes TYPE TABLE OF REF TO lcl_airplane. METHODS: display_airplanes, get_max_cargo RETURNING value(rv_max_cargo) TYPE s_plan_car. ENDCLASS.
"lcl_carrier DEFINITION
*--------------------------------------------------* * CLASS lcl_carrier IMPLEMENTATION *--------------------------------------------------* CLASS lcl_carrier IMPLEMENTATION. METHOD constructor. mv_name = iv_name. ENDMETHOD.
"constructor
METHOD display_attributes. DATA: lv_max_cargo TYPE s_plan_car. SKIP 2. WRITE: icon_flight AS ICON, mv_name. ULINE. ULINE. me->display_airplanes( ). lv_max_cargo = me->get_max_cargo( ). WRITE: / 'Capacity of biggest cargo plane:'(max), lv_max_cargo LEFT-JUSTIFIED. ENDMETHOD.
"display_attributes
METHOD add_airplane. APPEND io_plane TO mt_airplanes. ENDMETHOD. "add_airplane METHOD display_airplanes. DATA: lo_plane TYPE REF TO lcl_airplane. LOOP AT mt_airplanes INTO lo_plane. lo_plane->display_attributes( ). ENDLOOP. ENDMETHOD. "display_airplanes METHOD get_max_cargo. DATA: lo_plane TYPE REF TO lcl_airplane, lo_cargo TYPE REF TO lcl_cargo_plane. LOOP AT mt_airplanes INTO lo_plane. TRY.
154
© Copyright . Reservados todos los derechos.
Lección: Implementación down-casts mediante la herencia
lo_cargo ?= lo_plane. IF rv_max_cargo < lo_cargo->get_cargo( ). rv_max_cargo = lo_cargo->get_cargo( ). ENDIF. *
CATCH cx_sy_move_cast_error. plane is not a cargo plane - do nothing ENDTRY. ENDLOOP. ENDMETHOD. "get_max_cargo
ENDCLASS.
"lcl_carrier IMPLEMENTATION
© Copyright . Reservados todos los derechos.
155
Capítulo 3: Herencia y casting
Uso correcto de las jerarquías de clases
Figura 80: Uso de jerarquías de clases
Desde la fase de modelación, debería ser capaz de identificar una relación de generalización/ especialización entre ciertas clases. Si existe dicha relación entre ciertas clases, puede utilizar la herencia para representarla en objetos ABAP. Por ejemplo, la semántica debe mantenerse al redefinir métodos. Además, los componentes heredados deben utilizarse según la manera prevista en la clase superior. Mal uso de la herencia
Figura 81: Ejemplos: mal uso de la herencia
Si no entiende correctamente la formulación “es un (específico)”, correrá el riesgo de identificar los lugares erróneos donde utilizar la herencia. A veces, la necesidad de otro atributo para una clase se responde de manera incorrecta con una especialización. Por ejemplo, una clase superior llamada Coche contiene las subclases coche rojo, coche azul, etc. La sentencia "Un coche rojo es un coche específico" solo es correcta a primera vista. Sin embargo, no hay coches sin color. Como mucho, hay algunos coches que no se han pintado. Por ello, todos los coches necesitan el atributo color, asumiendo que es relevante para la aplicación. Por lo tanto, el atributo ya debería haberse definido en la clase superior. Puede haber contradicciones con la realidad cuando intenta implementar un método para pintar los coches.
156
© Copyright . Reservados todos los derechos.
Lección: Implementación down-casts mediante la herencia
Nota: Estos atributos también se definen como variables de referencia a una clase superior de clases de rol. Hay una descripción de clase para cada rol. Para modificar el rol de una instancia, se deberán intercambiar las referencias a las instancias de descripción de rol correspondientes. La bibliografía específica también hace referencia a ello como patrón de diseño de rol. En algunos casos, las relaciones de especialización que no permiten retener la semántica deben identificarse. Por ejemplo, la clase cuadrada hereda de la clase rectangular. Si intenta definir métodos para el rectángulo que modifica el ancho y la altura por separado, estos métodos no serán lógicos cuando se apliquen al cuadrado. Incluso si los métodos se redefinieron para que la longitud de los lados fuera uniforme, la semántica será diferente. Por el mismo motivo, tampoco es aceptable usar la herencia solo porque se encuentran algunas funciones requeridas en una clase superior.
© Copyright . Reservados todos los derechos.
157
Capítulo 3: Herencia y casting
RESUMEN DE LA LECCIÓN Ahora podrá:
158
●
Implementar conversiones down-cast con la herencia
●
Modelar jerarquías de clases
© Copyright . Reservados todos los derechos.
Capítulo 3 Evaluación de la formación
1. De las siguientes opciones, ¿cuál es una relación en la cual la subclase hereda todas las características principales de la clase superior? Seleccione la respuesta correcta. X
A Especialización
X
B Generalización
X
C Polimorfismo
X
D Casting
2. De las siguientes opciones, ¿cuáles son características de la generación y la especialización? Seleccione las respuestas correctas. X
A Los componentes comunes solo existen una vez en la clase superior.
X
B Los componentes de las subclases están disponibles en todas las clases superiores.
X
C Las subclases contienen extensiones o modificaciones.
X
D Las subclases no dependen de las clases superiores.
3. De las siguientes opciones, ¿cuál puede llamarse de forma automática en la clase superior? Seleccione la respuesta correcta. X
A Método
X
B Constructor de instancia
X
C Constructor estático
X
D Objeto
© Copyright . Reservados todos los derechos.
159
Capítulo 3: Evaluación de la formación
4. Una clase superior es una generalización de sus subclases. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
5. De las siguientes opciones, ¿cuál se utiliza para modificar clases superiores sin necesidad de conocer las subclases? Seleccione la respuesta correcta. X
A PROTECTED
X
B PRIVATE
X
C PUBLIC
6. De las siguientes opciones, ¿cuál se utiliza para definir la clase estática de variable de referencia? Seleccione la respuesta correcta. X
A APPEND
X
B CREATE OBJECT
X
C TYPE REF TO
X
D CLASS
7. De las siguientes opciones, ¿cuál se determina mediante la asignación? Seleccione la respuesta correcta.
160
X
A Clase superior
X
B Tipo estático
X
C Tipo dinámico
X
D Subclase
© Copyright . Reservados todos los derechos.
Capítulo 3: Evaluación de la formación
8. Supongamos que tenemos la clase X que se hereda de la clase Y. Tras un up-cast, una variable de referencia que posee un tipo estático TYPE REF TO Y apunta a una instancia de la clase X. ¿A qué componentes de la clase X puede acceder con esta variable de referencia? Seleccione las respuestas correctas. X
A Componentes definidos en la clase X
X
B Componentes heredados de la clase Y
X
C Componentes redefinidos en la clase X
X
D Componentes definidos en la clase X y redefinidos en sus subclases
9. Cuando los objetos de distintas clases reaccionan de manera distinta a las mismas llamadas del método, hablamos de __________. Seleccione la respuesta correcta. X
A objetos
X
B eventos
X
C polimorfismo
X
D herencia
10. Un uso típico de las asignaciones ________ es la preparación para el acceso genérico. Seleccione la respuesta correcta. X
A eventos
X
B up-cast
X
C métodos
X
D down-cast
11. De las siguientes opciones, ¿cuál se utiliza para asignar una referencia de clase superior a una referencia de subclase? Seleccione la respuesta correcta. X
A Widening Cast
X
B Narrowing Cast
X
C Redefinición
© Copyright . Reservados todos los derechos.
161
Capítulo 3: Evaluación de la formación
12. De las siguientes opciones, ¿cuál es el operador de asignación down-cast? Seleccione la respuesta correcta. X
A APPEND
X
B CATCH
X
C MOVE ... ?TO ...
X
D TRY-ENDTRY
13. Supongamos que tenemos la misma clase X que se hereda de la clase Y. Tras un down -cast, una variable de referencia que posee un tipo estático TYPE REF TO X apunta a una instancia de la clase X. ¿A cuáles de los siguientes componentes de la clase X puede acceder con esta variable de referencia? Seleccione las respuestas correctas. X
A Componentes definidos en la clase X
X
B Componentes heredados de la clase Y
X
C Componentes redefinidos en la clase X
X
D Componentes definidos en la clase X y redefinidos en sus subclases
X
E Componentes heredados y redefinidos de una relación de ‘amistad’
14. Supongamos que una variable de referencia tipificada en una interfaz contiene una referencia de instancia de una clase que implementa esta interfaz y que la copia en una variable de referencia que se indica en la clase (down.cast). ¿A cuáles de los siguientes componentes se puede acceder con esta variable de referencia? Seleccione las respuestas correctas.
162
X
A A los componentes de la interfaz
X
B A los componentes de la clase que no están definidos en la interfaz
X
C A todos los componentes de la clase
X
D A los componentes de la interfaz para los que se han definido nombres alias
X
E Componentes de una relación de ‘amistad’
© Copyright . Reservados todos los derechos.
Capítulo 3: Evaluación de la formación
15. ¿Cuáles son las ventajas de usar las jerarquías de clase correctamente? Seleccione las respuestas correctas. X
A Actualización centralizada
X
B Método de acceso seguro y genérico
X
C Semántica preservada
X
D Uso previsto de los componentes heredados
© Copyright . Reservados todos los derechos.
163
Capítulo 3 Respuestas a la Evaluación de la formación
1. De las siguientes opciones, ¿cuál es una relación en la cual la subclase hereda todas las características principales de la clase superior? Seleccione la respuesta correcta. X
A Especialización
X
B Generalización
X
C Polimorfismo
X
D Casting
2. De las siguientes opciones, ¿cuáles son características de la generación y la especialización? Seleccione las respuestas correctas. X
A Los componentes comunes solo existen una vez en la clase superior.
X
B Los componentes de las subclases están disponibles en todas las clases superiores.
X
C Las subclases contienen extensiones o modificaciones.
X
D Las subclases no dependen de las clases superiores.
3. De las siguientes opciones, ¿cuál puede llamarse de forma automática en la clase superior? Seleccione la respuesta correcta.
164
X
A Método
X
B Constructor de instancia
X
C Constructor estático
X
D Objeto
© Copyright . Reservados todos los derechos.
Capítulo 3: Respuestas a la Evaluación de la formación
4. Una clase superior es una generalización de sus subclases. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
5. De las siguientes opciones, ¿cuál se utiliza para modificar clases superiores sin necesidad de conocer las subclases? Seleccione la respuesta correcta. X
A PROTECTED
X
B PRIVATE
X
C PUBLIC
6. De las siguientes opciones, ¿cuál se utiliza para definir la clase estática de variable de referencia? Seleccione la respuesta correcta. X
A APPEND
X
B CREATE OBJECT
X
C TYPE REF TO
X
D CLASS
7. De las siguientes opciones, ¿cuál se determina mediante la asignación? Seleccione la respuesta correcta. X
A Clase superior
X
B Tipo estático
X
C Tipo dinámico
X
D Subclase
© Copyright . Reservados todos los derechos.
165
Capítulo 3: Respuestas a la Evaluación de la formación
8. Supongamos que tenemos la clase X que se hereda de la clase Y. Tras un up-cast, una variable de referencia que posee un tipo estático TYPE REF TO Y apunta a una instancia de la clase X. ¿A qué componentes de la clase X puede acceder con esta variable de referencia? Seleccione las respuestas correctas. X
A Componentes definidos en la clase X
X
B Componentes heredados de la clase Y
X
C Componentes redefinidos en la clase X
X
D Componentes definidos en la clase X y redefinidos en sus subclases
9. Cuando los objetos de distintas clases reaccionan de manera distinta a las mismas llamadas del método, hablamos de __________. Seleccione la respuesta correcta. X
A objetos
X
B eventos
X
C polimorfismo
X
D herencia
10. Un uso típico de las asignaciones ________ es la preparación para el acceso genérico. Seleccione la respuesta correcta. X
A eventos
X
B up-cast
X
C métodos
X
D down-cast
11. De las siguientes opciones, ¿cuál se utiliza para asignar una referencia de clase superior a una referencia de subclase? Seleccione la respuesta correcta.
166
X
A Widening Cast
X
B Narrowing Cast
X
C Redefinición
© Copyright . Reservados todos los derechos.
Capítulo 3: Respuestas a la Evaluación de la formación
12. De las siguientes opciones, ¿cuál es el operador de asignación down-cast? Seleccione la respuesta correcta. X
A APPEND
X
B CATCH
X
C MOVE ... ?TO ...
X
D TRY-ENDTRY
13. Supongamos que tenemos la misma clase X que se hereda de la clase Y. Tras un down -cast, una variable de referencia que posee un tipo estático TYPE REF TO X apunta a una instancia de la clase X. ¿A cuáles de los siguientes componentes de la clase X puede acceder con esta variable de referencia? Seleccione las respuestas correctas. X
A Componentes definidos en la clase X
X
B Componentes heredados de la clase Y
X
C Componentes redefinidos en la clase X
X
D Componentes definidos en la clase X y redefinidos en sus subclases
X
E Componentes heredados y redefinidos de una relación de ‘amistad’
14. Supongamos que una variable de referencia tipificada en una interfaz contiene una referencia de instancia de una clase que implementa esta interfaz y que la copia en una variable de referencia que se indica en la clase (down.cast). ¿A cuáles de los siguientes componentes se puede acceder con esta variable de referencia? Seleccione las respuestas correctas. X
A A los componentes de la interfaz
X
B A los componentes de la clase que no están definidos en la interfaz
X
C A todos los componentes de la clase
X
D A los componentes de la interfaz para los que se han definido nombres alias
X
E Componentes de una relación de ‘amistad’
© Copyright . Reservados todos los derechos.
167
Capítulo 3: Respuestas a la Evaluación de la formación
15. ¿Cuáles son las ventajas de usar las jerarquías de clase correctamente? Seleccione las respuestas correctas.
168
X
A Actualización centralizada
X
B Método de acceso seguro y genérico
X
C Semántica preservada
X
D Uso previsto de los componentes heredados
© Copyright . Reservados todos los derechos.
CAPÍTULO 4
Interfaces y casting
Lección 1 Definición e implementación de las interfaces locales Ejercicio 11: Definir e implementar una interfaz local
170 175
Lección 2 Implementar el polimorfismo mediante interfaces Ejercicio 12: Implementar el polimorfismo mediante interfaces
185 189
Lección 3 Unión de modelos de clase con interfaces Ejercicio 13: Integre los modelos de clase con interfaces.
196 199
OBJETIVOS DEL CAPÍTULO ●
Explicar las áreas de uso para interfaces
●
Crear relaciones de generalización y especialización utilizando interfaces
●
Implementar el polimorfismo mediante interfaces
●
Implementar down-casts con interfaces
●
Integrar distintos submodelos con interfaces
●
Crear y utilizar jerarquías de interfaz
© Copyright . Reservados todos los derechos.
169
Capítulo 4 Lección 1 Definición e implementación de las interfaces locales
RESUMEN DE LA LECCIÓN Este módulo explica el método de definición e implementación de interfaces. Ejemplo empresarial Como desarrollador, desea crear interfaces e implementarlas en su modelo en los objetos ABAP. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión del uso de la interfaz
●
Una buena comprensión de la definición de interfaz
●
Una buena comprensión de la implementación de la interfaz
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Explicar las áreas de uso para interfaces
●
Crear relaciones de generalización y especialización utilizando interfaces
Áreas de uso para interfaces
Figura 82: Definición central de componentes compartidos
Las interfaces difieren de la herencia habitual en sus áreas de uso. Sin embargo, en cuanto a la programación, prácticamente no hay diferencias entre las interfaces y la herencia normal.
170
© Copyright . Reservados todos los derechos.
Lección: Definición e implementación de las interfaces locales
Las interfaces pueden verse como clases superior que no pueden instanciarse, no contienen implementaciones y solo tienen componentes públicos. Puede simular herencias múltiples con las interfaces. En los objetos ABAP, las interfaces se utilizan principalmente para definir protocolos de interfaces uniformes para los servicios. Las distintas clases pueden implementar estos servicios de diferentes maneras, pero debe mantener la misma semántica. Por lo tanto, las interfaces no contienen implementaciones. En los objetos ABAP, los mismos componentes pueden definirse generalmente en interfaces y clases. Para reconocer las diferencias semánticas de la herencia normal, puede concentrarse en los casos de uso siguientes. Por ejemplo, desea permitir que múltiples clases implementen un servicio de diferentes maneras, pero utilizando los mismos nombres de método y una firma uniforme. Con la herencia normal, un método de este tipo se define en la clase superior compartida. Sin embargo, si no se puede modelar una clase superior de manera adecuada para la herencia, se deberá definir una interfaz y después el método en la interfaz. Por lo tanto, este caso se puede comparar con una relación de generalización dentro de una clase superior.
Definición del protocolo por el cliente
Figura 83: El cliente define el protocolo.
En comparación con la herencia normal, la distribución de roles en interfaces es, a veces, diferente. el usuario generalmente define las interfaces. En estas interfaces, el usuario describe, tanto técnica como semánticamente, los servicios que desea recibir del proveedor. Cada clase puede decidir ahora por sí misma si sirve a la interfaz, es decir, si realmente ofrece los servicios definidos en la interfaz. Por lo tanto, este caso es similar a una relación de especialización con una subclase. Como con la herencia normal, el acceso a estos servicios definidos suele ser genérico; es decir, utiliza una referencia que se indica en la interfaz. Como en la herencia, el polimorfismo también puede implementarse en las interfaces.
© Copyright . Reservados todos los derechos.
171
Capítulo 4: Interfaces y casting
Acceso genérico a componentes de interfaz
Figura 84: Interfaces en notación UML
En el lenguaje unificado de modelado (UML), representa las interfaces de la misma manera en que representa las clases. Sin embargo, además del nombre de interfaz, utiliza la notación «interfaz». Representa el uso de una interfaz con una línea de puntos que tiene una flecha bilateral del usuario a la interfaz. La palabra clave «usos» es opcional.
Crear relaciones de generalización y especialización utilizando interfaces
Figura 85: Definición e implementación de una interfaz
En objetos ABAP, puede definir los mismos componentes en una interfaz como en las clases. Sin embargo, las interfaces no conocen los niveles de visibilidad de los componentes; es decir, todos los componentes de una interfaz son públicos. Las clases implementan interfaces de las siguientes maneras:
172
© Copyright . Reservados todos los derechos.
Lección: Definición e implementación de las interfaces locales
●
Nombre de interfaz El nombre de la interfaz se enumera en la definición de la clase con la sentencia INTERFACES. Esto se produce en la PUBLIC SECTION, es decir, las interfaces solo pueden implementarse de manera pública.
●
Métodos de interfaz Los métodos de interfaz se implementan en la parte de implementación de la clase.
●
Componentes de interfaz Los componentes definidos en la interfaces se abordan en la parte de implementación de la clase.
Los componentes de interfaz se distinguen del resto de componentes en la clase de implementación, al prefijar el nombre de interfaz seguido de un guión ondulado (~) que es el operador de resolución de interfaz. interface_name~component_name Para simplificar el acceso a los componentes de interfaz, puede utilizar nombres alias. Estos solo pueden aparecer en la parte de definición de una clase o en la definición de interfaz. El uso de nombres alias está sujeto a la restricción de visibilidad de la clase de definición. A continuación se define un alias para un método de interfaz: ALIASES a_1 FOR lif_1~method_1. El método de interfaz lif_1~method_1 puede llamarse con la forma corta ref->a_1.
Acceso a componentes de interfaz
Figura 86: Cómo dirigirse a componentes de interfaz mediante referencias de objetos
Puede acceder a los componentes de interfaz solo mediante una referencia de objeto cuya clase implemente la interfaz. Utiliza el operador de resolución de interfaz (~) para acceder a los componentes de interfaz de la parte de implementación de la clase. De manera alternativa, se pueden utilizar los nombres de alias definidos en la clase de implementación para los componentes de interfaz. Incluso si los componentes compartidos
© Copyright . Reservados todos los derechos.
173
Capítulo 4: Interfaces y casting
de las clases de implementación se transfieren posteriormente a la interfaz, no será necesario adaptar el acceso a estos componentes.
174
© Copyright . Reservados todos los derechos.
Capítulo 4 Ejercicio 11 Definir e implementar una interfaz local
Ejemplo empresarial Es necesario añadir una compañía de vehículos de alquiler a su programa. La compañía de vehículos de alquiler y la compañía aérea existente deben añadirse a la clase de agencia de viajes como los interlocutores comerciales de la agencia de viajes. Para añadir estos interlocutores comerciales, necesita el acceso genérico a las aerolíneas y las compañías de alquiler de automóviles. En lugar de definir una clase superior común, es necesario definir una interfaz con servicios genéricos, que luego se implementa en las clases para las compañías aéreas y las de vehículos de alquiler. Defina e implemente la interfaz en su clase existente para las aerolíneas. Modelo: SAPBC401_INH_S3 Solución: SAPBC401_INT_S1 Tarea 1 Para mejorar la legibilidad de su programa, divida el código fuente en un programa principal y un programa de INCLUDE. El programa de INCLUDE debe contener todas las definiciones e implementaciones de clase locales. La declaración de variables de referencia y el bloque de evento START-OF -SELECTION debería permanecer en el programa principal.
Nota: Esta distribución no se sigue el uso recomendado de INCLUDES en los programas ABAP. Según las pautas de programación, las definiciones de clase y la declaraciones de datos deben pasar al INCLUDE TOP, las implementaciones al INCLUDE P y el bloque de eventos START-OF-SELECTION al INCLUDE E. 1. Complete el programa ZBC401_##_MAIN (## es su número de grupo de dos cifras) o copie la solución modelo del ejercicio anterior. 2. En su programa principal, implemente el uso de un nuevo programa INCLUDE (nombre recomendado: ZBC401_##_CARRIER con ## como su número de grupo de dos cifras). Cree el INCLUDE mediante la navegación hacia delante. Puede realizarlo haciendo doble clic en el nombre del INCLUDE. 3. Corte las secciones de definición e implementación de las cuatro clases locales del programa principal y péguelas en el programa include que acaba de crear.
© Copyright . Reservados todos los derechos.
175
Capítulo 4: Interfaces y casting
4. ¿Dónde debe ubicar la sentencia INCLUDE para evitar errores sintácticos?
5. Active y realice un test del programa.
Tarea 2 Defina una interfaz con el método DISPLAY_PARTNER para ofrecer más tarde opciones de acceso genéricas a clientes potenciales en nuestro ejemplo de la agencia de viajes. 1. Cree un INCLUDE nuevo (nombre recomendado: ZBC401_##_AGENCY con ## como su número de grupo de dos cifras) y defina una interfaz LIF_PARTNER en este nuevo INCLUDE. 2. La interfaz debería contener el método de instancia DISPLAY_PARTNER. El método de instancia no debe tener ningún parámetro. Más adelante, su tarea será visualizar atributos de interlocutores comerciales. Verifique el programa completo para asegurarse de que la sintaxis es correcta y actívelo. Tarea 3 La clase LCL_CARRIER debería poner a disposición los servicios definidos en la interfaz a clientes potenciales. Para lograrlo, la clase LCL_CARRIER debe implementar la interfaz y, por lo tanto, el método de interfaz DISPLAY_PARTNER. 1. En la definición de LCL_CARRIER, declare la interfaz creada recientemente. 2. Implemente la codificación del método de interfaz DISPLAY_PARTNER en su clase LCL_CARRIER. Tal como se deduce del nombre del método, los datos o atributos de este interlocutor comercial deberían visualizarse aquí. Considere las posibles soluciones y ejecute la aproximación más adecuada. Verifique toda la aplicación para asegurare de que la sintaxis sea correcta y active la aplicación. Consejo: El rendimiento de la aplicación aún no cambiará en este punto; los resultados solo se verán en las tareas posteriores.
Tarea 4 Realice una prueba de la interfaz implementada en la clase LCL_CARRIER llamando el método de interfaz desde el programa principal. 1. En el programa principal, elimine la llamada para el método DISPLAY_ATTRIBUTES de la clase LCL_CARRIER. Reemplácelo con una llamada para el método de interfaz DISPLAY_PARTNER.
176
© Copyright . Reservados todos los derechos.
Lección: Definición e implementación de las interfaces locales
2. ¿Cuál es el objetivo de una llamada de este tipo en este punto del ejercicio o, en otras palabras, qué nos ofrece la opción de esta llamada de método de interfaz en el programa principal en comparación con una llamada de método convencional?
3. Después de realizar un test con éxito, convierta esta llamada de método en un comentario, de manera que pase a ser inefectiva. Consejo: El uso genérico de los métodos de interfaz con otra clase tiene lugar en los siguientes pasos del ejercicio. El rendimiento de la aplicación aún no cambiará en este punto; los resultados solo podrán observarse en las tareas posteriores.
© Copyright . Reservados todos los derechos.
177
Capítulo 4 Solución 11 Definir e implementar una interfaz local
Ejemplo empresarial Es necesario añadir una compañía de vehículos de alquiler a su programa. La compañía de vehículos de alquiler y la compañía aérea existente deben añadirse a la clase de agencia de viajes como los interlocutores comerciales de la agencia de viajes. Para añadir estos interlocutores comerciales, necesita el acceso genérico a las aerolíneas y las compañías de alquiler de automóviles. En lugar de definir una clase superior común, es necesario definir una interfaz con servicios genéricos, que luego se implementa en las clases para las compañías aéreas y las de vehículos de alquiler. Defina e implemente la interfaz en su clase existente para las aerolíneas. Modelo: SAPBC401_INH_S3 Solución: SAPBC401_INT_S1 Tarea 1 Para mejorar la legibilidad de su programa, divida el código fuente en un programa principal y un programa de INCLUDE. El programa de INCLUDE debe contener todas las definiciones e implementaciones de clase locales. La declaración de variables de referencia y el bloque de evento START-OF -SELECTION debería permanecer en el programa principal.
Nota: Esta distribución no se sigue el uso recomendado de INCLUDES en los programas ABAP. Según las pautas de programación, las definiciones de clase y la declaraciones de datos deben pasar al INCLUDE TOP, las implementaciones al INCLUDE P y el bloque de eventos START-OF-SELECTION al INCLUDE E. 1. Complete el programa ZBC401_##_MAIN (## es su número de grupo de dos cifras) o copie la solución modelo del ejercicio anterior. a) Realice este paso de la forma habitual. Encontrará información adicional sobre cómo copiar programas en la biblioteca SAP. 2. En su programa principal, implemente el uso de un nuevo programa INCLUDE (nombre recomendado: ZBC401_##_CARRIER con ## como su número de grupo de dos cifras). Cree el INCLUDE mediante la navegación hacia delante. Puede realizarlo haciendo doble clic en el nombre del INCLUDE. a) Véase el extracto de código fuente de la solución modelo.
178
© Copyright . Reservados todos los derechos.
Lección: Definición e implementación de las interfaces locales
3. Corte las secciones de definición e implementación de las cuatro clases locales del programa principal y péguelas en el programa include que acaba de crear. a) Véase el extracto de código fuente de la solución modelo. 4. ¿Dónde debe ubicar la sentencia INCLUDE para evitar errores sintácticos? La sentencia INCLUDE debe colocarse antes de la declaración de variables de referencia. De lo contrario, las definiciones de clase no se conocerán en la declaración de variables de referencia. 5. Active y realice un test del programa. a) Realice este paso de la forma habitual. Encontrará información adicional sobre cómo copiar programas en la biblioteca SAP.
Tarea 2 Defina una interfaz con el método DISPLAY_PARTNER para ofrecer más tarde opciones de acceso genéricas a clientes potenciales en nuestro ejemplo de la agencia de viajes. 1. Cree un INCLUDE nuevo (nombre recomendado: ZBC401_##_AGENCY con ## como su número de grupo de dos cifras) y defina una interfaz LIF_PARTNER en este nuevo INCLUDE. a) Véase el extracto de código fuente de la solución modelo. 2. La interfaz debería contener el método de instancia DISPLAY_PARTNER. El método de instancia no debe tener ningún parámetro. Más adelante, su tarea será visualizar atributos de interlocutores comerciales. Verifique el programa completo para asegurarse de que la sintaxis es correcta y actívelo. a) Véase el extracto de código fuente de la solución modelo. Tarea 3 La clase LCL_CARRIER debería poner a disposición los servicios definidos en la interfaz a clientes potenciales. Para lograrlo, la clase LCL_CARRIER debe implementar la interfaz y, por lo tanto, el método de interfaz DISPLAY_PARTNER. 1. En la definición de LCL_CARRIER, declare la interfaz creada recientemente. a) Véase el extracto de código fuente de la solución modelo. 2. Implemente la codificación del método de interfaz DISPLAY_PARTNER en su clase LCL_CARRIER. Tal como se deduce del nombre del método, los datos o atributos de este interlocutor comercial deberían visualizarse aquí. Considere las posibles soluciones y ejecute la aproximación más adecuada. Verifique toda la aplicación para asegurare de que la sintaxis sea correcta y active la aplicación. Consejo: El rendimiento de la aplicación aún no cambiará en este punto; los resultados solo se verán en las tareas posteriores. a) Véase el extracto de código fuente de la solución modelo.
© Copyright . Reservados todos los derechos.
179
Capítulo 4: Interfaces y casting
Tarea 4 Realice una prueba de la interfaz implementada en la clase LCL_CARRIER llamando el método de interfaz desde el programa principal. 1. En el programa principal, elimine la llamada para el método DISPLAY_ATTRIBUTES de la clase LCL_CARRIER. Reemplácelo con una llamada para el método de interfaz DISPLAY_PARTNER. a) Véase el extracto de código fuente de la solución modelo. 2. ¿Cuál es el objetivo de una llamada de este tipo en este punto del ejercicio o, en otras palabras, qué nos ofrece la opción de esta llamada de método de interfaz en el programa principal en comparación con una llamada de método convencional? Si no fuera por la sintaxis detallada y más larga de esta llamada, la llamada del método de interfaz puede sustituirse por una llamada de método de instancia normal, por ejemplo, DISPLAY_ATTRIBUTES. En este punto del ejercicio, esta llamada no parece ser sensible en general. 3. Después de realizar un test con éxito, convierta esta llamada de método en un comentario, de manera que pase a ser inefectiva. Consejo: El uso genérico de los métodos de interfaz con otra clase tiene lugar en los siguientes pasos del ejercicio. El rendimiento de la aplicación aún no cambiará en este punto; los resultados solo podrán observarse en las tareas posteriores. a) Véase el extracto de código fuente de la solución modelo. Programa principal: SAPBC401_INT_S1 REPORT
sapbc401_int_s1.
TYPE-POOLS icon. INCLUDE bc401_int_s1_agency. INCLUDE bc401_int_s1_carrier. DATA: go_carrier go_airplane go_cargo go_passenger gv_count
TYPE TYPE TYPE TYPE TYPE
REF REF REF REF i.
TO TO TO TO
lcl_carrier, lcl_airplane, lcl_cargo_plane, lcl_passenger_plane,
START-OF-SELECTION. ******************* ***** Create Carrier ************************************ CREATE OBJECT go_carrier EXPORTING iv_name = 'Smile&Fly-Travel'.
180
© Copyright . Reservados todos los derechos.
Lección: Definición e implementación de las interfaces locales
***** Passenger Plane CREATE OBJECT go_passenger EXPORTING iv_name = 'LH BERLIN' iv_planetype = '747-400' iv_seats = 345 EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. go_carrier->add_airplane( go_passenger ). ENDIF. ***** cargo Plane CREATE OBJECT go_cargo EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' iv_cargo = 533 EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. go_carrier->add_airplane( go_cargo ). ENDIF. *** output carrier (including list of airplanes) * only for testing: * call interface method for the carrier *
go_carrier->lif_partner~display_partner( ). go_carrier->display_attributes( ). Include BC401_INT_S1_AGENCY
INTERFACE lif_partner. METHODS display_partner. ENDINTERFACE. Include BC401_INT_S1_CARRIER *---------------------------------------------------* * CLASS lcl_airplane DEFINITION *---------------------------------------------------* CLASS lcl_airplane DEFINITION. ... ENDCLASS. "lcl_airplane DEFINITION *---------------------------------------------------* * CLASS lcl_airplane IMPLEMENTATION *---------------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. ... ENDCLASS. "lcl_airplane IMPLEMENTATION *----------------------------------------------------* * CLASS lcl_cargo_plane DEFINITION *----------------------------------------------------* *
© Copyright . Reservados todos los derechos.
181
Capítulo 4: Interfaces y casting
*----------------------------------------------------* CLASS lcl_cargo_plane DEFINITION INHERITING FROM lcl_airplane. ... ENDCLASS. "lcl_cargo_plane DEFINITION *--------------------------------------------------* * CLASS lcl_cargo_plane IMPLEMENTATION *--------------------------------------------------* CLASS lcl_cargo_plane IMPLEMENTATION. ... ENDCLASS. "lcl_cargo_plane IMPLEMENTATION *--------------------------------------------------* * CLASS lcl_passenger_plane DEFINITION *--------------------------------------------------* CLASS lcl_passenger_plane DEFINITION INHERITING FROM lcl_airplane. ... ENDCLASS. "lcl_passenger_plane DEFINITION *---------------------------------------------------* * CLASS lcl_passenger_plane IMPLEMENTATION *---------------------------------------------------* CLASS lcl_passenger_plane IMPLEMENTATION. ... ENDCLASS.
"lcl_passenger_plane IMPLEMENTATION
*----------------------------------------------------* * CLASS lcl_carrier DEFINITION *----------------------------------------------------* CLASS lcl_carrier DEFINITION. PUBLIC SECTION. INTERFACES: lif_partner. METHODS: constructor IMPORTING iv_name TYPE string, display_attributes, add_airplane IMPORTING io_plane TYPE REF TO lcl_airplane. PRIVATE SECTION. DATA: mv_name TYPE string, mt_airplanes TYPE TABLE OF REF TO lcl_airplane. METHODS: display_airplanes. ENDCLASS.
"lcl_carrier DEFINITION
*---------------------------------------------------*
182
© Copyright . Reservados todos los derechos.
Lección: Definición e implementación de las interfaces locales
* CLASS lcl_carrier IMPLEMENTATION *---------------------------------------------------* CLASS lcl_carrier IMPLEMENTATION. METHOD constructor. mv_name = iv_name. ENDMETHOD. "constructor METHOD display_attributes. SKIP 2. WRITE: icon_flight AS ICON, mv_name. ULINE. ULINE. me->display_airplanes( ). ENDMETHOD. "display_attributes METHOD add_airplane. APPEND io_plane TO mt_airplanes. ENDMETHOD. "add_airplane METHOD display_airplanes. DATA: lo_plane TYPE REF TO lcl_airplane. LOOP AT mt_airplanes INTO lo_plane. lo_plane->display_attributes( ). ENDLOOP. ENDMETHOD. "display_airplanes METHOD lif_partner~display_partner. me->display_attributes( ). ENDMETHOD. "lif_partner~display_partner ENDCLASS.
"lcl_carrier IMPLEMENTATION
© Copyright . Reservados todos los derechos.
183
Capítulo 4: Interfaces y casting
RESUMEN DE LA LECCIÓN Ahora podrá:
184
●
Explicar las áreas de uso para interfaces
●
Crear relaciones de generalización y especialización utilizando interfaces
© Copyright . Reservados todos los derechos.
Capítulo 4 Lección 2 Implementar el polimorfismo mediante interfaces
RESUMEN DE LA LECCIÓN Este módulo explica el polimorfismo y la implementación del polimorfismo con interfaces. Ejemplo empresarial Como desarrollador, necesita crear interfaces e implementarlas el polimorfismo en su proyecto de objetos ABAP. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión del polimorfismo
●
Una buena comprensión del polimorfismo en la implementación de interfaz
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Implementar el polimorfismo mediante interfaces
Polimorfismo con interfaces
Figura 87: Up cast con referencias de interfaz
Una referencia de interfaz solo puede referirse a instancias de clases que han implementado la interfaz porque las interfaces en sí no pueden ser instanciadas. Al igual que en la herencia normal, debe utilizar up-cast para copiar una referencia a la variable de referencia de la interfaz y realizar el polimorfismo con interfaces.
© Copyright . Reservados todos los derechos.
185
Capítulo 4: Interfaces y casting
Si la clase ha implementado la interfaz, es seguro que todos los componentes a los que se puede acceder sintácticamente tras la asignación cast están disponibles en la instancia. Un usuario puede dirigirse a la instancia de la clase de implementación utilizando la interfaz. El prefijo del nombre de interfaz y el operador de resolución de interfaz se omiten. Sin embargo, el usuario está restringido al uso de componentes de la interfaz. En el ejemplo, solo puede acceder a los métodos DISPLAY_PARTNER y CHECK_AVAILABILITY de la interfaz LIF_PARTNER después de asignar la variable de referencia GO_PARTNER. No puede acceder a los componentes específicos de la instancia desde la clase LCL_RENTAL (GET_NAME en el ejemplo anterior) mediante la variable de referencia GO_PARTNER. Por lo tanto, la vista está restringida o permanece sin modificaciones. Por ello se describe este tipo de asignación de variables de referencia como up cast. Hay un cambio de una vista de varios componentes a una vista de unos pocos componentes. La referencia destino puede aceptar, por supuesto, más tipos dinámicos que antes después de la asignación. Por ello, el término widening cast también es adecuado.
Acceso genérico con interfaces
Figura 88: Tipo de línea de la tabla interna en el ejemplo de aplicación
Un área de uso típica de asignaciones up cast es la preparación para el acceso genérico. Un usuario que no tiene interés en los puntos concretos de las instancias de la clase que implementa la interfaz, y que simplemente quiere dirigirse a los componentes definidos en la interfaz, podría utilizar una referencia de interfaz para este acceso. En el ejemplo que se muestra, una agencia de viajes (LCL_TRAVEL_AGENCY) necesita gestionar todo tipo de interlocutores comerciales en una lista. El desarrollador debe asignar el tipo de fila de la tabla interna como la referencia a la interfaz LIF_PARTNER. La agencia de viajes solo quiere solicitar los servicios para visualizar sus atributos y para verificar la disponibilidad. Los métodos relevantes DISPLAY_PARTNER y CHECK_AVAILABILITY se definen en la interfaz LIF_PARTNER y se implementan en las clases de interlocutor comercial. Los objetos de diferentes clases (LCL_HOTEL, LCL_RENTAL y LCL_CARRIER en el ejemplo) pueden mantenerse en una tabla interna, indicados con referencias de interfaz (LIF_PARTNER en el ejemplo). Los componentes definidos en la interfaz pueden ser accedidos de forma uniforme.
186
© Copyright . Reservados todos los derechos.
Lección: Implementar el polimorfismo mediante interfaces
Para este ejemplo, necesita el método ADD_PARTNER. Este método copia las referencias a todos los tipos de interlocutores comerciales en esta tabla interna. El parámetro de importación de este método ya está indicado como la referencia a la interfaz.
Polimorfismo – Acceso genérico mediante la referencia de interfaz
Figura 89: Polimorfismo – Acceso genérico mediante la referencia de interfaz
El polimorfismo también puede realizarse para interfaces. Puede utilizar las referencias a interfaces para llamar los métodos y ejecutar distintas implementaciones según el objeto de la referencia. Se utiliza el tipo dinámico de la variable de referencia para buscar la implementación de un método. En el ejemplo anterior, lo_partner->display_partner( ) utiliza por ello la clase de la instancia a la que se refiere en realidad lo_partner para buscar la implementación de display_partner. La implementación que se ejecuta cuando se llama DISPLAY_PARTNER, depende del objeto al cual se remite la referencia de interfaz lo_partner en la actualidad. Cuando los objetos de distintas clases reaccionan de manera distinta a las mismas llamadas del método, se habla de polimorfismo. La opción de utilizar el polimorfismo es uno de los puntos fuertes principales de las interfaces. Un cliente puede tratar diferentes clases de manera uniforme, independientemente de su implementación. El sistema de tiempo de ejecución busca la implementación correcta de un método con la ayuda del cliente. El polimorfismo puede utilizarse para escribir programas altamente genéricos, es decir, que no necesitan cambiarse de manera significativa si se añaden casos de uso. En el ejemplo, es fácil añadir una clase para los alquileres de botes. La clase relevante, por ejemplo, con el nombre LCL_SHIPPING simplemente debería implementar la interfaz LIF_PARTNER y el método DISPLAY_PARTNER definido allí. La gestión de interlocutores comerciales puede incluir fácilmente navieras y también solicitarles que muestren sus atributos.
© Copyright . Reservados todos los derechos.
187
Capítulo 4: Interfaces y casting
188
© Copyright . Reservados todos los derechos.
Capítulo 4 Ejercicio 12 Implementar el polimorfismo mediante interfaces
Ejemplo empresarial Necesita añadir una clase que utilice la interfaz definida anteriormente: Las agencias de viajes necesitan gestionar varios interlocutores comerciales mediante la interfaz y tener acceso a los servicios generales de los interlocutores comerciales. Modelo: SAPBC401_INH_T2 Solución: SAPBC401_INT_S2 Tarea 1 Defina una clase local para agencias de viajes. 1. Complete su programa ZBC401_##_MAIN (## es el número de grupo de dos cifras) o copie el programa de modelo con todos los INCLUDE. 2. En el programa INCLUDE que contiene la definición de la interfaz LIF_PARTNER, defina e implemente la clase local LCL_TRAVEL_AGENCY. Consejo: Si no ha copiado el programa de modelo, puede reducir la carga de tipificación al copiar la definición e implementación de la clase LCL_TRAVEL_AGENCY desde el modelo SAPBC401_INT_T2 y el include BC401_INT_T2_AGENCY. También puede crear la clase LCL_TRAVEL_AGENCY desde el principio, sin utilizar modelos. 3. Como atributo de clase privado, añada una tabla interna MT_PARTNERS para la grabación en memoria intermedia de las referencias a los interlocutores comerciales que han implementado la interfaz LIF_PARTNER. 4. Defina e implemente el método público llamado ADD_PARTNER para que las referencias de interlocutor comercial puedan añadirse a la lista MT_PARTNERS. Defina un parámetro de importación denominado IO_PARTNER con un tipo adecuado. 5. Amplíe la implementación del método DISPLAY_ATTRIBUTES de modo que no solo muestre la información sobre la agencia de viajes sino también sobre los interlocutores comerciales. Utilice el método definido anteriormente DISPLAY_PARTNERS.
Tarea 2
© Copyright . Reservados todos los derechos.
189
Capítulo 4: Interfaces y casting
En el programa principal, genere una instancia de agencia de viajes, transfiera las referencias a la compañía aérea a esta instancia, y añada los atributos. 1. En el programa principal, defina una variable de referencia tipificada correctamente para su nueva clase de agencia de viajes. 2. Mediante la referencia, genere una instancia de su clase LCL_TRAVEL_AGENCY. Decida cómo completar los atributos. 3. Llame el método ADD_PARTNER para transferir las referencias a las instancias generadas de la compañía aérea a la agencia de viajes. 4. Visualice los atributos de la agencia de viajes (incluida la información sobre sus interlocutores comerciales) llamando al método DISPLAY_ATTRIBUTES.
190
© Copyright . Reservados todos los derechos.
Capítulo 4 Solución 12 Implementar el polimorfismo mediante interfaces
Ejemplo empresarial Necesita añadir una clase que utilice la interfaz definida anteriormente: Las agencias de viajes necesitan gestionar varios interlocutores comerciales mediante la interfaz y tener acceso a los servicios generales de los interlocutores comerciales. Modelo: SAPBC401_INH_T2 Solución: SAPBC401_INT_S2 Tarea 1 Defina una clase local para agencias de viajes. 1. Complete su programa ZBC401_##_MAIN (## es el número de grupo de dos cifras) o copie el programa de modelo con todos los INCLUDE. a) Realice este paso de la forma habitual. Para más información, consulte la biblioteca SAP. 2. En el programa INCLUDE que contiene la definición de la interfaz LIF_PARTNER, defina e implemente la clase local LCL_TRAVEL_AGENCY. Consejo: Si no ha copiado el programa de modelo, puede reducir la carga de tipificación al copiar la definición e implementación de la clase LCL_TRAVEL_AGENCY desde el modelo SAPBC401_INT_T2 y el include BC401_INT_T2_AGENCY. También puede crear la clase LCL_TRAVEL_AGENCY desde el principio, sin utilizar modelos. a) Realice este paso de la forma habitual. Para más información, consulte la biblioteca SAP. 3. Como atributo de clase privado, añada una tabla interna MT_PARTNERS para la grabación en memoria intermedia de las referencias a los interlocutores comerciales que han implementado la interfaz LIF_PARTNER. a) Véase el extracto de código fuente de la solución modelo. 4. Defina e implemente el método público llamado ADD_PARTNER para que las referencias de interlocutor comercial puedan añadirse a la lista MT_PARTNERS. Defina un parámetro de importación denominado IO_PARTNER con un tipo adecuado. a) Véase el extracto de código fuente de la solución modelo.
© Copyright . Reservados todos los derechos.
191
Capítulo 4: Interfaces y casting
5. Amplíe la implementación del método DISPLAY_ATTRIBUTES de modo que no solo muestre la información sobre la agencia de viajes sino también sobre los interlocutores comerciales. Utilice el método definido anteriormente DISPLAY_PARTNERS. a) Véase el extracto de código fuente de la solución modelo.
Tarea 2 En el programa principal, genere una instancia de agencia de viajes, transfiera las referencias a la compañía aérea a esta instancia, y añada los atributos. 1. En el programa principal, defina una variable de referencia tipificada correctamente para su nueva clase de agencia de viajes. a) Véase el extracto de código fuente de la solución modelo. 2. Mediante la referencia, genere una instancia de su clase LCL_TRAVEL_AGENCY. Decida cómo completar los atributos. a) Véase el extracto de código fuente de la solución modelo. 3. Llame el método ADD_PARTNER para transferir las referencias a las instancias generadas de la compañía aérea a la agencia de viajes. a) Véase el extracto de código fuente de la solución modelo. 4. Visualice los atributos de la agencia de viajes (incluida la información sobre sus interlocutores comerciales) llamando al método DISPLAY_ATTRIBUTES. a) Véase el extracto de código fuente de la solución modelo. Include BC401_INT_S2_AGENCY *&-------------------------------------------------* *& Include BC401_INT_S2_AGENCY *&-------------------------------------------------* INTERFACE lif_partner. METHODS: display_partner. ENDINTERFACE. "lif_partner *--------------------------------------------------* * CLASS lcl_travel_agency DEFINITION *--------------------------------------------------* CLASS lcl_travel_agency DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING iv_name TYPE string, add_partner IMPORTING io_partner TYPE REF TO lif_partner, display_agency_partners, display_attributes. PRIVATE SECTION. DATA: mv_name
192
TYPE string,
© Copyright . Reservados todos los derechos.
Lección: Implementar el polimorfismo mediante interfaces
mt_partners TYPE TABLE OF REF TO lif_partner. ENDCLASS.
"lcl_travel_agency DEFINITION
*---------------------------------------------------* * CLASS lcl_travel_agency IMPLEMENTATION *---------------------------------------------------* CLASS lcl_travel_agency IMPLEMENTATION. METHOD display_attributes. WRITE: / icon_private_files AS ICON, 'Travel Agency:'(007), mv_name. ULINE. display_agency_partners( ). ENDMETHOD. "display_attributes METHOD display_agency_partners. DATA: lo_partner TYPE REF TO lif_partner. WRITE 'Here are the partners of the travel agency:'(008). ULINE. LOOP AT mt_partners INTO lo_partner. lo_partner->display_partner( ). ENDLOOP. ENDMETHOD.
"display_agency_partners
METHOD constructor. mv_name = iv_name. ENDMETHOD. "constructor METHOD add_partner. APPEND io_partner TO mt_partners. ENDMETHOD. "add_partner ENDCLASS.
"lcl_travel_agency IMPLEMENTATION
Programa principal SAPBC401_INT_S2 REPORT
sapbc401_int_s2.
TYPE-POOLS icon. INCLUDE bc401_int_s2_agency. INCLUDE bc401_int_s2_carrier. DATA: go_agency go_carrier go_airplane go_cargo go_passenger gv_count
TYPE TYPE TYPE TYPE TYPE TYPE
REF REF REF REF REF i.
TO TO TO TO TO
lcl_travel_agency, lcl_carrier, lcl_airplane, lcl_cargo_plane, lcl_passenger_plane,
START-OF-SELECTION. ******************* ***** create travel_agency CREATE OBJECT go_agency EXPORTING
© Copyright . Reservados todos los derechos.
193
Capítulo 4: Interfaces y casting
iv_name = 'Travel&Smile Travel'. ***** Create Carrier CREATE OBJECT go_carrier EXPORTING iv_name = 'Smile&Fly Travel'. ***** Insert carrier into business partner list of ***** travel agency go_agency->add_partner( go_carrier ). ***** Passenger Plane CREATE OBJECT go_passenger EXPORTING iv_name = 'LH BERLIN' iv_planetype = '747-400' iv_seats = 345 EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. go_carrier->add_airplane( go_passenger ). ENDIF. ***** cargo Plane CREATE OBJECT go_cargo EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' iv_cargo = 533 EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. go_carrier->add_airplane( go_cargo ). ENDIF. ***** show attributes of all partners of ***** travel agency go_agency->display_attributes( ).
194
© Copyright . Reservados todos los derechos.
Lección: Implementar el polimorfismo mediante interfaces
RESUMEN DE LA LECCIÓN Ahora podrá: ●
Implementar el polimorfismo mediante interfaces
© Copyright . Reservados todos los derechos.
195
Capítulo 4 Lección 3 Unión de modelos de clase con interfaces
RESUMEN DE LA LECCIÓN Este módulo explica el método de unión de modelos de clase mediante interfaces. Ejemplo empresarial Como desarrollador, necesita integrar múltiples modelos de clase para su proyecto de objetos ABAP. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de los submodelos
●
Una buena comprensión de la integración de submodelos
●
Una buena comprensión de las jerarquías de interfaz
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Implementar down-casts con interfaces
●
Integrar distintos submodelos con interfaces
●
Crear y utilizar jerarquías de interfaz
Down-casts con interfaces
Figura 90: Asignación down cast y tratamiento de excepciones en el ejemplo de aplicación
196
© Copyright . Reservados todos los derechos.
Lección: Unión de modelos de clase con interfaces
Para asignar una referencia de interfaz a una referencia de clase, donde la clase ha implementado la interfaz, se deberá utilizar el operador de asignación down cast MOVE ... ? TO ... o su forma breve ?=. Sino, el sistema emitirá un mensaje indicando que no es seguro que todos los componentes a los que se puede acceder sintácticamente tras la asignación cast estén disponibles actualmente en la instancia. Como regla, la clase de implementación contiene más componentes que la interfaz. Las variables de referencia de interfaz pueden contener referencias a instancias de la clase de implementación en tiempo de ejecución. Después de asignar este tipo de referencia de vuelta a una referencia de la clase de implementación, los clientes ya no están limitados a componentes de interfaz.
Integrar distintos submodelos con interfaces Este tipo de asignación de variables de referencia se describe como down-casting. La vista suele estar ampliada o, al menos, no está modificada. Este es un cambio de una vista de algunos componentes a una vista de más componentes. También se utiliza el término Narrowing Cast. Un área de uso típica de las asignaciones down cast es cuando debemos dirigirnos a los componentes específicos de instancias cuyas referencias se mantienen en variables tipificadas en la interfaz. Un usuario que tiene interés en los puntos concretos de las instancias de clases de implementación no puede utilizar la referencia de interfaz, porque la asignación down-cast solo permite el acceso a los componentes de interfaz. En el ejemplo que se muestra aquí, una agencia de viajes (LCL_TRAVEL_AGENCY) necesita reservar un vuelo pero mantiene todo tipo de referencias a interlocutores comerciales en una tabla interna indicada en la interfaz LIF_PARTNER. ¿Qué sucede si no hay ninguna referencia de compañía aérea en la referencia de interfaz GO_PARTNER en tiempo de ejecución pero el operador de asignación down cast se utiliza para copiar la referencia a la referencia entonces no válida GO_CARRIER? Al contrario que la asignación up cast, es posible que el tipo estático de la variable de destino (GO_CARRIER) no sea ni más general ni igual que el tipo dinámico de las variables fuente (GO_PARTNER), concretamente si GO_PARTNER contiene referencias de hotel o de vehículos de alquiler. El sistema en tiempo de ejecución verifica este tipo de cast antes de la asignación, ya sea que el contenido actual de la variable fuente corresponda, o no, con los requisitos del tipo de la variable destino. O bien, se desencadena una excepción que puede tratarse y el valor original de la variable destino permanece igual. Esta excepción de la clase de error CX_SY_MOVE_CAST_ERROR puede identificarse mediante TRY-ENDTRY y la sentencia CATCH. Otra manera de evitar este error de tiempo de ejecución sería utilizar clases de identificación de tipo de tiempo de ejecución (RTTI). Pueden utilizarse para determinar el tipo dinámico en tiempo de ejecución y para fijar una condición para el cast. Las asignaciones entre variables de referencia de interfaz cuyas interfaces de tipificación no están relacionadas unas con las otras, tampoco pueden verificarse estáticamente y, por lo tanto, deben ejecutarse utilizando down cast. Con esta asignación, el sistema verifica en tiempo de ejecución si la clase de la instancia a la que se refiere la referencia fuente también soporta la interfaz con la que la referencia de destino está tipificada.
© Copyright . Reservados todos los derechos.
197
Capítulo 4: Interfaces y casting
198
© Copyright . Reservados todos los derechos.
Capítulo 4 Ejercicio 13 Integre los modelos de clase con interfaces.
Ejemplo empresarial Necesita añadir la compañía de vehículos de alquiler con sus vehículos en su propio modelo de objeto. Al implementar la interfaz ya definida, garantizará que la compañía de vehículos de alquiler podrá añadirse a la lista de interlocutores comerciales de la agencia de viajes. Modelo: SAPBC401_INT_T3 Solución: SAPBC401_INT_S3 Tarea 1 Copie las definiciones e implementaciones de las clases LCL_RENTAL y de las clases de vehículos (LCL_VEHICLE, LCL_TRUCK y LCL_BUS) en su programa y cree las instancias de las clases. 1. Complete su programa ZBC401_##_MAIN (## es el número de grupo de dos cifras) o copie el programa de modelo con todos los INCLUDE. 2. Si ha copiado el programa de modelo, analícelo y continúe con la próxima tarea. Si desea continuar trabajando con su propio programa, primero copie el programa de INCLUDE BC401_INT_T3_RENTAL (nombre sugerido: ZBC401_##_RENTAL, donde ## es el número de grupo de dos cifras) y realice la nueva parte del programa de INCLUDE de su propio programa. 3. En su programa principal, cree una instancia de LCL_RENTAL y un número de instancias de las clases de vehículos. Añada todos los vehículos a la lista de vehículos de la compañía de alquiler llamando al método ADD_VEHICLE de LCL_RENTAL. Consejo: Para reducir el trabajo de tipeado, puede copiar y pegar la codificación relevante desde el programa principal de SAPBC401_INT_T3.
Tarea 2 Implemente la interfaz LIF_PARTNER en la clase LCL_RENTAL. 1. Llame al método ADD_PARTNER para añadir la instancia de LCL_RENTAL a la lista de interlocutores comerciales de la agencia de viajes.
© Copyright . Reservados todos los derechos.
199
Capítulo 4: Interfaces y casting
2. Verifique la sintaxis. ¿Por qué produce un error de sintaxis esta llamada de método?
3. Consulte la sección de definición de clase LCL_RENTAL y declare la implementación de la interfaz LIF_PARTNER. 4. Proporcione una implementación del método definido en la interfaz. 5. Active el INCLUDE con la definición e implementación de LCL_RENTAL. A continuación, acceda al programa principal y realice otra verificación de sintaxis. ¿Por qué la llamada de ADD_PARTNER funciona ahora para la compañía de vehículos de alquiler?
200
© Copyright . Reservados todos los derechos.
Capítulo 4 Solución 13 Integre los modelos de clase con interfaces.
Ejemplo empresarial Necesita añadir la compañía de vehículos de alquiler con sus vehículos en su propio modelo de objeto. Al implementar la interfaz ya definida, garantizará que la compañía de vehículos de alquiler podrá añadirse a la lista de interlocutores comerciales de la agencia de viajes. Modelo: SAPBC401_INT_T3 Solución: SAPBC401_INT_S3 Tarea 1 Copie las definiciones e implementaciones de las clases LCL_RENTAL y de las clases de vehículos (LCL_VEHICLE, LCL_TRUCK y LCL_BUS) en su programa y cree las instancias de las clases. 1. Complete su programa ZBC401_##_MAIN (## es el número de grupo de dos cifras) o copie el programa de modelo con todos los INCLUDE. a) Realice este paso de la forma habitual. Para más información, consulte la biblioteca SAP. 2. Si ha copiado el programa de modelo, analícelo y continúe con la próxima tarea. Si desea continuar trabajando con su propio programa, primero copie el programa de INCLUDE BC401_INT_T3_RENTAL (nombre sugerido: ZBC401_##_RENTAL, donde ## es el número de grupo de dos cifras) y realice la nueva parte del programa de INCLUDE de su propio programa. a) Realice este paso de la forma habitual. Para más información, consulte la biblioteca SAP. 3. En su programa principal, cree una instancia de LCL_RENTAL y un número de instancias de las clases de vehículos. Añada todos los vehículos a la lista de vehículos de la compañía de alquiler llamando al método ADD_VEHICLE de LCL_RENTAL. Consejo: Para reducir el trabajo de tipeado, puede copiar y pegar la codificación relevante desde el programa principal de SAPBC401_INT_T3. a) Véase el extracto de código fuente de la solución modelo. Tarea 2 Implemente la interfaz LIF_PARTNER en la clase LCL_RENTAL.
© Copyright . Reservados todos los derechos.
201
Capítulo 4: Interfaces y casting
1. Llame al método ADD_PARTNER para añadir la instancia de LCL_RENTAL a la lista de interlocutores comerciales de la agencia de viajes. a) Véase el extracto de código fuente de la solución modelo. 2. Verifique la sintaxis. ¿Por qué produce un error de sintaxis esta llamada de método? El up-cast en el paso de parámetro del método no funciona porque los tipos LCL_RENTAL y LIF_PARTNER no son compatibles. Sin embargo, serán compatibles en cuanto LCL_RENTAL implemente la interfaz. 3. Consulte la sección de definición de clase LCL_RENTAL y declare la implementación de la interfaz LIF_PARTNER. a) Véase el extracto de código fuente de la solución modelo. 4. Proporcione una implementación del método definido en la interfaz. a) Véase el extracto de código fuente de la solución modelo. 5. Active el INCLUDE con la definición e implementación de LCL_RENTAL. A continuación, acceda al programa principal y realice otra verificación de sintaxis. ¿Por qué la llamada de ADD_PARTNER funciona ahora para la compañía de vehículos de alquiler? Porque ahora los tipos LCL_RENTAL y LIF_PARTNER son compatibles. LCL_RENTAL implementa la interfaz LIF_PARTNER. Se acepta cualquier instancia de LCL_RENTAL como interlocutor comercial. a) Solución: programa de Include BC401_INT_S3_RENTAL *------------------------------------------------* * CLASS lcl_vehicle DEFINITION *------------------------------------------------* CLASS lcl_vehicle DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING iv_make TYPE string, display_attributes. PRIVATE SECTION. DATA: mv_make TYPE string. ENDCLASS. "lcl_vehicle DEFINITION *------------------------------------------------* * CLASS lcl_vehicle IMPLEMENTATION *------------------------------------------------* CLASS lcl_vehicle IMPLEMENTATION. METHOD constructor. mv_make = iv_make. ENDMETHOD. "constructor METHOD display_attributes. WRITE mv_make. ENDMETHOD. "display_attributes ENDCLASS. "lcl_vehicle IMPLEMENTATION
202
© Copyright . Reservados todos los derechos.
Lección: Unión de modelos de clase con interfaces
*-------------------------------------------------* * CLASS lcl_truck DEFINITION *-------------------------------------------------* CLASS lcl_truck DEFINITION INHERITING FROM lcl_vehicle. PUBLIC SECTION. METHODS: constructor IMPORTING iv_make TYPE string iv_cargo TYPE s_plan_car, display_attributes REDEFINITION. PRIVATE SECTION. DATA: mv_cargo TYPE s_plan_car. ENDCLASS. "lcl_truck DEFINITION *-----------------------------------------------* * CLASS lcl_truck IMPLEMENTATION *------------------------------------------------* CLASS lcl_truck IMPLEMENTATION. METHOD constructor. super->constructor( iv_make ). mv_cargo = iv_cargo. ENDMETHOD. "constructor METHOD display_attributes. WRITE / icon_ws_truck AS ICON. super->display_attributes( ). WRITE: 20 'Max. Cargo:'(005), mv_cargo. ULINE. ENDMETHOD. "display_attributes ENDCLASS. "lcl_truck DEFINITION *-------------------------------------------------* * CLASS lcl_bus DEFINITION *-------------------------------------------------* CLASS lcl_bus DEFINITION INHERITING FROM lcl_vehicle. PUBLIC SECTION. METHODS: constructor IMPORTING iv_make TYPE string iv_passengers TYPE i, display_attributes REDEFINITION. PRIVATE SECTION. DATA: mv_passengers TYPE i. ENDCLASS. "lcl_bus DEFINITION *--------------------------------------------------* * CLASS lcl_bus IMPLEMENTATION *--------------------------------------------------* CLASS lcl_bus IMPLEMENTATION. METHOD constructor. super->constructor( iv_make ). mv_passengers = iv_passengers. ENDMETHOD. "constructor METHOD display_attributes. WRITE: / icon_transportation_mode AS ICON. super->display_attributes( ). WRITE: 20 'Max. Passengers: '(006), mv_passengers. ULINE.
© Copyright . Reservados todos los derechos.
203
Capítulo 4: Interfaces y casting
ENDMETHOD. "display_attributes ENDCLASS. "lcl_bus DEFINITION *-------------------------------------------------* * CLASS lcl_rental DEFINITION *-------------------------------------------------* CLASS lcl_rental DEFINITION. PUBLIC SECTION. INTERFACES: lif_partner. METHODS: constructor IMPORTING iv_name TYPE string, add_vehicle IMPORTING io_vehicle TYPE REF TO lcl_vehicle, display_attributes. PRIVATE SECTION. DATA: mv_name TYPE string, mt_vehicles TYPE TABLE OF REF TO lcl_vehicle. ENDCLASS. "lcl_rental DEFINITION *----------------------------------------------* * CLASS lcl_rental IMPLEMENTATION *----------------------------------------------* CLASS lcl_rental IMPLEMENTATION. METHOD constructor. mv_name = iv_name. ENDMETHOD. "constructor METHOD add_vehicle. APPEND io_vehicle TO mt_vehicles. ENDMETHOD. "add_vehicle METHOD display_attributes. DATA: lo_vehicle TYPE REF TO lcl_vehicle. WRITE: / icon_transport_proposal AS ICON, mv_name. ULINE. ULINE. LOOP AT mt_vehicles INTO lo_vehicle. lo_vehicle->display_attributes( ). ENDLOOP. ENDMETHOD. "display_attributes METHOD lif_partner~display_partner. me->display_attributes( ). ENDMETHOD. "lif_partner~display_partner ENDCLASS. "lcl_rental IMPLEMENTATION b) Solución: programa principal SAPBC401_INT_S3 REPORT sapbc401_int_s3. TYPE-POOLS icon. INCLUDE bc401_int_s3_agency. INCLUDE bc401_int_s3_carrier. INCLUDE bc401_int_s3_rental.
204
© Copyright . Reservados todos los derechos.
Lección: Unión de modelos de clase con interfaces
DATA: go_vehicle TYPE REF TO lcl_vehicle, go_truck TYPE REF TO lcl_truck, go_bus TYPE REF TO lcl_bus, go_rental TYPE REF TO lcl_rental. DATA: go_agency TYPE REF TO lcl_travel_agency, go_carrier TYPE REF TO lcl_carrier, go_airplane TYPE REF TO lcl_airplane, go_cargo TYPE REF TO lcl_cargo_plane, go_passenger TYPE REF TO lcl_passenger_plane, gv_count TYPE i. START-OF-SELECTION. ******************* ******* create travel_agency CREATE OBJECT go_agency EXPORTING iv_name = 'Travel&Smile Travel'. ******* create rental CREATE OBJECT go_rental EXPORTING iv_name = 'Happy Car Rental'. ***** Insert rental company into partner list of ***** travel agency go_agency->add_partner( go_rental ). ******* create truck CREATE OBJECT go_truck EXPORTING iv_make = 'MAN' iv_cargo = 45. go_rental->add_vehicle( go_truck ). ******* create truck CREATE OBJECT go_bus EXPORTING iv_make = 'Mercedes' iv_passengers = 80. go_rental->add_vehicle( go_bus ). ******* create truck CREATE OBJECT go_truck EXPORTING iv_make = 'VOLVO' iv_cargo = 48. go_rental->add_vehicle( go_truck ). ***** Create Carrier CREATE OBJECT go_carrier EXPORTING iv_name = 'Smile&Fly-Travel'. ***** Insert carrier into business partner list
© Copyright . Reservados todos los derechos.
205
Capítulo 4: Interfaces y casting
***** of travel agency go_agency->add_partner( go_carrier ). ***** Passenger Plane CREATE OBJECT go_passenger EXPORTING iv_name = 'LH BERLIN' iv_planetype = '747-400' iv_seats = 345 EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. go_carrier->add_airplane( go_passenger ). ENDIF. ***** cargo Plane CREATE OBJECT go_cargo EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' iv_cargo = 533 EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. go_carrier->add_airplane( go_cargo ). ENDIF. ******* show attributes of all partners of travel_agency go_agency->display_attributes( ).
206
© Copyright . Reservados todos los derechos.
Lección: Unión de modelos de clase con interfaces
Implementación de jerarquías de interfaz
Figura 91: Jerarquía de interfaces en el ejemplo de aplicación
Una implementación de interfaz es muy similar a la herencia normal. Con herencia regular puede definir grandes jerarquías de clases. Al utilizar interfaces en lugar de clases, lo llamamos jerarquías de interfaces. Nos gustaría ilustrar esta técnica con un ejemplo de aplicación. En este ejemplo, necesita saber si sería útil definir otro servicio de "ocupación de salas" en la interfaz LIF_PARTNER. En este caso, las clases LCL_CARRIER y LCL_RENTAL necesitan implementar el método adecuado porque se han integrado con la interfaz LIF_PARTNER. Sin embargo, mantener la misma semántica no es posible para las aerolíneas o empresas de alquiler de automóviles cuando se implementa el servicio de "ocupación de salas". Sin embargo, dado que existen otros tipos de interlocutor comercial para los que sería útil esta implementación (p. ej., moteles y hoteles), el método debe definirse de manera central y no individual para moteles y hoteles. Si también necesitamos ampliar el modelo con otros tipos de proveedores de alojamiento, como hostales, la jerarquía de interfaz debe retenerse.
© Copyright . Reservados todos los derechos.
207
Capítulo 4: Interfaces y casting
Interfaz compuesta en lenguaje unificado de modelado (UML)
Figura 92: Interfaz compuesta en notación UML
En los objetos ABAP, las interfaces, como clases superiores normales, pueden incluir otras interfaces. Como con la herencia normal, las jerarquías de interfaces pueden ser de cualquier profundidad. La interfaz de inclusión es una especialización de la interfaz incluida. La interfaz de inclusión se conoce como interfaz compuesta, representa una extensión de la interfaz incluida. Una interfaz incluida representa un componente de otra interfaz y, por tanto, se conoce como una interfaz compuesta. Una interfaz que no contiene otras interfaces en su interior se conoce como interfaz elemental. La notación UML corresponde a la implementación de una interfaz elemental por parte de una clase.
208
© Copyright . Reservados todos los derechos.
Lección: Unión de modelos de clase con interfaces
Definición e implementación de interfaces compuestas: sintaxis
Figura 93: Definición e implementación de interfaces compuestas: sintaxis
Como con la herencia normal, la clase de implementación sólo necesita enumerar la interfaz compuesta para integrar todos los componentes. No obstante, los componentes de las interfaces de componente mantienen sus nombres originales: component_interface_name~component_name Por lo tanto, no están prefijados con el nombre de la interfaz compuesta. Las implementaciones de métodos de todas las interfaces de mayor nivel deben realizarse en la primera clase de implementación. Los nombres de alias son adecuados para la sintaxis de forma corta cuando accede a los componentes de distintas interfaces. Si la clase de implementación contiene alias, proporciona una vista central de todos los componentes.
© Copyright . Reservados todos los derechos.
209
Capítulo 4: Interfaces y casting
Cómo dirigirse a componentes en interfaces compuestas – Sintaxis
Figura 94: Cómo dirigirse a componentes en interfaces compuestas – Sintaxis
Es necesario abordar los componentes de una interfaz compuesta y realizar asignaciones cast de la misma manera.
Uso correcto de interfaces
Figura 95: Utilización de interfaces
Las interfaces se utilizan para describir los protocolos para el uso de componentes sin conectar ninguna implementación. Se introduce una capa intermedia para proteger al cliente del servidor explícito, lo cual permite que el cliente sea independiente. Las interfaces permiten tratar diferentes clases de manera uniforme si esas clases implementaron sus interfaces. Como con la herencia, también se puede realizar polimorfismo con variables de referencia de interfaz. Como en el caso de la herencia normal, la definición de una interfaz significa la abstracción de las clases de implementación en un aspecto específico.
210
© Copyright . Reservados todos los derechos.
Lección: Unión de modelos de clase con interfaces
Las herencias múltiples pueden simularse mediante interfaces: Si se incluyen varias interfaces, todos los componentes estarán disponibles para todas estas interfaces y deberá implementar todos los métodos.
© Copyright . Reservados todos los derechos.
211
Capítulo 4: Interfaces y casting
RESUMEN DE LA LECCIÓN Ahora podrá:
212
●
Implementar down-casts con interfaces
●
Integrar distintos submodelos con interfaces
●
Crear y utilizar jerarquías de interfaz
© Copyright . Reservados todos los derechos.
Capítulo 4 Evaluación de la formación
1. De los siguientes enunciados, ¿cuál se utiliza para implementar una interfaz en una clase? Seleccione la respuesta correcta. X
A ALIASES
X
B METHODS
X
C INTERFACES
2. Puede acceder a los componentes de interfaz solo mediante una referencia de objeto. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
3. De las siguientes opciones, ¿cuál es el punto fuerte principal de las interfaces? Seleccione la respuesta correcta. X
A Eventos
X
B Herencia
X
C Polimorfismo
4. ?= es el operador de asignación down cast. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
213
Capítulo 4: Evaluación de la formación
5. De las siguientes, ¿cuál se asemeja más a la herencia? Seleccione la respuesta correcta. X
A Interfaz
X
B Clase
X
C Método
6. Las interfaces como clases superiores pueden incluir otras interfaces. Indique si esta afirmación es verdadera o falsa.
214
X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
Capítulo 4 Respuestas a la Evaluación de la formación
1. De los siguientes enunciados, ¿cuál se utiliza para implementar una interfaz en una clase? Seleccione la respuesta correcta. X
A ALIASES
X
B METHODS
X
C INTERFACES
2. Puede acceder a los componentes de interfaz solo mediante una referencia de objeto. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
3. De las siguientes opciones, ¿cuál es el punto fuerte principal de las interfaces? Seleccione la respuesta correcta. X
A Eventos
X
B Herencia
X
C Polimorfismo
4. ?= es el operador de asignación down cast. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
215
Capítulo 4: Respuestas a la Evaluación de la formación
5. De las siguientes, ¿cuál se asemeja más a la herencia? Seleccione la respuesta correcta. X
A Interfaz
X
B Clase
X
C Método
6. Las interfaces como clases superiores pueden incluir otras interfaces. Indique si esta afirmación es verdadera o falsa.
216
X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
CAPÍTULO 5
Eventos orientados a objetos
Lección 1 Implementación de eventos en clases locales Ejercicio 14: Implementar eventos en las clases locales
218 227
Lección 2 Implementación de eventos en interfaces locales Ejercicio 15: Implementar el tratamiento de eventos para las interfaces
240 241
OBJETIVOS DEL CAPÍTULO ●
Implementar llamadas de método controladas por evento
●
Desencadenar y tratar eventos
●
Registrarse para eventos
●
Explicar las secciones de visibilidad en el tratamiento de eventos
●
Implementar eventos en las interfaces locales
© Copyright . Reservados todos los derechos.
217
Capítulo 5 Lección 1 Implementación de eventos en clases locales
RESUMEN DE LA LECCIÓN Este módulo explica el método de la implementación de eventos en las clases locales. Ejemplo empresarial Como desarrollador, desea implementar un comportamiento controlado por evento para su modelo en los objetos ABAP. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de cómo definir y desencadenar eventos
●
Una buena comprensión de cómo crear eventos
●
Una buena comprensión de cómo registrar eventos
●
Una buena comprensión de cómo implementar eventos en clases locales
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Implementar llamadas de método controladas por evento
●
Desencadenar y tratar eventos
●
Registrarse para eventos
●
Explicar las secciones de visibilidad en el tratamiento de eventos
Llamadas de método controladas por evento
Figura 96: Llamadas de método controladas por evento
218
© Copyright . Reservados todos los derechos.
Lección: Implementación de eventos en clases locales
Además de atributos y métodos, las clases y sus instancias pueden contener un tercer tipo de componente: los eventos. Los eventos de instancia pueden ser desencadenados por parte de las instancias de la clase, pero los eventos de instancia estáticos pueden ser desencadenados por la clase en sí. Los eventos también se pueden definir como componentes de interfaz. Si se dan las circunstancias adecuadas, los métodos de programa de control pueden reaccionar ante el desencadenamiento de este evento. Esto significa que el sistema de tiempo de ejecución puede llamar estos métodos de programa de control después de que el evento fue desencadenado. En otras palabras, el cliente generalmente no llama el método de programa de control de manera directa. Esto provoca un concepto de modelación completamente diferente. mientras está desarrollando la clase que desencadena el evento, no necesita saber nada acerca de la clase que lo está tratando. La clase de desencadenamiento envía un mensaje específico a todas las clases y, si es necesario, a sus instancias. Al momento del desarrollo, no se conocen los tipos de programas de control ni la cantidad de programas de control que podrían usarse. Debido a la definición de método de programa de control, el rango de resultados posibles puede limitarse. Sin embargo, los resultados que pueden producirse solo podrán determinarse después de que el evento fue desencadenado. Un evento puede tener parámetros de exportación, lo que significa que, al contrario que una llamada de método explícita, el programa de llamada determina el protocolo. En este ejemplo de aplicación, después de haberse creado una instancia en la clase de vehículo, la instancia desencadena el evento vehículo creado. Este evento es recibido por varias instancias y se procesa de manera distinta por cada una. Por ejemplo, la compañía de vehículos de alquiler trata la compra de un vehículo, mientras que la oficina de registro de vehículos registra el vehículo adquirido.
Atención: No confunda este concepto de eventos en la programación orientada a objetos con los eventos en el sistema de tiempo de ejecución ABAP, como LOAD-OF -PROGRAM, START-OF-SELECTION, etc. Tampoco confunda este concepto con el procesamiento de fondo ni con el control de workflow.
© Copyright . Reservados todos los derechos.
219
Capítulo 5: Eventos orientados a objetos
Tratamiento de eventos en un diagrama de clases UML
Figura 97: Tratamiento de eventos en un diagrama de clases UML
En los diagramas de clases UML, una flecha punteada con el estereotipo «handlesEventOf» apunta desde la clase de tratamiento a la clase de desencadenamiento. La definición de evento y la firma sólo aparecen implícitamente en la clase de tratamiento dentro del método de programa de control. Los métodos de programa de control están separados de los otros métodos mediante el estereotipo «eventHandler». Para desencadenar y tratar eventos Este procedimiento resume todos los pasos de programación necesarios para el control por eventos: 1. Defina un evento en una clase. La sintaxis es EVENTS eventname, CLASS-EVENTS eventname. 2. Desencadenar el evento en un método de esta clase. La sintaxis para ello es RAISE EVENT eventname. 3. Definir e implementar el método de programa de control en el mismo u otro. La sintaxis para ello es [CLASS -] METHODS … FOR EVENT …. OF ... 4. Registrar objeto o clase del programa de control para eventos en tiempo de ejecución. La sintaxis para ello es SET HANDLER.
220
© Copyright . Reservados todos los derechos.
Lección: Implementación de eventos en clases locales
Desencadenar y tratar eventos
Figura 98: Definición y desencadenamiento de eventos - Sintaxis
Dependiendo del estado de su aplicación, es posible que no necesite programar todos los pasos cada vez. La separación de causa y efecto en su programación debería reflejarse en la manera en que construye aplicaciones complejas. A menudo, el evento ya está desencadenado y todo lo que debe hacer es crear otro programa de control de eventos. Dentro de una clase, los eventos de instancia se definen utilizando la sentencia EVENTS, mientras que los eventos estáticos se definen utilizando la sentencia CLASS-EVENTS. Los eventos solo pueden tener parámetros de exportación que deben transmitirse por valor. Una clase o instancia puede desencadenar un evento en tiempo de ejecución mediante la sentencia RAISE EVENT. Tanto los eventos de instancia como los eventos estáticos pueden desencadenarse en métodos de instancia. Puede desencadenar eventos estáticos en los métodos estáticos. Cuando se desencadena un evento, los métodos de programa de control que se registran para este evento se llaman en secuencia. Estos métodos de programa de control pueden desencadenar más eventos propios.
© Copyright . Reservados todos los derechos.
221
Capítulo 5: Eventos orientados a objetos
Eventos de tratamiento - Sintaxis
Figura 99: Eventos de tratamiento - Sintaxis
Los eventos de instancia o los métodos estáticos pueden definirse dentro de una clase como eventos de tratamiento. Para ello, debe especificar el evento con la sentencia FOR EVENT y la clase o interfaz en el cual se definió el evento con la sentencia OF. Si el evento contiene parámetros de exportación y desea poder dirigirse a ellos sintácticamente, debe haber especificado los parámetros de exportación inmediatamente después de IMPORTING en la definición de método. Los parámetros de exportación de la firma del método del programa de control son los que puede incluir de manera explícita como parámetros de exportación del evento asociado. Los parámetros se introducen por el método de programa de control durante la definición del evento. El objeto que desencadena el evento determina el protocolo. Además de los parámetros de exportación definidos de manera explícita, el parámetro de importación predefinido SENDER siempre puede enumerarse. Al utilizar este parámetro, puede situar una referencia al objeto de desencadenamiento de evento en el método de programa de control. Por lo tanto, los métodos de programa de control se llaman normalmente por parte de eventos desencadenados RAISE EVENT. Sin embargo, también pueden llamarse explícitamente (CALL METHOD).
222
© Copyright . Reservados todos los derechos.
Lección: Implementación de eventos en clases locales
Registro del programa de control de eventos
Figura 100: Registro del programa de control de eventos
La definición del método de programa de control solo especifica cómo y para qué evento de qué clase reacciona el método. En tiempo de ejecución, debe determinarse qué posibles reacciones realmente tendrán lugar y cuándo se producirá cada una de ellas. Al desencadenar eventos de instancia, también debe especificar qué evento desencadenará la reacción. Si hay métodos de instancia fijados para que lleven a cabo la reacción, también se deberá(n) especificar la(s) instancia(s) que efectuará(n) la reacción. Estas especificaciones se conocen de manera colectiva como la inscripción. El registro siempre se lleva a cabo mediante el desencadenador. Cuando el evento se desencadena, el tiempo de ejecución utiliza las inscripciones del desencadenador para determinar qué métodos de programa de control deben ser llamados. En este ejemplo, se definen los métodos de programa de control para el evento de la clase de vehículo, la clase de vehículo de alquiler y la clase de matriculación de vehículo. Sin embargo, sólo es posible predeterminar qué instancias de vehículos de alquiler y qué instancias de matriculación de vehículo reaccionarán ante qué instancia de vehículo, y cuándo lo harán. Las inscripciones también pueden ser anuladas.
© Copyright . Reservados todos los derechos.
223
Capítulo 5: Eventos orientados a objetos
Inscripción del tratamiento de eventos - Sintaxis
Figura 101: Inscripción del tratamiento de eventos - Sintaxis
Los eventos se registran mediante la sentencia SET HANDLER. La inscripción sólo está activa durante el tiempo de ejecución del programa. Con los eventos de instancia, FOR es seguido por la referencia al objeto que desencadena el evento. El suplemento ACTIVATION 'X' es opcional durante el registro. Para deshacer el registro, utilice ACTIVATION ' '. Es posible registrar varios métodos con una sentencia SET HANDLER: SET HANDLER ref_handler_1->on_eventname_1 ... ref_handler_n->on_eventname_n FOR ... Atención: Si se han registrado varios métodos en un evento, la secuencia en la que los métodos de programa de control se llaman no está definida, es decir, no existe ninguna secuencia garantizada en la que se llamen los métodos de programa de control. Con el suplemento ALL INSTANCES, un control de eventos puede registrarse para todas las instancias de la clase que define al evento de instancia. Éste es el único modo de registrar a objetos que aún no han sido creados.
224
© Copyright . Reservados todos los derechos.
Lección: Implementación de eventos en clases locales
Tablas del programa de control de eventos
Figura 102: Tablas del programa de control del registro/cancelación
Cada objeto o clase que define eventos tiene una tabla interna conocida como la tabla del programa de control. Todos los métodos del programa de control que están registrados en los eventos se enumeran en la tabla del programa de control. Para métodos de instancia, la tabla de programa de control también contiene referencias a los objetos registrados.
Consejo: Los objetos que se registran para el tratamiento de eventos no son eliminados por el recolector de basura, aún si no se conservan referencias hacia ellos.
Nota: Es posible añadir o eliminar programas de control de eventos para un evento determinado mientras se ejecuta un programa de control de eventos para exactamente el mismo evento. Si se registra un nuevo programa de control de eventos, este se agrega al final de la secuencia y se ejecuta cuando sea el momento. Si se cancela el registro de un programa de control de eventos existente, este programa de control se elimina inmediatamente de la secuencia de método de programa de control de eventos.
Secciones de visibilidad en tratamiento de eventos Los eventos están sujetos al concepto de visibilidad y pueden ser, por lo tanto, públicos, protegidos o privados. Los métodos de programa de control de eventos también tienen atributos de visibilidad. Las siguientes secciones de visibilidad determinan dónde pueden tratarse los eventos:
© Copyright . Reservados todos los derechos.
225
Capítulo 5: Eventos orientados a objetos
●
PUBLIC Se puede acceder a ellos desde cualquier lugar.
●
PROTECTED Solo pueden tratarse dentro de esta clase o de sus subclases.
●
PRIVATE Sólo puede tratarse dentro de su clase
La visibilidad del método de programa de control es la siguiente: ●
PUBLIC En cualquier lugar del programa
●
PROTECTED Pueden tratarse dentro de esta clase o de sus subclases.
●
PRIVATE Sólo puede tratarse dentro de su clase
Los métodos de programa de control de eventos solo pueden tener la misma visibilidad, o una más restringida, que los eventos a los que hacen referencia.
226
© Copyright . Reservados todos los derechos.
Capítulo 5 Ejercicio 14 Implementar eventos en las clases locales
Ejemplo empresarial Necesita incluir referencias de aviones y vehículos en las listas de compañía aérea y de vehículos. Este proceso debe estar controlado por eventos. Modelo: SAPBC401_INT_S3 Solución: SAPBC401_EVE_S1 Tarea 1 Defina un evento para la creación de un avión. Desencadene y trate el evento de manera que la referencia al avión se introduzca en la lista de aviones de la compañía aérea. 1. Utilice su programa ZBC401_##_MAIN (## es el número de grupo de dos cifras) o copie el programa modelo. Identifique la clase adecuada para desencadenar el evento y la clase que debería utilizar para tratar el evento. Utilice su diagrama UML si es necesario. 2. Defina el evento público AIRPLANE_CREATED en la clase LCL_AIRPLANE. Seleccione un método adecuado de LCL_AIRPLANE y active el evento en su implementación. 3. En la clase LCL_CARRIER, defina un método de control para el evento que acaba de definir (nombre recomendado: ON_AIRPLANE_CREATED). 4. Implemente el método de control para que se añada el nuevo avión a la lista de aviones de la compañía aérea. Consejo: Puede hacerlo directamente o llamando al método existente ADD_AIRPLANE. En ambos casos, asegúrese de que no pueda añadirse el avión a la lista nuevamente. Por lo tanto, elimine el método ADD_AIRPLANE o hágalo privado. 5. Elimine todas las de ADD_AIRPLANE de su programa principal. 6. Registre el nuevo método de programa de control, de manera que cada avión creado se añada a la lista de aviones por compañía aérea.
© Copyright . Reservados todos los derechos.
227
Capítulo 5: Eventos orientados a objetos
Nota: A pesar de que este modelo no es realista, lo utilizaremos de momento. Puede crear una regla distinta para indicar el avión posteriormente. 7. ¿Dónde podría ejecutarse la sentencia SET HANDLER en el ejemplo expuesto? ¿También podría hacerse desde el programa principal?
8. Observe la ejecución del programa en el ABAP Debugger. 9. ¿Cuál tendría que ser la sintaxis en este caso?
Tarea 2 Defina un evento para la creación de un vehículo. Desencadene y trate el evento de manera que la referencia al vehículo se introduzca en la lista de vehículos de la compañía de vehículos de alquiler. 1. Elimine todas las llamadas de ADD_VEHICLE de su programa principal. 2. Defina el evento público VEHICLE_CREATED en la clase LCL_VEHICLE y active el evento en la implementación de constructor. 3. En la clase LCL_RENTAL, defina e implemente un método de control para el evento que acaba de definir (nombre recomendado: ON_VEHICLE_CREATED). 4. Registre el nuevo método de programa de control, de manera que cada vehículo se haya añadido a la lista de vehículos por compañía de alquiler de vehículos. Nota: A pesar de que este modelo no es realista, lo utilizaremos de momento. Más adelante podrá crearse una regla distinta para introducir los vehículos. 5. Observe la ejecución del programa en el ABAP Debugger.
228
© Copyright . Reservados todos los derechos.
Capítulo 5 Solución 14 Implementar eventos en las clases locales
Ejemplo empresarial Necesita incluir referencias de aviones y vehículos en las listas de compañía aérea y de vehículos. Este proceso debe estar controlado por eventos. Modelo: SAPBC401_INT_S3 Solución: SAPBC401_EVE_S1 Tarea 1 Defina un evento para la creación de un avión. Desencadene y trate el evento de manera que la referencia al avión se introduzca en la lista de aviones de la compañía aérea. 1. Utilice su programa ZBC401_##_MAIN (## es el número de grupo de dos cifras) o copie el programa modelo. Identifique la clase adecuada para desencadenar el evento y la clase que debería utilizar para tratar el evento. Utilice su diagrama UML si es necesario. a) Realice este paso de la forma habitual. Para más información, consulte la biblioteca SAP. 2. Defina el evento público AIRPLANE_CREATED en la clase LCL_AIRPLANE. Seleccione un método adecuado de LCL_AIRPLANE y active el evento en su implementación. a) Consulte el extracto del código fuente de la solución del modelo. 3. En la clase LCL_CARRIER, defina un método de control para el evento que acaba de definir (nombre recomendado: ON_AIRPLANE_CREATED). a) Consulte el extracto del código fuente de la solución del modelo. 4. Implemente el método de control para que se añada el nuevo avión a la lista de aviones de la compañía aérea. Consejo: Puede hacerlo directamente o llamando al método existente ADD_AIRPLANE. En ambos casos, asegúrese de que no pueda añadirse el avión a la lista nuevamente. Por lo tanto, elimine el método ADD_AIRPLANE o hágalo privado. a) Consulte el extracto del código fuente de la solución del modelo. 5. Elimine todas las de ADD_AIRPLANE de su programa principal. a) Consulte el extracto del código fuente de la solución del modelo.
© Copyright . Reservados todos los derechos.
229
Capítulo 5: Eventos orientados a objetos
6. Registre el nuevo método de programa de control, de manera que cada avión creado se añada a la lista de aviones por compañía aérea. Nota: A pesar de que este modelo no es realista, lo utilizaremos de momento. Puede crear una regla distinta para indicar el avión posteriormente. a) Consulte el extracto del código fuente de la solución del modelo. 7. ¿Dónde podría ejecutarse la sentencia SET HANDLER en el ejemplo expuesto? ¿También podría hacerse desde el programa principal? En el constructor de LCL_CARRIER o en el programa principal después de la creación de LCL_CARRIER, pero antes de la creación del primer avión. 8. Observe la ejecución del programa en el ABAP Debugger. a) Realice este paso de la forma habitual. Encontrará información adicional en la biblioteca SAP. 9. ¿Cuál tendría que ser la sintaxis en este caso? SET HANDLER go_carrier->on_airplane_created FOR ALL INSTANCES. Tarea 2 Defina un evento para la creación de un vehículo. Desencadene y trate el evento de manera que la referencia al vehículo se introduzca en la lista de vehículos de la compañía de vehículos de alquiler. 1. Elimine todas las llamadas de ADD_VEHICLE de su programa principal. a) Consulte el extracto del código fuente de la solución del modelo. 2. Defina el evento público VEHICLE_CREATED en la clase LCL_VEHICLE y active el evento en la implementación de constructor. a) Consulte el extracto del código fuente de la solución del modelo. 3. En la clase LCL_RENTAL, defina e implemente un método de control para el evento que acaba de definir (nombre recomendado: ON_VEHICLE_CREATED). a) Consulte el extracto del código fuente de la solución del modelo. 4. Registre el nuevo método de programa de control, de manera que cada vehículo se haya añadido a la lista de vehículos por compañía de alquiler de vehículos. Nota: A pesar de que este modelo no es realista, lo utilizaremos de momento. Más adelante podrá crearse una regla distinta para introducir los vehículos. a) Consulte el extracto del código fuente de la solución del modelo. 5. Observe la ejecución del programa en el ABAP Debugger.
230
© Copyright . Reservados todos los derechos.
Lección: Implementación de eventos en clases locales
a) Realice este paso de la forma habitual. Encontrará información adicional sobre el ABAP Debugger en la biblioteca SAP. Programa de Include BC401_EVE_S1_CARRIER *--------------------------------------------------* * CLASS lcl_airplane DEFINITION *--------------------------------------------------* CLASS lcl_airplane DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype EXCEPTIONS wrong_planetype, display_attributes. CLASS-METHODS: display_n_o_airplanes, class_constructor. EVENTS: airplane_created. PROTECTED SECTION. CONSTANTS: c_pos_1 TYPE i VALUE 30. PRIVATE SECTION. TYPES: ty_planetypes TYPE STANDARD TABLE OF saplane WITH NON-UNIQUE KEY planetype. DATA: mv_name mv_planetype mv_weight mv_tankcap
TYPE TYPE TYPE TYPE
string, saplane-planetype, saplane-weight, saplane-tankcap.
CLASS-DATA: gv_n_o_airplanes TYPE i, gt_planetypes TYPE ty_planetypes. CLASS-METHODS: get_technical_attributes IMPORTING iv_type TYPE saplane-planetype EXPORTING ev_weight TYPE saplane-weight ev_tankcap TYPE saplane-tankcap EXCEPTIONS wrong_planetype. ENDCLASS.
"lcl_airplane DEFINITION
*-------------------------------------------------*
© Copyright . Reservados todos los derechos.
231
Capítulo 5: Eventos orientados a objetos
* CLASS lcl_airplane IMPLEMENTATION *-------------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. METHOD class_constructor. SELECT * FROM saplane INTO TABLE gt_planetypes. ENDMETHOD. "class_constructor METHOD constructor. mv_name = iv_name. mv_planetype = iv_planetype. get_technical_attributes( EXPORTING iv_type = iv_planetype IMPORTING ev_weight = mv_weight ev_tankcap = mv_tankcap EXCEPTIONS wrong_planetype = 1 ). IF sy-subrc <> 0. RAISE wrong_planetype. ELSE. gv_n_o_airplanes = gv_n_o_airplanes + 1. RAISE EVENT airplane_created. ENDIF. ENDMETHOD.
"constructor
METHOD display_attributes. ... ENDMETHOD.
"display_attributes
METHOD display_n_o_airplanes. ... ENDMETHOD.
"display_n_o_airplanes
METHOD get_technical_attributes. ... ENDMETHOD. ENDCLASS.
"get_technical_attributes "lcl_airplane IMPLEMENTATION
*-------------------------------------------* * CLASS lcl_cargo_plane DEFINITION *-------------------------------------------* CLASS lcl_cargo_plane DEFINITION INHERITING FROM lcl_airplane. ... ENDCLASS.
"lcl_cargo_plane DEFINITION
*-----------------------------------------------* * CLASS lcl_cargo_plane IMPLEMENTATION
232
© Copyright . Reservados todos los derechos.
Lección: Implementación de eventos en clases locales
*-----------------------------------------------* CLASS lcl_cargo_plane IMPLEMENTATION. ... ENDCLASS.
"lcl_cargo_plane IMPLEMENTATION
*------------------------------------------------* * CLASS lcl_passenger_plane DEFINITION *------------------------------------------------* CLASS lcl_passenger_plane DEFINITION INHERITING FROM lcl_airplane. ... ENDCLASS.
"lcl_passenger_plane DEFINITION
*-------------------------------------------------* * CLASS lcl_passenger_plane IMPLEMENTATION *-------------------------------------------------* CLASS lcl_passenger_plane IMPLEMENTATION. ... ENDCLASS.
"lcl_passenger_plane IMPLEMENTATION
*--------------------------------------------------* * CLASS lcl_carrier DEFINITION *--------------------------------------------------* CLASS lcl_carrier DEFINITION. PUBLIC SECTION. INTERFACES lif_partner. METHODS: constructor IMPORTING iv_name TYPE string, display_attributes. PRIVATE SECTION. DATA: mv_name TYPE string, mt_airplanes TYPE TABLE OF REF TO lcl_airplane. METHODS: on_airplane_created FOR EVENT airplane_created OF lcl_airplane IMPORTING sender, display_airplanes. ENDCLASS.
"lcl_carrier DEFINITION
*--------------------------------------------------* * CLASS lcl_carrier IMPLEMENTATION *--------------------------------------------------* CLASS lcl_carrier IMPLEMENTATION. METHOD constructor. mv_name = iv_name. SET HANDLER on_airplane_created FOR ALL INSTANCES.
© Copyright . Reservados todos los derechos.
233
Capítulo 5: Eventos orientados a objetos
ENDMETHOD.
"constructor
METHOD lif_partner~display_partner. display_attributes( ). ENDMETHOD. "lif_partners~display_partner METHOD on_airplane_created. APPEND sender TO mt_airplanes. ENDMETHOD. "on_airplane_created METHOD display_attributes. SKIP 2. WRITE: icon_flight AS ICON, mv_name. ULINE. ULINE. display_airplanes( ). ENDMETHOD. "display_attributes METHOD display_airplanes. DATA: lo_plane TYPE REF TO lcl_airplane. LOOP AT mt_airplanes INTO lo_plane. lo_plane->display_attributes( ). ENDLOOP. ENDMETHOD. "display_airplanes ENDCLASS.
"lcl_carrier IMPLEMENTATION
Programa de Include BC401_EVE_S1_RENTAL *-----------------------------------------------* * CLASS lcl_vehicle DEFINITION *-----------------------------------------------* CLASS lcl_vehicle DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING iv_make TYPE string, display_attributes. CLASS-METHODS: get_count EXPORTING ev_count TYPE i. EVENTS: vehicle_created. PRIVATE SECTION. DATA: mv_make TYPE string. CLASS-DATA: gv_n_o_vehicles TYPE i. ENDCLASS.
"lcl_vehicle DEFINITION
*-------------------------------------------------* * CLASS lcl_vehicle IMPLEMENTATION *-------------------------------------------------* CLASS lcl_vehicle IMPLEMENTATION. METHOD constructor. mv_make = iv_make. ADD 1 TO gv_n_o_vehicles.
234
© Copyright . Reservados todos los derechos.
Lección: Implementación de eventos en clases locales
RAISE EVENT vehicle_created. ENDMETHOD. "constructor METHOD display_attributes. WRITE mv_make. ENDMETHOD. "display_attributes METHOD get_count. ev_count = gv_n_o_vehicles. ENDMETHOD. "get_count ENDCLASS.
"lcl_vehicle IMPLEMENTATION
*-----------------------------------------------* * CLASS lcl_truck DEFINITION *-----------------------------------------------* CLASS lcl_truck DEFINITION INHERITING FROM lcl_vehicle. ... ENDCLASS.
"lcl_truck DEFINITION
*-----------------------------------------------* * CLASS lcl_truck IMPLEMENTATION *-----------------------------------------------* CLASS lcl_truck IMPLEMENTATION. ... ENDCLASS.
"lcl_truck DEFINITION
*-------------------------------------------------* * CLASS lcl_bus DEFINITION *-------------------------------------------------* CLASS lcl_bus DEFINITION INHERITING FROM lcl_vehicle. ... ENDCLASS.
"lcl_bus DEFINITION
*-------------------------------------------------* * CLASS lcl_bus IMPLEMENTATION *-------------------------------------------------* CLASS lcl_bus IMPLEMENTATION. ... ENDCLASS.
"lcl_bus DEFINITION
*-------------------------------------------------* * CLASS lcl_rental DEFINITION *--------------------------------------------------* CLASS lcl_rental DEFINITION. PUBLIC SECTION. INTERFACES: lif_partner. METHODS: constructor IMPORTING iv_name TYPE string,
© Copyright . Reservados todos los derechos.
235
Capítulo 5: Eventos orientados a objetos
display_attributes. PRIVATE SECTION. DATA: mv_name TYPE string, mt_vehicles TYPE TABLE OF REF TO lcl_vehicle. METHODS: on_vehicle_created FOR EVENT vehicle_created OF lcl_vehicle IMPORTING sender. ENDCLASS.
"lcl_rental DEFINITION
*-------------------------------------------------* * CLASS lcl_rental IMPLEMENTATION *-------------------------------------------------* CLASS lcl_rental IMPLEMENTATION. METHOD lif_partner~display_partner. display_attributes( ). ENDMETHOD. "lif_partners~display_partner METHOD constructor. mv_name = iv_name. SET HANDLER on_vehicle_created FOR ALL INSTANCES. ENDMETHOD. "constructor METHOD on_vehicle_created. APPEND sender TO mt_vehicles. ENDMETHOD. "on_vehicle_created METHOD display_attributes. DATA: lo_vehicle TYPE REF TO lcl_vehicle. WRITE: / icon_transport_proposal AS ICON, mv_name. WRITE: / 'Here comes the vehicle list: '. ULINE. ULINE. LOOP AT mt_vehicles INTO lo_vehicle. lo_vehicle->display_attributes( ). ENDLOOP. ENDMETHOD. "display_attributes ENDCLASS.
"lcl_rental IMPLEMENTATION
Programa principal SAPBC401_EVE_S1 REPORT
sapbc401_eve_s1.
TYPE-POOLS icon. INCLUDE bc401_eve_s1_agency. INCLUDE bc401_eve_s1_carrier. INCLUDE bc401_eve_s1_rental. DATA: go_vehicle go_truck
236
TYPE REF TO lcl_vehicle, TYPE REF TO lcl_truck,
© Copyright . Reservados todos los derechos.
Lección: Implementación de eventos en clases locales
go_bus go_rental go_agency go_carrier go_airplane go_cargo go_passenger gv_count
TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE
REF REF REF REF REF REF REF i.
TO TO TO TO TO TO TO
lcl_bus, lcl_rental, lcl_travel_agency, lcl_carrier, lcl_airplane, lcl_cargo_plane, lcl_passenger_plane,
START-OF-SELECTION. ******************* ******* create travel_agency CREATE OBJECT go_agency EXPORTING iv_name = 'Travel&smile Travel'. ******* create rental CREATE OBJECT go_rental EXPORTING iv_name = 'Happy Car Rental'. ***** Insert rental company into partner list ***** of travel agency go_agency->add_partner( go_rental ). ******* create truck CREATE OBJECT go_truck EXPORTING iv_make = 'MAN' iv_cargo = 45. * go_rental->add_vehicle( go_truck ). ******* create truck CREATE OBJECT go_bus EXPORTING iv_make = 'Mercedes' iv_passengers = 80. * go_rental->add_vehicle( go_bus ). ******* create truck CREATE OBJECT go_truck EXPORTING iv_make = 'VOLVO' iv_cargo = 48. * go_rental->add_vehicle( go_truck ). ***** Create Carrier CREATE OBJECT go_carrier EXPORTING iv_name = 'Smile&Fly-Travel'. ***** Insert carrier into business partner list ***** of travel agency go_agency->add_partner( go_carrier ). ***** Passenger Plane CREATE OBJECT go_passenger EXPORTING iv_name = 'LH BERLIN' iv_planetype = '747-400' iv_seats = 345 EXCEPTIONS
© Copyright . Reservados todos los derechos.
237
Capítulo 5: Eventos orientados a objetos
wrong_planetype = 1. *
IF sy-subrc = 0. go_carrier->add_airplane( go_passenger ). ELSE. WRITE: / icon_failure AS ICON, 'Wrong plane type'. ENDIF.
***** cargo Plane CREATE OBJECT go_cargo EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' iv_cargo = 533 EXCEPTIONS wrong_planetype = 1. IF sy-subrc = 0. * go_carrier->add_airplane( go_cargo ). ELSE. WRITE: / icon_failure AS ICON, 'Wrong plane type'. ENDIF. ***** show attributes of all partners travel agency go_agency->display_attributes( ).
238
© Copyright . Reservados todos los derechos.
Lección: Implementación de eventos en clases locales
RESUMEN DE LA LECCIÓN Ahora podrá: ●
Implementar llamadas de método controladas por evento
●
Desencadenar y tratar eventos
●
Registrarse para eventos
●
Explicar las secciones de visibilidad en el tratamiento de eventos
© Copyright . Reservados todos los derechos.
239
Capítulo 5 Lección 2 Implementación de eventos en interfaces locales
RESUMEN DE LA LECCIÓN Este módulo explica la implementación de eventos en las interfaces locales. Ejemplo empresarial Como desarrollador, necesita implementar eventos en las clases locales del avión. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de los eventos
●
Una buena comprensión de las interfaces
●
Una buena comprensión de la implementación de eventos en interfaces locales
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Implementar eventos en las interfaces locales
Implementar eventos en las interfaces locales Los eventos se pueden definir como componentes de interfaz. El desencadenamiento y tratamiento de eventos se realiza como en las clases. Pasos para implementar el tratamiento de eventos para las interfaces: 1. Definir evento en una interfaz 2. Desencadenar el evento de interfaz en clases de implementación 3. Tratar evento de interfaz en clase del programa de control (con clase) 4. Registrar tratamiento de eventos
240
© Copyright . Reservados todos los derechos.
Capítulo 5 Ejercicio 15 Implementar el tratamiento de eventos para las interfaces
Ejemplo empresarial Deben introducirse las referencias de compañía aérea y de vehículos de alquiler en una lista de la agencia de viajes. Este proceso debe estar controlado por eventos. Asegúrese de crear su programa de manera que pueda ampliarse fácilmente para gestionar interlocutores comerciales adicionales de la agencia de viajes en el futuro. Modelo: SAPBC401_EVE_S1 Solución: SAPBC401_EVE_S2 Defina un evento para la creación de un interlocutor comercial. Desencadene y trate el evento de manera que la referencia al interlocutor comercial se introduzca en la lista de interlocutores de la agencia de viajes. 1. Use el programa ZBC401_##_MAIN o copie la solución modelo del ejercicio anterior (donde ## es su número de grupo de dos cifras). 2. Elimine las llamadas del método ADD_PARTNER de su programa principal. Nota: La entrada de una referencia a interlocutor comercial en la lista de la agencia de viajes debe estar controlada por evento. 3. Si es necesario, examine su diagrama UML. ¿Qué clase o interfaz debería definir el evento? ¿Qué clase o interfaz debería desencadenarlo? ¿Qué clase o interfaz debería tratarlo? Si corresponde, ilustre las relaciones en su diagrama UML. 4. Defina el evento PARTNER_CREATED y desencadénelo mediante un método adecuado en todas las clases que implementan la interfaz. 5. Elimine el método ADD_PARTNER en la clase LCL_TRAVEL_AGENCY. Reemplácelo por un método de controlador para el evento que acaba de definir (nombre propuesto: ON_PARTNER_CREATED). 6. Registre el nuevo método de programa de control, de manera que cada interlocutor comercial creado se añada a la lista de interlocutores por agencia de viajes.
© Copyright . Reservados todos los derechos.
241
Capítulo 5: Eventos orientados a objetos
Nota: A pesar de que este modelo no es realista, lo utilizaremos de momento. Más adelante podrá crearse una regla distinta para introducir el interlocutor comercial. 7. Observe la ejecución del programa en el ABAP Debugger.
242
© Copyright . Reservados todos los derechos.
Capítulo 5 Solución 15 Implementar el tratamiento de eventos para las interfaces
Ejemplo empresarial Deben introducirse las referencias de compañía aérea y de vehículos de alquiler en una lista de la agencia de viajes. Este proceso debe estar controlado por eventos. Asegúrese de crear su programa de manera que pueda ampliarse fácilmente para gestionar interlocutores comerciales adicionales de la agencia de viajes en el futuro. Modelo: SAPBC401_EVE_S1 Solución: SAPBC401_EVE_S2 Defina un evento para la creación de un interlocutor comercial. Desencadene y trate el evento de manera que la referencia al interlocutor comercial se introduzca en la lista de interlocutores de la agencia de viajes. 1. Use el programa ZBC401_##_MAIN o copie la solución modelo del ejercicio anterior (donde ## es su número de grupo de dos cifras). a) Realice este paso de la forma habitual. Para más información, consulte la biblioteca SAP. 2. Elimine las llamadas del método ADD_PARTNER de su programa principal. Nota: La entrada de una referencia a interlocutor comercial en la lista de la agencia de viajes debe estar controlada por evento. a) Véase el extracto del código fuente de la solución modelo. 3. Si es necesario, examine su diagrama UML. ¿Qué clase o interfaz debería definir el evento? ¿Qué clase o interfaz debería desencadenarlo? ¿Qué clase o interfaz debería tratarlo? Si corresponde, ilustre las relaciones en su diagrama UML. a) Hable con su instructor si tiene cualquier duda. 4. Defina el evento PARTNER_CREATED y desencadénelo mediante un método adecuado en todas las clases que implementan la interfaz. a) Véase el extracto del código fuente de la solución modelo.
© Copyright . Reservados todos los derechos.
243
Capítulo 5: Eventos orientados a objetos
5. Elimine el método ADD_PARTNER en la clase LCL_TRAVEL_AGENCY. Reemplácelo por un método de controlador para el evento que acaba de definir (nombre propuesto: ON_PARTNER_CREATED). a) Véase el extracto del código fuente de la solución modelo. 6. Registre el nuevo método de programa de control, de manera que cada interlocutor comercial creado se añada a la lista de interlocutores por agencia de viajes. Nota: A pesar de que este modelo no es realista, lo utilizaremos de momento. Más adelante podrá crearse una regla distinta para introducir el interlocutor comercial. a) Véase el extracto del código fuente de la solución modelo. 7. Observe la ejecución del programa en el ABAP Debugger. a) Realice este paso de la forma habitual. Encontrará información adicional sobre el ABAP Debugger en la biblioteca SAP. Solución: programa de Include BC401_EVE_S2_AGENCY *-----------------------------------------------* * INTERFACE lif_partners *&----------------------------------------------* INTERFACE lif_partner. METHODS: display_partner. EVENTS: partner_created. ENDINTERFACE. "lif_partners *------------------------------------------------* * CLASS lcl_travel_agency DEFINITION *------------------------------------------------* CLASS lcl_travel_agency DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING iv_name TYPE string, display_agency_partners, display_attributes. PRIVATE SECTION. DATA: mv_name TYPE string, mt_partners TYPE TABLE OF REF TO lif_partner. METHODS: on_partner_created FOR EVENT partner_created OF lif_partner IMPORTING sender. ENDCLASS. "lcl_travel_agency DEFINITION *-------------------------------------------------* * CLASS lcl_travel_agency IMPLEMENTATION *-------------------------------------------------* CLASS lcl_travel_agency IMPLEMENTATION. METHOD display_attributes.
244
© Copyright . Reservados todos los derechos.
Lección: Implementación de eventos en interfaces locales
WRITE: / icon_private_files AS ICON, 'Travel Agency:'(007), mv_name. SKIP. display_agency_partners( ). ENDMETHOD.
"display_attributes
METHOD display_agency_partners. DATA: lo_partner TYPE REF TO lif_partner. WRITE 'Here are the partners of the travel agency:'(008). ULINE. LOOP AT mt_partners INTO lo_partner. lo_partner->display_partner( ). ENDLOOP. ENDMETHOD.
"display_agency_partners
METHOD constructor. mv_name = iv_name. SET HANDLER on_partner_created FOR ALL INSTANCES. ENDMETHOD. "constructor METHOD on_partner_created. APPEND sender TO mt_partners. ENDMETHOD. "on_partner_created ENDCLASS.
"lcl_travel_agency IMPLEMENTATION
Solución: programa de Include BC401_EVE_S2_RENTAL *--------------------------------------------------* * CLASS lcl_vehicle DEFINITION *--------------------------------------------------* CLASS lcl_vehicle DEFINITION. ... ENDCLASS. "lcl_vehicle DEFINITION *--------------------------------------------------* * CLASS lcl_vehicle IMPLEMENTATION *--------------------------------------------------* CLASS lcl_vehicle IMPLEMENTATION. ... ENDCLASS. "lcl_vehicle IMPLEMENTATION *--------------------------------------------------* * CLASS lcl_truck DEFINITION *--------------------------------------------------* CLASS lcl_truck DEFINITION INHERITING FROM lcl_vehicle. ... ENDCLASS. "lcl_truck DEFINITION *--------------------------------------------------* * CLASS lcl_truck IMPLEMENTATION *--------------------------------------------------* CLASS lcl_truck IMPLEMENTATION. ... ENDCLASS. "lcl_truck DEFINITION *--------------------------------------------------*
© Copyright . Reservados todos los derechos.
245
Capítulo 5: Eventos orientados a objetos
* CLASS lcl_bus DEFINITION *--------------------------------------------------* CLASS lcl_bus DEFINITION INHERITING FROM lcl_vehicle. ... ENDCLASS. "lcl_bus DEFINITION *--------------------------------------------------* * CLASS lcl_bus IMPLEMENTATION *--------------------------------------------------* CLASS lcl_bus IMPLEMENTATION. ... ENDCLASS. "lcl_bus DEFINITION *--------------------------------------------------* * CLASS lcl_rental DEFINITION *--------------------------------------------------* CLASS lcl_rental DEFINITION. ... ENDCLASS. "lcl_rental DEFINITION *--------------------------------------------------* * CLASS lcl_rental IMPLEMENTATION *--------------------------------------------------* CLASS lcl_rental IMPLEMENTATION. METHOD lif_partner~display_partner. display_attributes( ). ENDMETHOD. "lif_partners~display_partner METHOD constructor. mv_name = iv_name. SET HANDLER on_vehicle_created FOR ALL INSTANCES. RAISE EVENT lif_partner~partner_created. ENDMETHOD.
"constructor
METHOD on_vehicle_created. APPEND sender TO mt_vehicles. ENDMETHOD. "on_vehicle_created METHOD display_attributes. ... ENDMETHOD. "display_attributes ENDCLASS.
"lcl_rental IMPLEMENTATION
Solución: programa de Include BC401_EVE_S2_CARRIER *-------------------------------------------------* * CLASS lcl_airplane DEFINITION *-------------------------------------------------* CLASS lcl_airplane DEFINITION. ... ENDCLASS. "lcl_airplane DEFINITION *-------------------------------------------------*
246
© Copyright . Reservados todos los derechos.
Lección: Implementación de eventos en interfaces locales
* CLASS lcl_airplane IMPLEMENTATION *-------------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. ... ENDCLASS. "lcl_airplane IMPLEMENTATION *-------------------------------------------------* * CLASS lcl_cargo_plane DEFINITION *-------------------------------------------------* CLASS lcl_cargo_plane DEFINITION INHERITING FROM lcl_airplane. ... ENDCLASS. "lcl_cargo_plane DEFINITION *-------------------------------------------------* * CLASS lcl_cargo_plane IMPLEMENTATION *-------------------------------------------------* CLASS lcl_cargo_plane IMPLEMENTATION. ... ENDCLASS. "lcl_cargo_plane IMPLEMENTATION *-------------------------------------------------* * CLASS lcl_passenger_plane DEFINITION *-------------------------------------------------* CLASS lcl_passenger_plane DEFINITION INHERITING FROM lcl_airplane. ... ENDCLASS. "lcl_passenger_plane DEFINITION *-------------------------------------------------* * CLASS lcl_passenger_plane IMPLEMENTATION *-------------------------------------------------* CLASS lcl_passenger_plane IMPLEMENTATION. ... ENDCLASS. "lcl_passenger_plane IMPLEMENTATION *-------------------------------------------------* * CLASS lcl_carrier DEFINITION *-------------------------------------------------* CLASS lcl_carrier DEFINITION. ... ENDCLASS. "lcl_carrier DEFINITION *-------------------------------------------------* * CLASS lcl_carrier IMPLEMENTATION *-------------------------------------------------* CLASS lcl_carrier IMPLEMENTATION. METHOD constructor. mv_name = iv_name. SET HANDLER on_airplane_created FOR ALL INSTANCES. RAISE EVENT lif_partner~partner_created. ENDMETHOD. "constructor METHOD lif_partner~display_partner. display_attributes( ). ENDMETHOD. "lif_partners~display_partner METHOD on_airplane_created. APPEND sender TO mt_airplanes. ENDMETHOD. "on_airplane_created METHOD display_attributes.
© Copyright . Reservados todos los derechos.
247
Capítulo 5: Eventos orientados a objetos
... ENDMETHOD. "display_attributes METHOD display_airplanes. ... ENDMETHOD. "display_airplanes ENDCLASS.
"lcl_carrier IMPLEMENTATION
Solución: programa principal SAPBC401_EVE_S2 REPORT sapbc401_eve_s2. TYPE-POOLS icon. INCLUDE bc401_eve_s2_agency. INCLUDE bc401_eve_s2_carrier. INCLUDE bc401_eve_s2_rental. DATA: go_vehicle TYPE REF TO lcl_vehicle, go_truck TYPE REF TO lcl_truck, go_bus TYPE REF TO lcl_bus, go_rental TYPE REF TO lcl_rental, go_passenger TYPE REF TO lcl_passenger_plane, go_cargo TYPE REF TO lcl_cargo_plane, go_carrier TYPE REF TO lcl_carrier, go_agency TYPE REF TO lcl_travel_agency. START-OF-SELECTION. ******************* ******* create travel_agency CREATE OBJECT go_agency EXPORTING iv_name = 'Travel&Smile Travel'. ******* create rental CREATE OBJECT go_rental EXPORTING iv_name = 'Happy Car Rental'. * go_agency->add_partner( go_rental ). ******* create truck CREATE OBJECT go_truck EXPORTING iv_make = 'MAN' iv_cargo = 45. ******* create truck CREATE OBJECT go_bus EXPORTING iv_name = 'Mercedes' iv_passengers = 80. ******* create truck CREATE OBJECT go_truck EXPORTING iv_make = 'VOLVO'
248
© Copyright . Reservados todos los derechos.
Lección: Implementación de eventos en interfaces locales
iv_cargo = 48. ***** Create Carrier CREATE OBJECT go_carrier EXPORTING iv_name = 'Smile&Fly-Travel'. * go_agency->add_partner( go_rental ). ***** Passenger Plane CREATE OBJECT go_passenger EXPORTING iv_name = 'LH BERLIN' iv_planetype = '747-400' iv_seats = 345 EXCEPTIONS wrong_planetype = 1. IF sy-subrc <> 0. WRITE: / icon_failure AS ICON, 'Wrong plane type'. ENDIF. ***** cargo Plane CREATE OBJECT go_cargo EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' iv_cargo = 533 EXCEPTIONS wrong_planetype = 1. IF sy-subrc <> 0. WRITE: / icon_failure AS ICON, 'Wrong plane type'. ENDIF. ******* show attributes of all partners of travel_agency go_agency->display_attributes( ).
© Copyright . Reservados todos los derechos.
249
Capítulo 5: Eventos orientados a objetos
RESUMEN DE LA LECCIÓN Ahora podrá: ●
250
Implementar eventos en las interfaces locales
© Copyright . Reservados todos los derechos.
Capítulo 5 Evaluación de la formación
1. ¿Cuáles de los siguientes no se definen como componentes de interfaz? Seleccione la respuesta correcta. X
A Atributos
X
B Métodos
X
C Eventos
X
D Clases
2. De las siguientes sentencias, ¿cuál se utiliza para desencadenar los eventos? Seleccione la respuesta correcta. X
A CLASS-EVENTS
X
B RAISE EVENT
X
C EVENTS
X
D FOR EVENTS
3. Puede desencadenar eventos estáticos en los métodos estáticos. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
4. De las siguientes opciones, ¿cuál especifica la definición del método de programa de control? Seleccione la respuesta correcta. X
A qué método reaccionará a cada evento y clase
X
B qué instancia(s) ejecutarán la reacción
© Copyright . Reservados todos los derechos.
251
Capítulo 5: Evaluación de la formación
5. Los eventos se registran mediante la sentencia SET HANDLER. La inscripción sólo está activa durante el tiempo de ejecución del programa. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
6. ¿Qué visibilidad del evento garantiza que solo pueda tratarse en la clase misma y sus subclases? Seleccione la respuesta correcta.
252
X
A Público
X
B Protegido
X
C Privado
© Copyright . Reservados todos los derechos.
Capítulo 5 Respuestas a la Evaluación de la formación
1. ¿Cuáles de los siguientes no se definen como componentes de interfaz? Seleccione la respuesta correcta. X
A Atributos
X
B Métodos
X
C Eventos
X
D Clases
2. De las siguientes sentencias, ¿cuál se utiliza para desencadenar los eventos? Seleccione la respuesta correcta. X
A CLASS-EVENTS
X
B RAISE EVENT
X
C EVENTS
X
D FOR EVENTS
3. Puede desencadenar eventos estáticos en los métodos estáticos. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
4. De las siguientes opciones, ¿cuál especifica la definición del método de programa de control? Seleccione la respuesta correcta. X
A qué método reaccionará a cada evento y clase
X
B qué instancia(s) ejecutarán la reacción
© Copyright . Reservados todos los derechos.
253
Capítulo 5: Respuestas a la Evaluación de la formación
5. Los eventos se registran mediante la sentencia SET HANDLER. La inscripción sólo está activa durante el tiempo de ejecución del programa. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
6. ¿Qué visibilidad del evento garantiza que solo pueda tratarse en la clase misma y sus subclases? Seleccione la respuesta correcta.
254
X
A Público
X
B Protegido
X
C Privado
© Copyright . Reservados todos los derechos.
CAPÍTULO 6
Objetos de Repository orientados a objetos
Lección 1 Crear clases globales Ejercicio 16: Implementar una clase global
256 265
Lección 2 Definición e implementación de las interfaces globales Ejercicio 17: Importar e implementar una interfaz global
272 277
Lección 3 Implementación de la herencia en clases globales Ejercicio 18: Implementar la herencia en las clases globales
286 293
OBJETIVOS DEL CAPÍTULO ●
Crear clases globales
●
Probar clases globales
●
Usar clases globales
●
Definir e implementar interfaces globales
●
Importar clases e interfaces locales
●
Generar diagramas de UML para clases globales
●
Implementar la herencia en las clases globales
●
Tratar las clases globales
●
Usar el asistente de refactoring.
© Copyright . Reservados todos los derechos.
255
Capítulo 6 Lección 1 Crear clases globales
RESUMEN DE LA LECCIÓN En este módulo se explica cómo crear clases globales. Ejemplo empresarial Como desarrollador, debe crear una clase ABAP global para aviones a la cual puede acceder mediante los demás objetos ABAP en el sistema SAP. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de las clases globales
●
Una buena comprensión de cómo probar y usar las clases globales
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Crear clases globales
●
Probar clases globales
●
Usar clases globales
Definición de clases globales Nota: En el siguiente módulo se utilizarán numerosas capturas e ilustraciones de pantalla. Tenga en cuenta que el aspecto de algunos de los iconos o menús depende del release. Al igual que las subrutinas, las clases o las interfaces locales solo pueden utilizarse dentro del programa en el que están definidas e implementadas. La sentencia CLASS es una sentencia declarativa local del programa. Tal como la sentencia TYPES define tipos de datos locales, la sentencia CLASS define tipos de objeto locales. Por otro lado, las clases globales o las interfaces globales son objetos de repository individuales con todas las características estándar de ABAP Workbench, como la integración activa, la creación de versiones, el sistema de transporte, etc. La convención de área de nombres, por ejemplo: Y*, Z* o un área de nombres de cliente especial, es la misma que la utilizada para el área de nombres de otros objetos de repository. Por ello, está disponible una herramienta especial de actualización en el Workbench ABAP que se denomina Generador de clases. Si no está seguro acerca de una determinada característica en el Generador de clases, se recomienda utilizar Quickinfo. Es el texto explicativo que aparece cuando coloca el cursor por encima de un icono y lo deja allí por un poco tiempo.
256
© Copyright . Reservados todos los derechos.
Lección: Crear clases globales
Creación de clases globales en el Object Navigator
Figura 103: Creación de clases globales en el Object Navigator
Al igual que con otros objetos de repository, el área de navegación separada del Object Navigator lo convierte en la herramienta de desarrollo ideal para todos los objetos de repository. La manera más fácil de crear una nueva clase global es utilizar el menú contextual en el área de navegación. Para ello, primero seleccione el nodo de paquete o seleccione el nodo de clase dentro de un paquete. Aparece una ventana de diálogo que le ofrece algunas elecciones para la clase nueva. Seleccione la clase ABAP habitual. La clase global o la interfaz global se visualizarán en la tabla del Generador de clases del área de edición del Object Navigator.
© Copyright . Reservados todos los derechos.
257
Capítulo 6: Objetos de Repository orientados a objetos
Definición de atributos en una clase global
Figura 104: Definición de atributos
Seleccione la etiqueta Atributos para abrir la lista de todas las definiciones de atributo de la clase. En este lugar también puede definir nuevos atributos. Puede utilizar la Ayuda para entradas al definir los tipos de atributos. Utilice descripciones cortas y con sentido.
Crear métodos en la clase global
Figura 105: Definición de métodos
258
© Copyright . Reservados todos los derechos.
Lección: Crear clases globales
Seleccione la etiqueta Métodos para abrir una lista de todas las definiciones de método de la clase. Puede definir nuevos métodos en ese lugar. Utilice descripciones cortas y con sentido. Hay ventanas de editor diferentes para los parámetros de método (también se conoce como firma del método) y la implementación. Seleccione el pulsador Constructor para definir un constructor de instancia. El sistema selecciona de manera automática el nombre del constructor.
Consejo: Los métodos pueden transportarse por separado, porque cada implementación se almacena en un include ABAP propio. Definición de parámetros de método
Figura 106: Definición de firmas de método
En la lista de métodos, seleccione un método y el pulsador Parámetro para ir a la actualización de firmas. Puede definir nuevos parámetros formales en este lugar. Puede utilizar la Ayuda para entradas cuando define los tipos de parámetros. Utilice descripciones cortas y con sentido. Las exploración de firmas es posible con la ayuda de los pulsadores Método anterior o Métodos siguientes. Seleccione el pulsador Métodos para volver a la lista de métodos.
© Copyright . Reservados todos los derechos.
259
Capítulo 6: Objetos de Repository orientados a objetos
Implementación de métodos
Figura 107: Implementación de métodos
En la lista de métodos, haga doble clic sobre un método para seleccionarlo. O bien, seleccione el pulsador de código fuente para acceder a la actualización del texto fuente si ya seleccionó un método. Puede implementar los métodos en este lugar.
Consejo: Seleccione el pulsador relevante para visualizar la firma del método.
260
© Copyright . Reservados todos los derechos.
Lección: Crear clases globales
Visualización de la definición de método
Figura 108: Visualización de la definición de método
Seleccione Pasar a → Definición de método para modificar los atributos de su método durante la implementación. O bien, puede definir un método de programa de control en la pestaña Atributos en la ventana de diálogo. Definición de componentes mediante el área de navegación
Figura 109: Definición de componentes mediante el área de navegación
Puede definir atributos, métodos o eventos en el menú contextual del área de navegación del Object Navigator. Las propiedades se actualizarán en una ventana de diálogo, y no en la tabla.
© Copyright . Reservados todos los derechos.
261
Capítulo 6: Objetos de Repository orientados a objetos
Consejo: Seleccione Clase → Imprimir o Método → Imprimir para imprimir la selección del texto fuente.
Entorno de test del generador de clases
Figura 110: El entorno de test del generador de clases
Puede probar las clases globales activas seleccionando el acceso vía menús Clase → Ejecutar → En entorno de test y haciendo clic en el botón correspondiente de la barra de tareas o presionando F8. Es posible acceder directamente a los atributos y métodos estáticos en el entorno de test. Es posible acceder a los atributos y métodos de instancia únicamente después de la creación de instancias. Puede crear una instancia con el pulsador Crear instancia. El sistema enumera únicamente los componentes públicos. Es posible realizar test de los métodos mediante el icono Ejecutar método. A continuación se detallan los pasos para desencadenar eventos en una clase: 1. Seleccione un evento. 2. Seleccione el Programa de control para registrar un método estándar para el evento. 3. Llame un método en el que se haya implementado el desencadenador de eventos. El evento desencadenado y todos los parámetros actuales exportados se visualizarán en una lista.
262
© Copyright . Reservados todos los derechos.
Lección: Crear clases globales
Uso de clases globales en el Editor ABAP
Figura 111: Separación de áreas de navegación y tratamiento en el Object Navigator
Como otros objetos de Repository, las clases y las interfaces globales se añaden al área de navegación del object navigator. De esta manera, las ventajas expuestas también se aplican a las clases e interfaces globales. Instanciación de objeto mediante la función de arrastrar y soltar
Figura 112: Instanciación de objeto mediante la función de arrastrar y soltar
En el área de navegación, seleccione un nombre de clase y arrástrelo hacia el área de tratamiento manteniendo pulsado el botón izquierdo del ratón. De este modo, crea un sentencia CREATE OBJECT. A continuación añada la variable de referencia y los parámetros actuales, si conviene, a la sentencia.
© Copyright . Reservados todos los derechos.
263
Capítulo 6: Objetos de Repository orientados a objetos
O bien, puede seleccionar el pulsador Patrón. Puede encontrar la sentencia CREATE OBJECT seleccionando ABAP Objects Pattern. Puede generar la sentencia mediante la Ayuda para entradas. Llamadas de método mediante la función de arrastrar y soltar
Figura 113: Llamadas de método mediante la función de arrastrar y soltar
En el área de navegación, seleccione un nombre de método y arrástrelo hacia el área de tratamiento manteniendo pulsado el botón izquierdo del ratón. De este modo, crea un sentencia CREATE METHOD. A continuación añada la variable de referencia y los parámetros actuales, si conviene, a la sentencia. O bien, también puede seleccionar el pulsador Patrón. La sentencia CALL METHOD se encuentra bajo ABAP Objects Pattern. Puede generar la sentencia mediante la Ayuda para entradas.
Nota: Para generar patrones, a partir de SAP Netweaver 7.0, puede habilitar el estilo de escritura funcional moderno para las llamadas de método. Seleccione Utilidades → Parametrizaciones → Patrón y marque la casilla de selección Estilo de escritura funcional para método de llamada.
264
© Copyright . Reservados todos los derechos.
Capítulo 6 Ejercicio 16 Implementar una clase global
Ejemplo empresarial Desea crear una clase global para representar hoteles. Modelo: SAPBC401_EVE_S2 (programa principal) Solución: SAPBC401_GCL_S1 (programa principal) CL_HOTEL (clase global) Tarea 1 Cree una clase global para hoteles. 1. Cree la clase global ZCL_##_HOTEL (## es su número de grupo de dos cifras). 2. Defina los siguientes atributos en la clase: Nombre de atributo
Tipo
Características
C_POS_1
I
Como constante privada con valor 30.
MV_NAME
del tipo STRING
Como un atributo de instancia privado.
MV_BEDS
del tipo I
Como un atributo de instancia privado.
GV_N_O_HOTELS
del tipo I
Como un atributo estático privado.
Actualice los textos breves. 3. Defina los siguientes métodos en la clase: Nombre de método
Características del método
CONSTRUCTOR
Constructor de instancia para parametrizar los atributos privados con los parámetros de importación IV_NAME y IV_BEDS
DISPLAY_ATTRIBUTES
Método de instancia para visualizar atributos en una lista ABAP
© Copyright . Reservados todos los derechos.
265
Capítulo 6: Objetos de Repository orientados a objetos
Nombre de método
Características del método
DISPLAY_N_O_HOTELS
Método estático para visualizar el número de instancias de hotel creadas en una lista ABAP
4. Utilice la constante definida antes de alinear el resultado de los valores en una columna. Actualice los textos breves.
Tarea 2 Verifique su trabajo. 1. Active su clase. 2. Pruebe su clase en el entorno de test del Generador de clases. Tarea 3 Cree una instancia de su clase global para hoteles en su programa principal. 1. Complete el programa ZBC401_##_MAIN (donde ## es el número de grupo de dos cifras) o copie el programa modelo. 2. Defina una variable de referencia, especifique su clase de hotel global como el tipo y cree una instancia. 3. Si no ha realizado el ejercicio opcional, en el que añade los interlocutores comerciales a la agencia de viajes mediante el tratamiento de eventos, llame el método ADD_PARTNER para el hotel. 4. ¿Por qué aún no puede integrarse el hotel a la lista de la agencia de viajes de interlocutores comerciales?
5. ¿Puede implementarse la interfaz local LIF_PARTNER en la clase global para hoteles?
266
© Copyright . Reservados todos los derechos.
Capítulo 6 Solución 16 Implementar una clase global
Ejemplo empresarial Desea crear una clase global para representar hoteles. Modelo: SAPBC401_EVE_S2 (programa principal) Solución: SAPBC401_GCL_S1 (programa principal) CL_HOTEL (clase global) Tarea 1 Cree una clase global para hoteles. 1. Cree la clase global ZCL_##_HOTEL (## es su número de grupo de dos cifras). a) Siga los procesos tal como se indica en la sección relevante de esta unidad. 2. Defina los siguientes atributos en la clase: Nombre de atributo
Tipo
Características
C_POS_1
I
Como constante privada con valor 30.
MV_NAME
del tipo STRING
Como un atributo de instancia privado.
MV_BEDS
del tipo I
Como un atributo de instancia privado.
GV_N_O_HOTELS
del tipo I
Como un atributo estático privado.
Actualice los textos breves. a) Siga los procesos tal como se indica en la sección relevante de esta unidad. 3. Defina los siguientes métodos en la clase: Nombre de método
Características del método
CONSTRUCTOR
Constructor de instancia para parametrizar los atributos privados con los parámetros de importación IV_NAME y IV_BEDS
DISPLAY_ATTRIBUTES
Método de instancia para visualizar atributos en una lista ABAP
© Copyright . Reservados todos los derechos.
267
Capítulo 6: Objetos de Repository orientados a objetos
Nombre de método
Características del método
DISPLAY_N_O_HOTELS
Método estático para visualizar el número de instancias de hotel creadas en una lista ABAP
4. Utilice la constante definida antes de alinear el resultado de los valores en una columna. Actualice los textos breves. a) Siga los procesos tal como se indica en la sección relevante de esta unidad.
Tarea 2 Verifique su trabajo. 1. Active su clase. a) Realice este paso de la forma habitual. Encontrará información adicional en la biblioteca SAP. 2. Pruebe su clase en el entorno de test del Generador de clases. a) Siga los procesos tal como se indica en la sección relevante de esta unidad. Tarea 3 Cree una instancia de su clase global para hoteles en su programa principal. 1. Complete el programa ZBC401_##_MAIN (donde ## es el número de grupo de dos cifras) o copie el programa modelo. a) Realice este paso de la forma habitual. Para más información, consulte la biblioteca SAP. 2. Defina una variable de referencia, especifique su clase de hotel global como el tipo y cree una instancia. a) Véase el extracto del código fuente de la solución modelo. 3. Si no ha realizado el ejercicio opcional, en el que añade los interlocutores comerciales a la agencia de viajes mediante el tratamiento de eventos, llame el método ADD_PARTNER para el hotel. a) Siga los mismos pasos que siguió para la compañía aérea y la compañía de alquiler de vehículos. 4. ¿Por qué aún no puede integrarse el hotel a la lista de la agencia de viajes de interlocutores comerciales? La clase global para hoteles no implementa la interfaz que utiliza la clase de agencia de viajes. 5.
268
© Copyright . Reservados todos los derechos.
Lección: Crear clases globales
¿Puede implementarse la interfaz local LIF_PARTNER en la clase global para hoteles? No, las clases globales sólo pueden implementar interfaces globales. Por lo tanto, deberá reemplazarse la interfaz local por una global. Esto se realiza en el siguientes ejercicio. a) Modele la solución de la siguiente manera. Solución: programa principal SAPBC401_GCL_S1 REPORT
sapbc401_gcl_s1.
TYPE-POOLS icon. INCLUDE bc401_gcl_s1_agency. INCLUDE bc401_gcl_s1_carrier. INCLUDE bc401_gcl_s1_rental. DATA: go_hotel go_vehicle go_truck go_bus go_rental go_passenger go_cargo go_carrier go_agency
TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE
REF REF REF REF REF REF REF REF REF
TO TO TO TO TO TO TO TO TO
cl_hotel, lcl_vehicle, lcl_truck, lcl_bus, lcl_rental, lcl_passenger_plane, lcl_cargo_plane, lcl_carrier, lcl_travel_agency.
START-OF-SELECTION. ******************* ******* create travel_agency CREATE OBJECT go_agency EXPORTING iv_name = 'Travel&Smile Travel'. ******* create hotel CREATE OBJECT go_hotel EXPORTING iv_name = 'Sleep Well Hotel' iv_beds = 345. * hotel not added to partner list * does not implement interface * go_agency->add_partner( go_hotel ) ******* create rental CREATE OBJECT go_rental EXPORTING iv_name = 'Happy Car Rental'. * go_agency->add_partner( go_rental ). ******* create truck CREATE OBJECT go_truck EXPORTING iv_make = 'MAN' iv_cargo = 45. ******* create truck CREATE OBJECT go_bus
© Copyright . Reservados todos los derechos.
269
Capítulo 6: Objetos de Repository orientados a objetos
EXPORTING iv_make = 'Mercedes' iv_passengers = 80. ******* create truck CREATE OBJECT go_truck EXPORTING iv_make = 'VOLVO' iv_cargo = 48. ***** Create Carrier CREATE OBJECT go_carrier EXPORTING iv_name = 'Smile&Fly-Travel'. * go_agency->add_partner( go_rental ). ***** Passenger Plane CREATE OBJECT go_passenger EXPORTING iv_name = 'LH BERLIN' iv_planetype = '747-400' iv_seats = 345 EXCEPTIONS wrong_planetype = 1. IF sy-subrc <> 0. WRITE: / icon_failure AS ICON, 'Wrong plane type'. ENDIF. ***** cargo Plane CREATE OBJECT go_cargo EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' iv_cargo = 533 EXCEPTIONS wrong_planetype = 1. IF sy-subrc <> 0. WRITE: / icon_failure AS ICON, 'Wrong plane type'. ENDIF. ***** show attributes of all partners of travel_agency go_agency->display_attributes( ).
270
© Copyright . Reservados todos los derechos.
Lección: Crear clases globales
RESUMEN DE LA LECCIÓN Ahora podrá: ●
Crear clases globales
●
Probar clases globales
●
Usar clases globales
© Copyright . Reservados todos los derechos.
271
Capítulo 6 Lección 2 Definición e implementación de las interfaces globales
RESUMEN DE LA LECCIÓN Este módulo explica cómo definir e implementar las interfaces globales. Ejemplo empresarial Como desarrollador, necesita crear una interfaz global de manera que otros desarrolladores de su organización puedan usar la misma interfaz e implementarla con sus propios medios en sus clases. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de cómo definir e implementar interfaces globales
●
Una buena comprensión de cómo importar clases e interfaces locales
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Definir e implementar interfaces globales
●
Importar clases e interfaces locales
Definición de interfaces globales
Figura 114: Definición de interfaces globales
272
© Copyright . Reservados todos los derechos.
Lección: Definición e implementación de las interfaces globales
Crea las interfaces globales como crea las clases globales. Haga clic con el botón derecho en el Object Navigator. La convención para fijar nombres es IF_ para interfaces de SAP y ZIF_ o YIF_ para interfaces definidas por el usuario.
Implementación de interfaces globales
Figura 115: Inclusión de interfaces globales
Si desea incluir la interfaz global en la clase global, debe introducir el nombre de la interfaz en la etiqueta Interfaces. Una vez hecho esto, aparecerán automáticamente todos los componentes de la interfaz en las fichas relevantes, según la convención para fijar nombres con el operador de resolución de interfaz. En el ejemplo, se incorpora la interfaz global ZIF_00_PARTNER que contiene el método DISPLAY_PARTNER. Haga doble clic en el nombre del método para implementarlo.
© Copyright . Reservados todos los derechos.
273
Capítulo 6: Objetos de Repository orientados a objetos
Importación de clases e interfaces locales
Figura 116: Importación de una clase de programa local
El siguiente procedimiento es una manera fácil de realizar copias globales de clases e interfaces locales.
Consejo: La función de copiar las clases locales a las clases globales no puede usarse desde el OBJECT-NAVIGATOR.
Para importar clases e interfaces locales Estos son los pasos para importar clases locales e interfaces: 1. En la pantalla SAP Easy Access Menu, seleccione Herramientas → Workbench ABAP → Desarrollo → Generador de clases o llame la transacción SE24. 2. En la pantalla Generador de clases: En la pantalla inicial , seleccione Tipo de objeto → Importar → Clases locales en el programa. 3. En la ventana de diálogo Importar del programa, introduzca el nombre del programa principal y, si las clases y las interfaces locales fueron definidas dentro de los programas de Include, marque la casilla de selección Expandir Include. 4. Seleccione el pulsador Visualizar clases/interfaces. 5. Introduzca nombres para las clases e interfaces globales que desee crear. 6. Tenga en cuenta el área de nombres de cliente, si corresponde. 7. Seleccione las clases e interfaces globales que desee crear y haga clic en el pulsador Importar.
274
© Copyright . Reservados todos los derechos.
Lección: Definición e implementación de las interfaces globales
© Copyright . Reservados todos los derechos.
275
Capítulo 6: Objetos de Repository orientados a objetos
276
© Copyright . Reservados todos los derechos.
Capítulo 6 Ejercicio 17 Importar e implementar una interfaz global
Ejemplo empresarial Añada un hotel como nuevo interlocutor comercial en su programa de gestión de interlocutores comerciales de una agencia de viajes. Modelo: SAPBC401_GCL_S1 (programa) CL_HOTEL (clase global) Solución: SAPBC401_GCL_S2 (programa) CL_HOTEL2 (clase global) IF_PARTNER (interfaz global) Tarea 1 Cree una interfaz global para el acceso generalizado a instancias de interlocutor comercial. 1. Si conviene, cambie el nombre de interfaz en su diagrama UML por ZIF_##_PARTNERS. (## es su número de grupo de dos cifras). 2. Cree la interfaz global ZIF_##_PARTNER. Defina el método de instancia DISPLAY_PARTNER en su interfaz global. Si la interfaz local contiene el evento PARTNER_CREATED, defina el evento en la interfaz global. Consejo: En lugar de crear la interfaz global manualmente, puede importar la interfaz local desde su programa ZBC401_##_MAIN o desde el programa de modelo.
Tarea 2 Reemplace la interfaz local en su programa principal con la interfaz global. 1. Complete el programa ZBC401_##_MAIN (donde ## es el número de grupo de dos cifras) o copie el programa modelo. 2. Elimine completamente la definición de interfaz local. 3. Adapte todos los lugares donde se utilizó la interfaz local para que se utilice e implemente la interfaz global.
© Copyright . Reservados todos los derechos.
277
Capítulo 6: Objetos de Repository orientados a objetos
Consejo: Use la función Encontrar/Reemplazar del Editor ABAP para escribir menos.
Tarea 3 Trate su clase de hotel para implementar la interfaz y pruebe su programa. 1. Complete la clase global ZCL_##_HOTEL (donde ## es el número de grupo de dos cifras) o copie la clase modelo. 2. En el programa principal, reemplace la referencia de la clase modelo con una referencia de su propia clase. 3. Si es necesario, añada la clase ZCL_##_HOTEL a su diagrama UML. La clase ZCL_##_HOTEL implementa el método de interfaz DISPLAY_PARTNER y desencadena el evento de instancia PARTNER_CREATED. Dibuje las relaciones en su diagrama. 4. Declare la interfaz como una interfaz implementada en su clase de hotel. 5. Implemente el método de interfaz para que se llame el método de instancia DISPLAY_ATTRIBUTES del hotel. 6. Active la clase global y su programa. Ejecute su programa. Si lo ha hecho todo correctamente, los atributos de hotel deberían visualizarse ahora en la lista. Si los atributos del hotel no aparecen en la lista, depure su programa y analice el origen del error.
278
© Copyright . Reservados todos los derechos.
Capítulo 6 Solución 17 Importar e implementar una interfaz global
Ejemplo empresarial Añada un hotel como nuevo interlocutor comercial en su programa de gestión de interlocutores comerciales de una agencia de viajes. Modelo: SAPBC401_GCL_S1 (programa) CL_HOTEL (clase global) Solución: SAPBC401_GCL_S2 (programa) CL_HOTEL2 (clase global) IF_PARTNER (interfaz global) Tarea 1 Cree una interfaz global para el acceso generalizado a instancias de interlocutor comercial. 1. Si conviene, cambie el nombre de interfaz en su diagrama UML por ZIF_##_PARTNERS. (## es su número de grupo de dos cifras). a) Hable con su instructor si tiene cualquier duda. 2. Cree la interfaz global ZIF_##_PARTNER. Defina el método de instancia DISPLAY_PARTNER en su interfaz global. Si la interfaz local contiene el evento PARTNER_CREATED, defina el evento en la interfaz global. Consejo: En lugar de crear la interfaz global manualmente, puede importar la interfaz local desde su programa ZBC401_##_MAIN o desde el programa de modelo. a) Siga los procesos tal como se indica en la sección relevante de esta unidad. Hable con su instructor si tiene cualquier duda. Tarea 2 Reemplace la interfaz local en su programa principal con la interfaz global. 1. Complete el programa ZBC401_##_MAIN (donde ## es el número de grupo de dos cifras) o copie el programa modelo. a) Realice este paso de la forma habitual. Para más información, consulte la biblioteca SAP. 2. Elimine completamente la definición de interfaz local.
© Copyright . Reservados todos los derechos.
279
Capítulo 6: Objetos de Repository orientados a objetos
a) Véase el extracto del código fuente de la solución modelo. 3. Adapte todos los lugares donde se utilizó la interfaz local para que se utilice e implemente la interfaz global. Consejo: Use la función Encontrar/Reemplazar del Editor ABAP para escribir menos.
a) Véase el extracto del código fuente de la solución modelo. Tarea 3 Trate su clase de hotel para implementar la interfaz y pruebe su programa. 1. Complete la clase global ZCL_##_HOTEL (donde ## es el número de grupo de dos cifras) o copie la clase modelo. a) Realice este paso de la forma habitual. Para más información, consulte la biblioteca SAP. 2. En el programa principal, reemplace la referencia de la clase modelo con una referencia de su propia clase. a) Véase el extracto del código fuente de la solución modelo. 3. Si es necesario, añada la clase ZCL_##_HOTEL a su diagrama UML. La clase ZCL_##_HOTEL implementa el método de interfaz DISPLAY_PARTNER y desencadena el evento de instancia PARTNER_CREATED. Dibuje las relaciones en su diagrama. a) Hable con su instructor si tiene cualquier duda. 4. Declare la interfaz como una interfaz implementada en su clase de hotel. a) Siga los procesos tal como se indica en la sección relevante de esta unidad. 5. Implemente el método de interfaz para que se llame el método de instancia DISPLAY_ATTRIBUTES del hotel. a) Siga los procesos tal como se indica en la sección relevante de esta unidad. 6. Active la clase global y su programa. Ejecute su programa. Si lo ha hecho todo correctamente, los atributos de hotel deberían visualizarse ahora en la lista. Si los atributos del hotel no aparecen en la lista, depure su programa y analice el origen del error. a) Realice este paso de la forma habitual. Para más información, consulte la biblioteca SAP. Include BC401_GCL_S2_AGENCY *------------------------------------------------* * INTERFACE lif_partners *------------------------------------------------* *INTERFACE lif_partner. * METHODS: * display_partner. * EVENTS: * partner_created.
280
© Copyright . Reservados todos los derechos.
Lección: Definición e implementación de las interfaces globales
*ENDINTERFACE.
"lif_partners
*------------------------------------------------* * CLASS lcl_travel_agency DEFINITION *------------------------------------------------* CLASS lcl_travel_agency DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING iv_name TYPE string, display_agency_partners, display_attributes. PRIVATE SECTION. DATA: mv_name TYPE string, mt_partners TYPE TABLE OF REF TO if_partner. METHODS: on_partner_created FOR EVENT partner_created OF if_partner IMPORTING sender. ENDCLASS.
"lcl_travel_agency DEFINITION
*------------------------------------------------* * CLASS lcl_travel_agency IMPLEMENTATION *------------------------------------------------* CLASS lcl_travel_agency IMPLEMENTATION. METHOD display_attributes. WRITE: / icon_private_files AS ICON, 'Travel Agency:'(007), mv_name. SKIP. display_agency_partners( ). ENDMETHOD. "display_attributes METHOD display_agency_partners. DATA: lo_partner TYPE REF TO if_partner. WRITE 'Here are the partners of the travel agency:'(008). ULINE. LOOP AT mt_partners INTO lo_partner. lo_partner->display_partner( ). ENDLOOP. ENDMETHOD.
"display_agency_partners
METHOD constructor. mv_name = iv_name. SET HANDLER on_partner_created FOR ALL INSTANCES. ENDMETHOD. "constructor METHOD on_partner_created. APPEND sender TO mt_partners. ENDMETHOD. "on_partner_created ENDCLASS.
"lcl_travel_agency IMPLEMENTATION
© Copyright . Reservados todos los derechos.
281
Capítulo 6: Objetos de Repository orientados a objetos
Include BC401_GCL_S2_CARRIER
... *---------------------------------------------------* * CLASS lcl_carrier DEFINITION *---------------------------------------------------* CLASS lcl_carrier DEFINITION. PUBLIC SECTION. INTERFACES if_partner. METHODS: constructor IMPORTING iv_name TYPE string, on_airplane_created FOR EVENT airplane_created OF lcl_airplane IMPORTING sender, display_attributes. PRIVATE SECTION. DATA: mv_name TYPE string, mt_airplanes TYPE TABLE OF REF TO lcl_airplane. METHODS: display_airplanes. ENDCLASS.
"lcl_carrier DEFINITION
*-------------------------------------------------* * CLASS lcl_carrier IMPLEMENTATION *-------------------------------------------------* CLASS lcl_carrier IMPLEMENTATION. METHOD constructor. mv_name = iv_name. SET HANDLER on_airplane_created FOR ALL INSTANCES. RAISE EVENT if_partner~partner_created. ENDMETHOD. "constructor METHOD if_partner~display_partner. display_attributes( ). ENDMETHOD. "if_partners~display_partner METHOD on_airplane_created. APPEND sender TO mt_airplanes. ENDMETHOD. "on_airplane_created METHOD display_attributes. SKIP 2. WRITE: icon_flight AS ICON, mv_name. ULINE. ULINE. display_airplanes( ). ENDMETHOD. "display_attributes METHOD display_airplanes. DATA: lo_plane TYPE REF TO lcl_airplane. LOOP AT mt_airplanes INTO lo_plane.
282
© Copyright . Reservados todos los derechos.
Lección: Definición e implementación de las interfaces globales
lo_plane->display_attributes( ). ENDLOOP. ENDMETHOD. "display_airplanes ENDCLASS.
"lcl_carrier IMPLEMENTATION
Programa de Include BC401_GCL_S2_RENTAL ... *---------------------------------------------------* * CLASS lcl_rental DEFINITION *---------------------------------------------------* CLASS lcl_rental DEFINITION. PUBLIC SECTION. INTERFACES: if_partner. METHODS: constructor IMPORTING iv_name TYPE string, on_vehicle_created FOR EVENT vehicle_created OF lcl_vehicle IMPORTING sender, display_attributes. PRIVATE SECTION. DATA: mv_name TYPE string, mt_vehicles TYPE TABLE OF REF TO lcl_vehicle. ENDCLASS. "lcl_rental DEFINITION *---------------------------------------------------* * CLASS lcl_rental IMPLEMENTATION *---------------------------------------------------* CLASS lcl_rental IMPLEMENTATION. METHOD if_partner~display_partner. display_attributes( ). ENDMETHOD. "if_partners~display_partner METHOD constructor. mv_name = iv_name. SET HANDLER on_vehicle_created FOR ALL INSTANCES. RAISE EVENT if_partner~partner_created. ENDMETHOD. "constructor METHOD on_vehicle_created. APPEND sender TO mt_vehicles. ENDMETHOD. "on_vehicle_created METHOD display_attributes. DATA: lo_vehicle TYPE REF TO lcl_vehicle. WRITE: / icon_transport_proposal AS ICON, mv_name. WRITE: / 'Here comes the vehicle list: '. ULINE. ULINE. LOOP AT mt_vehicles INTO lo_vehicle. lo_vehicle->display_attributes( ). ENDLOOP.
© Copyright . Reservados todos los derechos.
283
Capítulo 6: Objetos de Repository orientados a objetos
ENDMETHOD. ENDCLASS.
284
"display_attributes "lcl_rental IMPLEMENTATION
© Copyright . Reservados todos los derechos.
Lección: Definición e implementación de las interfaces globales
RESUMEN DE LA LECCIÓN Ahora podrá: ●
Definir e implementar interfaces globales
●
Importar clases e interfaces locales
© Copyright . Reservados todos los derechos.
285
Capítulo 6 Lección 3 Implementación de la herencia en clases globales
RESUMEN DE LA LECCIÓN Este módulo explica cómo generar diagramas UML con la herencia en las clases globales. Ejemplo empresarial Como desarrollador, necesita generar diagramas UML que lo ayudan a mantener un resumen de las clases globales y sus relaciones entre sí. Además, debe mejorar la implementación de su clase de hotel utilizando la herencia. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de cómo generar diagramas UML
●
Una buena comprensión de cómo tratar clases globales
●
Una buena comprensión de cómo usar el asistente de refactoring
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá:
286
●
Generar diagramas de UML para clases globales
●
Implementar la herencia en las clases globales
●
Tratar las clases globales
●
Usar el asistente de refactoring.
© Copyright . Reservados todos los derechos.
Lección: Implementación de la herencia en clases globales
La generación de diagramas de UML para las clases globales
Figura 117: Generación de un diagrama UML para paquete
A partir de SAP NetWeaver 7.0 Enhancement Package 2 (EhP2), el Generador de clases puede generar diagramas UML para la codificación existente. Esta función se limita a las clases globales y no se aplica a las locales. Sin embargo, los diagramas pueden incluir objetos del Diccionario ABAP. El gráfico muestra cómo iniciar la funcionalidad para completar el paquete. En una ventana emergente, puede añadir una selección de objetos y especificar qué detalles desea ver en el diagrama.
© Copyright . Reservados todos los derechos.
287
Capítulo 6: Objetos de Repository orientados a objetos
Definición de la herencia en las clases globales
Figura 118: Definición de una relación de herencia
Establezca las relaciones de herencia entre clases globales en la pestaña Propiedades. Seleccione el pulsador Clase superior para especificar una clase superior. En el ejemplo que se muestra en la figura, la subclase ZCL_CARGO_PLANE_00 hereda de la clase superior ZCL_AIRPLANE_00.
Redefinición de un método en una clase global
Figura 119: Cómo redefinir un método heredado
288
© Copyright . Reservados todos los derechos.
Lección: Implementación de la herencia en clases globales
Para redefinir un método heredado, seleccione el método relevante en la lista y seleccione el pulsador Redefinir. Como alternativa, puede utilizar el menú contextual en el área de navegación.
Nota: El aspecto de algunos de los iconos o menús depende del nivel del release. El icono que se utiliza para redefinir métodos es un ejemplo de esto.
Consejo: Para definir el constructor en la subclase, seleccione el pulsador CONSTRUCTOR en la barra de herramientas de la aplicación. El sistema le propondrá entonces transferir la firma del constructor de clase superior. Esto es útil cuando se desea crear el constructor de subclase. Puede añadir algunos parámetros aquí. De manera similar, aquí puede encontrar la llamada para la clase superior.
Definición de tipos locales en las clases globales
Figura 120: Definición de un tipo local
Puede definir tipos locales en clases globales. Las clases globales incluyen las clases locales. Técnicamente, no está definiendo una clase dentro de una clase, sino una clase que es local en el objeto de repository de la clase global. Todos los componentes de la clase global tienen acceso a estos tipos locales, pero están encapsulados si se intenta acceder a ellos desde el exterior. Esto también es válido para interfaces locales en clases globales. Para tratar las partes de implementación de estas clases locales, seleccione el pulsador Impl.
© Copyright . Reservados todos los derechos.
289
Capítulo 6: Objetos de Repository orientados a objetos
Visualizar los componentes de clases
Figura 121: Visualización estructurada de componentes heredados
Para mejorar la comprensión de los componentes de herencia e interfaz, puede fijar el indicador Agrupar por clases e interfaces en las Parametrizaciones específicas de usuario del generador de clases. El sistema visualizará entonces los componentes de la clase global en un grupo. Clasificación de la visualización de componentes de clases globales
Figura 122: Clasificación de la visualización de componentes de clases globales
Puede clasificar todos los componentes en cinco criterios de tres niveles. Seleccione el pulsador Clasificar para que se visualice la ventana de diálogo correspondiente. .
290
© Copyright . Reservados todos los derechos.
Lección: Implementación de la herencia en clases globales
El asistente de refactoring
Figura 123: Cómo trabajar con el asistente de refactoring
Las clases, las interfaces y las asociaciones entre ellas se manifiestan con su implementación ABAP. Puede adaptar y ampliar su implementación ABAP para los nuevos requisitos empresariales. Comúnmente dichas adaptaciones se denominan refactoring. El asistente de refactoring de SAP lo ayuda a adaptar fácilmente la jerarquía y las asociaciones de las clases e interfaces. Por ejemplo, puede utilizar el Asistente de refactoring para desplazar los componentes de una clase dentro de la jerarquía de herencia. Para obtener una lista completa de las funciones de esta herramienta, véase la biblioteca SAP. Trabajar con la herramienta es sencillo, ya que se basa en diálogos de arrastrar y soltar.
Consejo: El pulsador Info de herramienta abre el artículo de la biblioteca SAP sobre el Asistente de refactoring. Allí también podrá encontrar las descripciones sobre otras capacidades de la herramienta. Generalmente, el Asistente de refactoring no ajusta la implementación de los métodos. Después de usar el Asistente de refactoring, debe verificar y ajustar las implementaciones de método en forma manual. Para mover una definición de método de una clase global a una interfaz global Para mover una definición de método de una clase global a una interfaz global, realice lo siguiente: 1. Cambie al modo de tratamiento de una clase global que implementa una interfaz global. 2. Seleccione Herramientas → Asistente de refactoring. 3. En la estructura de árbol que aparece, abra la carpeta para el método que desee desplazar y para el destino que, en este caso, es la interfaz implementada.
© Copyright . Reservados todos los derechos.
291
Capítulo 6: Objetos de Repository orientados a objetos
4. Desplace el método a la interfaz. 5. Seleccione Grabar. 6. Si es necesario, adapte las sentencias llamando el método en el código fuente. 7. Active tanto la clase como la interfaz.
292
© Copyright . Reservados todos los derechos.
Capítulo 6 Ejercicio 18 Implementar la herencia en las clases globales
Ejemplo empresarial Use la herencia y trabaje con el Asistente de refactoring. Modelo: CL_HOTEL2 (clase global) Solución: CL_HOTEL3 (clase global) CL_HOUSE (clase global) Tarea 1 Defina una clase superior global para casas y deje que su clase de hotel herede de ella. 1. Si es necesario, añada la clase ZCL_##_HOUSE a su diagrama UML. (## es el número de grupo de dos cifras). La clase ZCL_##_HOUSE define el atributo MV_NAME y el método DISPLAY_ATTRIBUTES. La clase ZCL_##_HOTEL heredará de la clase ZCL_##_HOUSE. Dibuje las relaciones en su diagrama UML. 2. Cree la clase global ZCL_##_HOUSE y déjela vacía. Atención: Asegúrese de desmarcar la casilla de selección final. El significado de esta propiedad se explica en el siguiente módulo. 3. Defina una relación de herencia para que ZCL_##_HOUSE sea la clase superior y ZCL_##_HOTEL la subclase.
Tarea 2 Desplace los componentes generales de la clase ZCL_##_HOTEL a la clase superior. 1. Utilice el asistente de refactoring para desplazar la constante c_POS_1, el atributo MV_NAME, el constructor de instancia y el método DISPLAY_ATTRIBUTES a la clase ZCL_##_HOUSE. 2. Adapte la firma y la implementación del constructor de instancia en la clase superior. 3. Adapte la implementación del método DISPLAY_ATTRIBUTES en la clase superior. 4. Defina e implemente el constructor de instancia para la subclase.
© Copyright . Reservados todos los derechos.
293
Capítulo 6: Objetos de Repository orientados a objetos
5. Redefina el método DISPLAY_ATTRIBUTES en la subclase. Consejo: Para que la constante C_POS_1 esté disponible en la implementación de DISPLAY_ATTRIBUTES de la subclase, debe modificar su visibilidad a protegido. 6. Observe la ejecución del programa en el ABAP Debugger.
294
© Copyright . Reservados todos los derechos.
Capítulo 6 Solución 18 Implementar la herencia en las clases globales
Ejemplo empresarial Use la herencia y trabaje con el Asistente de refactoring. Modelo: CL_HOTEL2 (clase global) Solución: CL_HOTEL3 (clase global) CL_HOUSE (clase global) Tarea 1 Defina una clase superior global para casas y deje que su clase de hotel herede de ella. 1. Si es necesario, añada la clase ZCL_##_HOUSE a su diagrama UML. (## es el número de grupo de dos cifras). La clase ZCL_##_HOUSE define el atributo MV_NAME y el método DISPLAY_ATTRIBUTES. La clase ZCL_##_HOTEL heredará de la clase ZCL_##_HOUSE. Dibuje las relaciones en su diagrama UML. a) Hable con su instructor si tiene cualquier duda. 2. Cree la clase global ZCL_##_HOUSE y déjela vacía. Atención: Asegúrese de desmarcar la casilla de selección final. El significado de esta propiedad se explica en el siguiente módulo. a) Siga los procesos tal como se indica en la sección relevante de esta unidad. b) Hable con su instructor si tiene cualquier duda. 3. Defina una relación de herencia para que ZCL_##_HOUSE sea la clase superior y ZCL_##_HOTEL la subclase. a) Siga los procesos tal como se indica en la sección relevante de esta unidad. b) Hable con su instructor si tiene cualquier duda.
Tarea 2 Desplace los componentes generales de la clase ZCL_##_HOTEL a la clase superior.
© Copyright . Reservados todos los derechos.
295
Capítulo 6: Objetos de Repository orientados a objetos
1. Utilice el asistente de refactoring para desplazar la constante c_POS_1, el atributo MV_NAME, el constructor de instancia y el método DISPLAY_ATTRIBUTES a la clase ZCL_##_HOUSE. a) Siga los procesos tal como se indica en la sección relevante de esta unidad. b) Hable con su instructor si tiene cualquier duda. 2. Adapte la firma y la implementación del constructor de instancia en la clase superior. a) Siga los procesos tal como se indica en la sección relevante de esta unidad. b) Hable con su instructor si tiene cualquier duda. 3. Adapte la implementación del método DISPLAY_ATTRIBUTES en la clase superior. a) Siga los procesos tal como se indica en la sección relevante de esta unidad. b) Hable con su instructor si tiene cualquier duda. 4. Defina e implemente el constructor de instancia para la subclase. a) Siga los procesos tal como se indica en la sección relevante de esta unidad. b) Hable con su instructor si tiene cualquier duda. 5. Redefina el método DISPLAY_ATTRIBUTES en la subclase. Consejo: Para que la constante C_POS_1 esté disponible en la implementación de DISPLAY_ATTRIBUTES de la subclase, debe modificar su visibilidad a protegido. a) Siga los procesos tal como se indica en la sección relevante de esta unidad. b) Hable con su instructor si tiene cualquier duda. 6. Observe la ejecución del programa en el ABAP Debugger. a) Realice este paso de la forma habitual. Para más información, consulte la biblioteca SAP.
296
© Copyright . Reservados todos los derechos.
Lección: Implementación de la herencia en clases globales
RESUMEN DE LA LECCIÓN Ahora podrá: ●
Generar diagramas de UML para clases globales
●
Implementar la herencia en las clases globales
●
Tratar las clases globales
●
Usar el asistente de refactoring.
© Copyright . Reservados todos los derechos.
297
Capítulo 6: Objetos de Repository orientados a objetos
298
© Copyright . Reservados todos los derechos.
Capítulo 6 Evaluación de la formación
1. Solo puede utilizar las clases o interfaces locales dentro del mismo programa en el que están definidas e implementadas. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
2. De las siguientes opciones, ¿cuál se usa para probar el desencadenamiento de eventos en una clase del entorno de test? Seleccione las respuestas correctas. X
A Seleccione un evento.
X
B Elija un programa de control.
X
C Llame un método que desencadene el evento.
3. No puede pasar al estilo de escritura funcional moderno al generar llamadas de método en SAP NetWeaver (NW) Application Server (AS) 7.0. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
4. La convención para fijar nombres para las interfaces SAP es ZIF_ o YIF_. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
299
Capítulo 6: Evaluación de la formación
5. De las siguientes opciones, ¿cuál se utiliza para generar diagramas de UML para la codificación existente? Seleccione la respuesta correcta. X
A Class Builder
X
B Clase superior
X
C Métodos
X
D Interfaces
6. De los siguientes pulsadores, ¿cuál se utiliza para anular un método heredado? Seleccione la respuesta correcta. X
A CONSTRUCTOR
X
B Redefinir
X
C Implementación
7. Los tipos locales de la clase global se encapsulan y no es posible acceder a ellos desde el exterior. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
8. No puede utilizar el Asistente de refactoring para desplazar los componentes de una clase dentro de la jerarquía de herencia. Indique si esta afirmación es verdadera o falsa.
300
X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
Capítulo 6 Respuestas a la Evaluación de la formación
1. Solo puede utilizar las clases o interfaces locales dentro del mismo programa en el que están definidas e implementadas. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
2. De las siguientes opciones, ¿cuál se usa para probar el desencadenamiento de eventos en una clase del entorno de test? Seleccione las respuestas correctas. X
A Seleccione un evento.
X
B Elija un programa de control.
X
C Llame un método que desencadene el evento.
3. No puede pasar al estilo de escritura funcional moderno al generar llamadas de método en SAP NetWeaver (NW) Application Server (AS) 7.0. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
4. La convención para fijar nombres para las interfaces SAP es ZIF_ o YIF_. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
301
Capítulo 6: Respuestas a la Evaluación de la formación
5. De las siguientes opciones, ¿cuál se utiliza para generar diagramas de UML para la codificación existente? Seleccione la respuesta correcta. X
A Class Builder
X
B Clase superior
X
C Métodos
X
D Interfaces
6. De los siguientes pulsadores, ¿cuál se utiliza para anular un método heredado? Seleccione la respuesta correcta. X
A CONSTRUCTOR
X
B Redefinir
X
C Implementación
7. Los tipos locales de la clase global se encapsulan y no es posible acceder a ellos desde el exterior. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
8. No puede utilizar el Asistente de refactoring para desplazar los componentes de una clase dentro de la jerarquía de herencia. Indique si esta afirmación es verdadera o falsa.
302
X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
CAPÍTULO 7
Ejemplos orientados a objetos de ABAP
Lección 1 Implementación de ABAP List Viewer (ALV) Ejercicio 19: Implementar el control Grid ALV Ejercicio 20: Implementar una ventana emergente con el control Grid ALV
304 311 317
Lección 2 Implementación de add-ins empresariales (BAdI)
326
OBJETIVOS DEL CAPÍTULO ●
Implementar ABAP List Viewer (ALV) de manera simple.
●
Implementar el doble clic en la ABAP List Viewer (ALV)
●
Describir los Add-ins empresariales (BAdI)
© Copyright . Reservados todos los derechos.
303
Capítulo 7 Lección 1 Implementación de ABAP List Viewer (ALV)
RESUMEN DE LA LECCIÓN Este módulo le enseña a implementar el ABAP List Viewer (ALV). Ejemplo empresarial Necesita crear un informe con el control ALV Grid. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión del control ALV Grid
●
Una buena comprensión del uso de un ALV en un área de pantalla
●
Una buena comprensión de cómo se implementa ALV
●
●
●
Una buena comprensión de la implementación de un programa de control para el evento de doble clic Una buena comprensión de cómo se implementa un programa de control de evento para el control ALV Grid Una buena comprensión de cómo se implementa una ventana emergente con el control ALV Grid
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá:
304
●
Implementar ABAP List Viewer (ALV) de manera simple.
●
Implementar el doble clic en la ABAP List Viewer (ALV)
© Copyright . Reservados todos los derechos.
Lección: Implementación de ABAP List Viewer (ALV)
El control Grid ALV
Figura 124: El control Grid ALV
Los siguientes temas ilustran las posibles áreas de aplicación de la programación ABAP orientada a objetos y el uso de clases estándar de SAP. Por ejemplo, el control ALV Grid en el contexto de Control Framework y Add-Ins empresariales (BAdI). SAP Control Framework es una colección de clases e interfaces globales que se puede utilizar para añadir controles SAP GUI en los programas de objetos ABAP, independientemente de la plataforma. El control Grid ALV es una herramienta que se puede utilizar para visualizar listas no jerárquicas en una forma estandarizada. Los datos de la lista se muestran en tablas. Es muy fácil trabajar con esta herramienta, ya que solo son necesarios unos pocos pasos de programación. El control Grid ALV contiene numerosas funciones estándar interactivas que los usuarios de listas necesitan a menudo, como imprimir, exportar, etc. Como programador, tiene la opción de suprimir estas funciones estándar. Si es necesario, puede adaptar las implementaciones para que cumplan las necesidades de la aplicación. También es posible añadir las funciones propias a la barra de herramientas de aplicación.
© Copyright . Reservados todos los derechos.
305
Capítulo 7: Ejemplos orientados a objetos de ABAP
Cómo incluir una instancia de control Grid ALV en un programa de diálogo
Figura 125: Cómo incluir una instancia de control Grid ALV en un programa de diálogo
Los controles del container ofrecen la conexión técnica entre la pantalla y el control de la aplicación. Los controles de aplicación, como el control Grid ALV, control Tree, SAP Picture Control, entre otros, siempre están integrados en este Container Control que, a su vez, está conectado a la pantalla. Existen diferentes tipos de container controls. Sin embargo, todos incorporan funciones de control fundamentales, como barras de desplazamiento.
Uso de un ALV en un área de pantalla
Figura 126: Visualizar datos de aplicación mediante una instancia Grid ALV
306
© Copyright . Reservados todos los derechos.
Lección: Implementación de ABAP List Viewer (ALV)
Debe situar un control Grid ALV en un área de pantalla con un tamaño fijo. Para hacer esto, debe crear una instancia de cada una de las clases globales CL_GUI_CUSTOM_CONTAINER y CL_GUI_ALV_GRID. Para la visualización normal, siga estos pasos de programación: 1. Utilice el editor de pantalla completa del Screen Painter para definir un área de control Custom en su pantalla. 2. Cree una instancia de la clase CL_GUI_CUSTOM_CONTAINER y transfiera el nombre del área de control Custom al constructor. 3. Cree una instancia de la clase CL_GUI_GUI_ALV_GRID y transfiera la referencia de la instancia de control Custom al constructor. 4. Llame el método SET_TABLE_FOR_FIRST_DISPLAY de la instancia de control Grid y transfiérale la tabla estándar interna, que contiene los datos que se visualizarán. Si la tabla contiene un tipo de fila global definido en el diccionario ABAP, puede transferir el nombre de esta estructura global al mismo método. Entonces, el control ALV Grid crea el catálogo del campo de manera automática.
Atención: La tabla interna que se transfiere al método SET_TABLE_FOR_FIRST_DISPLAY debe definirse globalmente. Por lo tanto, la tabla debe ser una variable de programa global o un atributo público de una clase. Cuando modifica los contenidos de las tablas internas mientras el programa se está ejecutando, solo será necesario llamar el método REFRESH_TABLE_DISPLAY en el paso de diálogo relevante para actualizar la visualización.
Implementación de un programa de control para el evento de doble clic
Figura 127: Control Grid ALV: Doble clic
© Copyright . Reservados todos los derechos.
307
Capítulo 7: Ejemplos orientados a objetos de ABAP
Un control Grid ALV puede reaccionar ante el doble clic de un usuario. Como posible reacción, se puede desencadenar un paso de tratamiento posterior en el cual se visualice información adicional. En el ejemplo que se muestra en la figura, los datos de reserva de los pasajeros individuales o los datos del avión también podrían visualizarse para los datos del vuelo. Esto se ejecuta captando el evento DOUBLE_CLICK con un método de programa de control. Control Grid ALV: reacción ante a un doble clic
Figura 128: Control Grid ALV: reacción ante a un doble clic
Un método de programa de control es un método de clase (método estático) o un método de instancia de un objeto. Si un método de clase se define como un método de programa de control, no será necesario instanciar ningún objeto de la clase tratada para que utilice el método. Para crear un objeto de programa de control para un evento, defina primero una clase. Esta clase tiene un método público en la PUBLIC SECTION que puede reaccionar con un evento. Durante la implementación del método de programa de control, defina el texto fuente que deberá ejecutarse cuando se desencadene el evento. El método recibe la información que suministra el evento desde la posición del ratón cuando se hace doble clic, y crea un mensaje de información en el ejemplo de control que visualiza la flecha y el campo del clic del ratón.
308
© Copyright . Reservados todos los derechos.
Lección: Implementación de ABAP List Viewer (ALV)
Nota: La documentación ampliada acerca del SAP Control Framework está disponible en la documentación de productos SAP estándar (que se ofrece con el producto o en línea a través del portal de ayuda de SAP). La biblioteca SAP tiene descripciones completas de todas las clases y un programa de aprendizaje completo. El Object Navigator del Workbench ABAP también contiene el Demo Center, que facilita muchísimo el uso de programas modelo estándar. Lo encontrará en el Object Navigator del Workbench ABAP en Entorno → Ejemplos → Ejemplos de control. Los elementos individuales del SAP Control Framework también se cubren en otros cursos. SAP también ofrece un curso exhaustivo diferente acerca de la programación de diálogos con los controles SAP. El curso cubre todos los aspectos, incluidas las técnicas de programación complejas, como las funciones arrastrar y soltar.
© Copyright . Reservados todos los derechos.
309
Capítulo 7: Ejemplos orientados a objetos de ABAP
310
© Copyright . Reservados todos los derechos.
Capítulo 7 Ejercicio 19 Implementar el control Grid ALV
Ejemplo empresarial Desea ver una lista de conexiones de vuelos en un Control Grid ALV. Cuando hace doble clic en una conexión, debe visualizarse el número de fila y el nombre de la columna que seleccionó. Modelo: SAPBC401_ALV_T1 Solución: SAPBC401_ALV_S1 Cree un control ALV Grid y reaccione al doble clic en el control ALV Grid. Tarea 1 Programación de un control Grid ALV y visualización de la lista de conexiones de vuelos ya almacenados en la tabla interna GT_SPFLI. 1. Copie el programa de modelo SAPBC401_ALV_T1 en ZBC401_##_ALV. 2. En el programa principal, defina las variables de referencia GO_CONTAINER y GO_ALV_GRID necesarias para el control Grid ALV. 3. Analice la pantalla existente 100 y preste especial atención en el nombre del Área de control de container custom, que se utiliza como la base para el control Grid ALV. Implemente el módulo PBO ALV_GRID. Utilice las variables de referencia para instanciar las dos clases en este módulo PBO. Preste atención al hecho de que CREATE OBJECT no se llama de manera repetida cuando el PBO se ejecuta de forma repetida. 4. Para visualizar los datos en el control Grid ALV, llame al método SET_TABLE_FOR_FIRST_DISPLAY y transfiera la tabla interna con los datos de conexión de vuelos y el nombre del tipo de línea de esa tabla interna. 5. Active y realice un test del programa. Atención: Trabaja con una pantalla en este ejercicio, por lo tanto, siempre debe activar todas las partes del programa así como la pantalla.
Tarea 2 Trate un doble clic en el control Grid ALV. Si el usuario hace doble clic en una fila en el control Grid ALV, debe visualizarse el número de fila y el nombre de la columna en la que el usuario hizo doble clic en un mensaje tipo "I".
© Copyright . Reservados todos los derechos.
311
Capítulo 7: Ejemplos orientados a objetos de ABAP
1. Defina una clase local LCL_EVENT_HANDLER y en esta clase defina el método de instancia para gestionar el evento DOUBLE_CLICK que desencadenó el control Grid ALV. Nota: La clase LCL_EVENT_HANDLER solo actúa como programa de control y que no tiene otras funciones. Importe los parámetros ES_ROW_NO y E_COLUMN en el método de controlador. 2. Implemente el método de controlador. Envíe un mensaje del tipo I para emitir el número de fila y el nombre de columna en los que hizo clic el usuario. 3. Instancie la clase de controlador y registre el método de programa del control de eventos. 4. Active y realice un test del programa.
312
© Copyright . Reservados todos los derechos.
Capítulo 7 Solución 19 Implementar el control Grid ALV
Ejemplo empresarial Desea ver una lista de conexiones de vuelos en un Control Grid ALV. Cuando hace doble clic en una conexión, debe visualizarse el número de fila y el nombre de la columna que seleccionó. Modelo: SAPBC401_ALV_T1 Solución: SAPBC401_ALV_S1 Cree un control ALV Grid y reaccione al doble clic en el control ALV Grid. Tarea 1 Programación de un control Grid ALV y visualización de la lista de conexiones de vuelos ya almacenados en la tabla interna GT_SPFLI. 1. Copie el programa de modelo SAPBC401_ALV_T1 en ZBC401_##_ALV. a) Realice este paso de la forma habitual. 2. En el programa principal, defina las variables de referencia GO_CONTAINER y GO_ALV_GRID necesarias para el control Grid ALV. a) Revise el extracto del código fuente de la solución modelo o consulte las diapositivas correspondientes acerca del control Grid ALV. 3. Analice la pantalla existente 100 y preste especial atención en el nombre del Área de control de container custom, que se utiliza como la base para el control Grid ALV. Implemente el módulo PBO ALV_GRID. Utilice las variables de referencia para instanciar las dos clases en este módulo PBO. Preste atención al hecho de que CREATE OBJECT no se llama de manera repetida cuando el PBO se ejecuta de forma repetida. a) Revise el extracto del código fuente de la solución modelo o consulte las diapositivas correspondientes sobre el control Grid ALV. Hable con su instructor si tiene cualquier duda. 4. Para visualizar los datos en el control Grid ALV, llame al método SET_TABLE_FOR_FIRST_DISPLAY y transfiera la tabla interna con los datos de conexión de vuelos y el nombre del tipo de línea de esa tabla interna. a) Revise el extracto del código fuente de la solución modelo o consulte las diapositivas correspondientes sobre el control Grid ALV. Hable con su instructor si tiene cualquier duda. 5. Active y realice un test del programa.
© Copyright . Reservados todos los derechos.
313
Capítulo 7: Ejemplos orientados a objetos de ABAP
Atención: Trabaja con una pantalla en este ejercicio, por lo tanto, siempre debe activar todas las partes del programa así como la pantalla. a) Realice este paso de la forma habitual.
Tarea 2 Trate un doble clic en el control Grid ALV. Si el usuario hace doble clic en una fila en el control Grid ALV, debe visualizarse el número de fila y el nombre de la columna en la que el usuario hizo doble clic en un mensaje tipo "I". 1. Defina una clase local LCL_EVENT_HANDLER y en esta clase defina el método de instancia para gestionar el evento DOUBLE_CLICK que desencadenó el control Grid ALV. Nota: La clase LCL_EVENT_HANDLER solo actúa como programa de control y que no tiene otras funciones. Importe los parámetros ES_ROW_NO y E_COLUMN en el método de controlador. a) Vea el extracto del código fuente de la solución modelo o consulte las diapositivas correspondientes acerca de cómo hacer doble clic en el control Grid ALV. 2. Implemente el método de controlador. Envíe un mensaje del tipo I para emitir el número de fila y el nombre de columna en los que hizo clic el usuario. a) Puede utilizar el mensaje 010 de la clase de mensaje BC401. 3. Instancie la clase de controlador y registre el método de programa del control de eventos. a) Revise el extracto del código fuente de la solución modelo o consulte las diapositivas correspondientes acerca de cómo hacer doble clic en el control Grid ALV. 4. Active y realice un test del programa. a) Realice este paso de la forma habitual. Asegúrese de que el programa muestre lo siguiente: SAPBC401_ALV_S1 REPORT
sapbc401_alv_s1.
*-------------------------------------------------* * CLASS lcl_event_handler DEFINITION *-------------------------------------------------* CLASS lcl_event_handler DEFINITION. PUBLIC SECTION. METHODS on_double_click FOR EVENT double_click OF cl_gui_alv_grid IMPORTING es_row_no e_column. ENDCLASS. "lcl_event_handler DEFINITION *-------------------------------------------------*
314
© Copyright . Reservados todos los derechos.
Lección: Implementación de ABAP List Viewer (ALV)
* CLASS lcl_event_handler IMPLEMENTATION *-------------------------------------------------* CLASS lcl_event_handler IMPLEMENTATION. METHOD on_double_click. MESSAGE i010(bc401) WITH es_row_no-row_id e_column-fieldname. ENDMETHOD. ENDCLASS.
"handler_method "lcl_event_handler IMPLEMENTATION
*** Types and Data Definitions TYPES: ty_spfli TYPE STANDARD TABLE OF spfli WITH NON-UNIQUE KEY carrid connid. DATA: ok_code TYPE sy-ucomm. DATA: go_handler TYPE REF TO lcl_event_handler, go_container TYPE REF TO cl_gui_custom_container, go_alv_grid TYPE REF TO cl_gui_alv_grid. DATA: gt_spfli TYPE ty_spfli.
START-OF-SELECTION. ******************** SELECT * FROM spfli INTO TABLE gt_spfli. CALL SCREEN '0100'. *&----------------------------------------------* *& Module STATUS_0100 OUTPUT *&----------------------------------------------* MODULE status_0100 OUTPUT. SET PF-STATUS 'DYNPROSTATUS'. SET TITLEBAR 'TITLE1'. ENDMODULE. " STATUS_0100 OUTPUT *&----------------------------------------------* *& Module ALV_GRID OUTPUT *&----------------------------------------------* MODULE alv_grid OUTPUT. ** Create object of class CL_GUI_CUSTOM_CONTAINER ** to manage data IF go_container IS NOT BOUND. CREATE OBJECT go_container EXPORTING container_name = 'CONTAINER_1' EXCEPTIONS others = 6. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. ** create object of class cl_gui_alv_grid to visualize data
© Copyright . Reservados todos los derechos.
315
Capítulo 7: Ejemplos orientados a objetos de ABAP
CREATE OBJECT go_alv_grid EXPORTING i_parent = go_container EXCEPTIONS others = 5. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. ** create handler instance and register handler method CREATE OBJECT go_handler. SET HANDLER go_handler->on_double_click FOR go_alv_grid. ** Call method to visualize data of internal table CALL METHOD go_alv_grid->set_table_for_first_display EXPORTING i_structure_name = 'SPFLI' CHANGING it_outtab = gt_spfli EXCEPTIONS OTHERS = 4. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. ENDIF. ENDMODULE.
" ALV_GRID
OUTPUT
*&-----------------------------------------------* *& Module USER_COMMAND_0100 INPUT *&-----------------------------------------------* MODULE user_command_0100 INPUT. CASE ok_code. WHEN 'BACK'. SET SCREEN 0. WHEN 'EXIT'. LEAVE PROGRAM. ENDCASE. ENDMODULE.
316
" USER_COMMAND_0100
INPUT
© Copyright . Reservados todos los derechos.
Capítulo 7 Ejercicio 20 Implementar una ventana emergente con el control Grid ALV
Ejemplo empresarial Necesita ver una lista de conexiones de vuelos en un Control Grid ALV. Cuando hace doble clic en una conexión, se visualizará la lista de vuelos para esta conexión en un segundo control Grid ALV. Modelo: SAPBC401_ALV_S1 Solución: SAPBC401_ALV_S2 Tarea 1 Lea desde la tabla SFLIGHT de la base de datos los vuelos que pertenecen a la conexión de vuelos en la que el usuario hizo doble clic. 1. Complete el programa ZBC401_##_ALV (## es el número de grupo de dos cifras) o copie la solución modelo del ejercicio anterior. 2. En el método de programa de control de eventos, elimina la sentencia MESSAGE. Defina una estructura local (nombre sugerido: LS_SPFLI) que funcione como el área de trabajo para la tabla interna GT_SPFLI. Desde GT_SPFLI, lea la entrada que corresponda a la fila matriz en la que hizo doble clic. Consejo: Utilice READ TABLE con un acceso a índice.
3. ¿Es aceptable definir GT_SPFLI después de la definición de la clase del programa de control de eventos?
4. En la definición de la clase de control de evento, defina un atributo de instancia privado MT_SFLIGHT, que es una tabla interna (estándar) con el tipo de línea SFLIGHT. Consejo: Defina un tipo de tabla privado TY_SFLIGHT en la misma clase.
© Copyright . Reservados todos los derechos.
317
Capítulo 7: Ejemplos orientados a objetos de ABAP
5. En el método de control de eventos, implemente un array fetch en la tabla de base de datos SFLIGHT para completar MT_SFLIGHT con esos vuelos, que tienen los mismos campos clave que la conexión de vuelos en la que hizo clic. 6. Active su programa y analícelo en ABAP Debugger. Asegúrese de que MT_SFLIGHT esté completado correctamente.
Tarea 2 Amplíe el método de programa de control de eventos para que los vuelos seleccionados se presenten en un segundo control Grid ALV que se visualiza en un container de ventana de diálogo. 1. En la clase de control de eventos, defina dos variables de referencia como los atributos de instancia privados (nombres sugeridos: MO_CONT_POPUP y MO_ALV_POPUP). Escríbalos con las clases globales CL_GUI_DIALOGBOX_CONTAINER y CL_GUI_ALV_GRID. 2. En el método de programa de control de eventos, utilice estas variables de referencia para crear instancias de las dos clases. Asegúrese de que la sentencia CREATE OBJECT no se llame de manera repetida cuando el método del programa de control de eventos se ejecute de manera repetida. 3. Para visualizar los datos en el control Grid ALV, llame al método SET_TABLE_FOR_FIRST_DISPLAY y transfiera la tabla interna MT_SFLIGHT con los datos de conexión de vuelos y el nombre del tipo de línea de esa tabla interna. Asegúrese de que este método solo se llame si se acaban de crear el container de ventana de diálogo y el segundo control Grid ALV. 4. Si el container de ventana de diálogo y el segundo control Grid ALV ya existen, no llame el método SET_TABLE_FOR_FIRST_DISPLAY para actualizar los datos que se visualizan. En lugar de ello, llame el método REFRESH_TABLE_DISPLAY. Consejo: No debe proporcionar valores para los parámetros opcionales de este método. 5. Active y realice un test del programa. Nota: En este momento, si hace clic en el botón de la esquina superior derecha de la ventana, no cerrará el container de la ventana de diálogo. Para implementar esta función, tendrá que gestionar el evento CLOSE de la clase CL_GUI_DIALOGBOX_CONTAINER y llamar al método FREE del container de ventana de diálogo. Otros cursos de formación y la documentación del Control Framework explican este procedimiento en detalle.
318
© Copyright . Reservados todos los derechos.
Capítulo 7 Solución 20 Implementar una ventana emergente con el control Grid ALV
Ejemplo empresarial Necesita ver una lista de conexiones de vuelos en un Control Grid ALV. Cuando hace doble clic en una conexión, se visualizará la lista de vuelos para esta conexión en un segundo control Grid ALV. Modelo: SAPBC401_ALV_S1 Solución: SAPBC401_ALV_S2 Tarea 1 Lea desde la tabla SFLIGHT de la base de datos los vuelos que pertenecen a la conexión de vuelos en la que el usuario hizo doble clic. 1. Complete el programa ZBC401_##_ALV (## es el número de grupo de dos cifras) o copie la solución modelo del ejercicio anterior. a) Realice este paso de la forma habitual. 2. En el método de programa de control de eventos, elimina la sentencia MESSAGE. Defina una estructura local (nombre sugerido: LS_SPFLI) que funcione como el área de trabajo para la tabla interna GT_SPFLI. Desde GT_SPFLI, lea la entrada que corresponda a la fila matriz en la que hizo doble clic. Consejo: Utilice READ TABLE con un acceso a índice.
a) Véase el extracto del código fuente de la solución modelo. 3. ¿Es aceptable definir GT_SPFLI después de la definición de la clase del programa de control de eventos? No. Para poder acceder al objeto de clase global GT_SPFLI desde la implementación de clase local, el objeto de datos debe definirse como variable de programa global antes de la definición de clase local. 4. En la definición de la clase de control de evento, defina un atributo de instancia privado MT_SFLIGHT, que es una tabla interna (estándar) con el tipo de línea SFLIGHT.
© Copyright . Reservados todos los derechos.
319
Capítulo 7: Ejemplos orientados a objetos de ABAP
Consejo: Defina un tipo de tabla privado TY_SFLIGHT en la misma clase.
a) Véase el extracto del código fuente de la solución modelo. 5. En el método de control de eventos, implemente un array fetch en la tabla de base de datos SFLIGHT para completar MT_SFLIGHT con esos vuelos, que tienen los mismos campos clave que la conexión de vuelos en la que hizo clic. a) Véase el extracto del código fuente de la solución modelo. 6. Active su programa y analícelo en ABAP Debugger. Asegúrese de que MT_SFLIGHT esté completado correctamente. a) Realice este paso de la forma habitual.
Tarea 2 Amplíe el método de programa de control de eventos para que los vuelos seleccionados se presenten en un segundo control Grid ALV que se visualiza en un container de ventana de diálogo. 1. En la clase de control de eventos, defina dos variables de referencia como los atributos de instancia privados (nombres sugeridos: MO_CONT_POPUP y MO_ALV_POPUP). Escríbalos con las clases globales CL_GUI_DIALOGBOX_CONTAINER y CL_GUI_ALV_GRID. a) Véase el extracto del código fuente de la solución modelo. 2. En el método de programa de control de eventos, utilice estas variables de referencia para crear instancias de las dos clases. Asegúrese de que la sentencia CREATE OBJECT no se llame de manera repetida cuando el método del programa de control de eventos se ejecute de manera repetida. a) Véase el extracto del código fuente de la solución modelo. 3. Para visualizar los datos en el control Grid ALV, llame al método SET_TABLE_FOR_FIRST_DISPLAY y transfiera la tabla interna MT_SFLIGHT con los datos de conexión de vuelos y el nombre del tipo de línea de esa tabla interna. Asegúrese de que este método solo se llame si se acaban de crear el container de ventana de diálogo y el segundo control Grid ALV. a) Véase el extracto del código fuente de la solución modelo. 4. Si el container de ventana de diálogo y el segundo control Grid ALV ya existen, no llame el método SET_TABLE_FOR_FIRST_DISPLAY para actualizar los datos que se visualizan. En lugar de ello, llame el método REFRESH_TABLE_DISPLAY. Consejo: No debe proporcionar valores para los parámetros opcionales de este método. a) Véase el extracto del código fuente de la solución modelo. 5. Active y realice un test del programa.
320
© Copyright . Reservados todos los derechos.
Lección: Implementación de ABAP List Viewer (ALV)
Nota: En este momento, si hace clic en el botón de la esquina superior derecha de la ventana, no cerrará el container de la ventana de diálogo. Para implementar esta función, tendrá que gestionar el evento CLOSE de la clase CL_GUI_DIALOGBOX_CONTAINER y llamar al método FREE del container de ventana de diálogo. Otros cursos de formación y la documentación del Control Framework explican este procedimiento en detalle. a) Realice este paso de la forma habitual. SAPBC401_ALV_S2 REPORT
sapbc401_alv_s2.
TYPES: ty_spfli TYPE STANDARD TABLE OF spfli WITH NON-UNIQUE KEY carrid connid. DATA: gt_spfli TYPE ty_spfli. *--------------------------------------------------* * CLASS lcl_event_handler DEFINITION *--------------------------------------------------* * *--------------------------------------------------* CLASS lcl_event_handler DEFINITION. PUBLIC SECTION. METHODS on_double_click FOR EVENT double_click OF cl_gui_alv_grid IMPORTING es_row_no e_column. PRIVATE SECTION. TYPES: ty_sflight TYPE STANDARD TABLE OF sflight WITH NON-UNIQUE KEY carrid connid fldate. DATA: mo_cont_popup TYPE REF TO cl_gui_dialogbox_container, mo_alv_popup TYPE REF TO cl_gui_alv_grid. DATA: mt_sflight TYPE ty_sflight. ENDCLASS.
"lcl_event_handler DEFINITION
*--------------------------------------------------* * CLASS lcl_event_handler IMPLEMENTATION *--------------------------------------------------* * *--------------------------------------------------* CLASS lcl_event_handler IMPLEMENTATION. METHOD on_double_click. DATA ls_spfli TYPE spfli. READ TABLE gt_spfli INTO ls_spfli INDEX es_row_no-row_id.
© Copyright . Reservados todos los derechos.
321
Capítulo 7: Ejemplos orientados a objetos de ABAP
SELECT * FROM sflight INTO TABLE mt_sflight WHERE carrid = ls_spfli-carrid AND connid = ls_spfli-connid. IF mo_cont_popup IS NOT BOUND. CREATE OBJECT mo_cont_popup EXPORTING width = 600 height = 300 EXCEPTIONS others = 8. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. CREATE OBJECT mo_alv_popup EXPORTING i_parent = mo_cont_popup EXCEPTIONS others = 5. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. mo_alv_popup->set_table_for_first_display( EXPORTING i_structure_name = 'SFLIGHT' CHANGING it_outtab = mt_sflight EXCEPTIONS OTHERS = 4 ). IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. ELSE. mo_alv_popup->refresh_table_display( EXCEPTIONS OTHERS = 2 ). IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. ENDIF. * MESSAGE i010(bc401) WITH * es_row_no-row_id e_column-fieldname. ENDMETHOD. ENDCLASS.
"handler_method "lcl_event_handler IMPLEMENTATION
DATA: ok_code TYPE sy-ucomm.
322
© Copyright . Reservados todos los derechos.
Lección: Implementación de ABAP List Viewer (ALV)
DATA: go_handler TYPE REF TO lcl_event_handler, go_container TYPE REF TO cl_gui_custom_container, go_alv_grid TYPE REF TO cl_gui_alv_grid. START-OF-SELECTION. ******************** SELECT * FROM spfli INTO TABLE gt_spfli. CALL SCREEN '0100'. *&------------------------------------------------* *& Module STATUS_0100 OUTPUT *&------------------------------------------------* * text *-------------------------------------------------* MODULE status_0100 OUTPUT. SET PF-STATUS 'DYNPROSTATUS'. SET TITLEBAR 'TITLE1'. ENDMODULE. " STATUS_0100 OUTPUT *&------------------------------------------------* *& Module ALV_GRID OUTPUT *&------------------------------------------------* * text *-------------------------------------------------* MODULE alv_grid OUTPUT. * Create object of class CL_GUI_CUSTOM_CONTAINER to * manage data IF go_container IS NOT BOUND. CREATE OBJECT go_container EXPORTING container_name = 'CONTAINER_1' EXCEPTIONS others = 6. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. * create object of class cl_gui_alv_grid to visualize data CREATE OBJECT go_alv_grid EXPORTING i_parent = go_container EXCEPTIONS others = 5. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. ** create handler Instance CREATE OBJECT go_handler. ** set handler to react on double-click SET HANDLER go_handler->on_double_click FOR go_alv_grid. ** Call method to visualize data of internal table CALL METHOD go_alv_grid->set_table_for_first_display
© Copyright . Reservados todos los derechos.
323
Capítulo 7: Ejemplos orientados a objetos de ABAP
EXPORTING i_structure_name = 'SPFLI' CHANGING it_outtab = gt_spfli EXCEPTIONS OTHERS = 4. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. ENDIF. ENDMODULE.
" ALV_GRID
OUTPUT
*&-------------------------------------------------* *& Module USER_COMMAND_0100 INPUT *&-------------------------------------------------* MODULE user_command_0100 INPUT. CASE ok_code. WHEN 'BACK'. SET SCREEN 0. WHEN 'EXIT'. LEAVE PROGRAM. ENDCASE. ENDMODULE.
324
" USER_COMMAND_0100
INPUT
© Copyright . Reservados todos los derechos.
Lección: Implementación de ABAP List Viewer (ALV)
RESUMEN DE LA LECCIÓN Ahora podrá: ●
Implementar ABAP List Viewer (ALV) de manera simple.
●
Implementar el doble clic en la ABAP List Viewer (ALV)
© Copyright . Reservados todos los derechos.
325
Capítulo 7 Lección 2 Implementación de add-ins empresariales (BAdI)
RESUMEN DE LA LECCIÓN Este módulo le enseña a implementar los add-ins empresariales (BAdI). Ejemplo empresarial Necesita ampliar la funcionalidad en un programa estándar de SAP sin alterar el programa original. Esto puede realizarse mediante BAdI. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de los BAdI
●
Una buena comprensión de cómo se define un BAdI
●
Una buena comprensión de cómo se implementa un BAdI
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Describir los Add-ins empresariales (BAdI)
BAdI A diferencia de los Exits de cliente, los BAdI se optimizan para el proceso de entrega de software modificado. El proceso de suministro típico no consiste solo en proveedores y clientes, sino que varios proveedores intermedios están involucrados en la cadena de suministro del software. Por ejemplo, un interlocutor de SAP puede ampliar un programa de aplicación SAP con una solución industrial como unidad empresarial industrial (IBU). Luego el cliente puede extender el mismo programa.
326
© Copyright . Reservados todos los derechos.
Lección: Implementación de add-ins empresariales (BAdI)
BAdI: Fundamentos
Figura 129: BAdI: Fundamentos
Con un BAdI, una aplicación de SAP proporciona la opción de ampliación a través de una interfaz y una clase de adaptador que implementa esa interfaz. La interfaz puede ser implementada por varios posibles usuarios en la cadena de suministro, por lo tanto, es posible obtener múltiples implementaciones de BAdI. Además, una implementación de BAdI en sí puede proporcionar otro BAdI que pueden implementar los usuarios que aparecen más adelante en la cadena de suministro. Definición de un BAdI – Fundamentos
Figura 130: Definición de un BAdI – Fundamentos
© Copyright . Reservados todos los derechos.
327
Capítulo 7: Ejemplos orientados a objetos de ABAP
Cuando define un BAdI, se debe especificar una interfaz (IF_EX_) con los correspondientes métodos definidos formalmente. La clase de adaptador que se genera automáticamente durante la definición de interfaz (CL_EX_) tiene, además de otras capacidades, la función de llamar todas las implementaciones activas del BAdI. Cuando dispone de varias implementaciones activas, no hay una secuencia de procesamiento predefinida. Para definir un BAdI
1. Ejecute la transacción SE18 o, en la pantalla SAP Easy Access, seleccione Herramientas → Workbench ABAP → Utilidades → Add-ins empresariales → Definición. 2. A partir de SAP Netweaver 7.0, no puede crear un BAdI de manera directa. Primero debe crear lo que se denomina punto de ampliación. En la definición del punto de ampliación, puede crear los BAdI en la etiqueta Definiciones de elementos del punto de ampliación. 3. Indique el nombre de la definición (). 4. Seleccione el pulsador Crear e indique el nombre de la interfaz () en la ventana de diálogo correspondiente.
BAdI – El programa de llamada
Figura 131: BAdI – El programa de llamada
La figura muestra un ejemplo de una llamada de BAdI. Debe definirse una variable de referencia del tipo de BadI. Un objeto de la clase de adaptador es instanciado por la llamada del método estático GET_INSTANCE de la clase CL_EXITHANDLER. La variable gb_adapter apunta a esta instancia.
328
© Copyright . Reservados todos los derechos.
Lección: Implementación de add-ins empresariales (BAdI)
Los métodos de interfaz del BAdI pueden llamarse a través de la referencia de objeto gb_adapter.
Búsqueda de BAdI Puede buscar los BAdI utilizando las siguientes estrategias: ● Puede utilizar el sistema de información de Repository (transacción SE84). ●
Puede utilizar la jerarquía de aplicaciones (transacción SE81).
●
Puede utilizar la guía de Customizing (Guía de implementación de la transacción SPRO).
●
●
●
Puede buscar en el código fuente de la aplicación para la sentencia CL_EXITHANDLER=>GET_INSTANCE. Es posible buscar, en el código fuente de la aplicación, la frecuencia de las interfaces BAdI con la convención para fijar nombres IF_EX_. A partir de SAP Netweaver AS 7.0, en el código fuente de aplicación, puede buscar la frecuencia de la sentencia GET BADI.
El nombre del BAdl debe investigarse antes de poder implementar el BAdI. Cuando busca nombres de BAdI, puede utilizar los mecanismos de búsqueda. Haga doble clic en la variable de referencia (gb_adapter) del ejemplo para obtener la definición de interfaz. Es posible derivar el nombre de BAdI del nombre de la interfaz.
Nota: Cómo buscar en el código fuente de ABAP: Cuando ejecute una transacción arbitraria, presione la tecla F1. En la ventana emergente que aparece, presione el pulsador Información técnica. Navegue al código fuente del programa haciendo doble clic en el nombre del programa. Luego llame la función de búsqueda global en el menú Tratar → Buscar siguiente y busque la cadena deseada. Comentario: No utilice la función de búsqueda del editor Tratar → Encontrar/ Reemplazar (Ctrl-F) porque esta función considerará solo un código fuente único.
© Copyright . Reservados todos los derechos.
329
Capítulo 7: Ejemplos orientados a objetos de ABAP
Implementar un BAdI
Figura 132: Implementación de un BAdI – SE19
Cuando se determina el nombre del BAdI, este puede implementarse. La implementación del BAdI se realiza a través de la actualización de implementación en Herramientas → Workbench ABAP → Utilidades → Add-Ins empresariales → Implementación (código de transacción SE19). O bien, puede acceder a las implementaciones navegando por el menú desde la definición de BAdI. Para implementar un BAdI, debe emitirse un nombre de implementación de BAdI. La convención para fijar nombres es Z. Aparecerá una ventana de diálogo para seleccionar el BAdI correspondiente. El código que se implementará se almacena en un método de una clase de cliente generada automáticamente. Por esta razón, el nombre de la clase de implementación debe otorgarse en una ventana de diálogo final. El nombre de propuesta de SAP consta de Y o Z (el prefijo del área de nombres), CL_ (de clase), IM_ (de implementación) e (el nombre real de la implementación). Cuando hace doble clic en uno de los métodos de BAdI, puede indicar el código del método. También puede crear métodos auxiliares en la clase de implementación para estructurar mejor el código requerido del método BAdI.
Nota: Activar los métodos o las implementaciones al final de la tarea.
Para implementar un BAdI 1. Ejecute el código de transacción SE19.
330
© Copyright . Reservados todos los derechos.
Lección: Implementación de add-ins empresariales (BAdI)
2. Indique un nombre de definición de BAdI (o nombre de punto de ampliación) y seleccione el pulsador Crear. 3. Indique un nombre de implementación y seleccione el pulsador OK. 4. Indique un texto de descripción y seleccione el pulsador Grabar. 5. Haga doble clic en la clase de implementación para navegar a la clase e implementar su código fuente allí. RESUMEN DE LA LECCIÓN Ahora podrá: ●
Describir los Add-ins empresariales (BAdI)
© Copyright . Reservados todos los derechos.
331
Capítulo 7: Ejemplos orientados a objetos de ABAP
332
© Copyright . Reservados todos los derechos.
Capítulo 7 Evaluación de la formación
1. El control Grid (ALV) ABAP List Viewer es una herramienta que se puede utilizar para visualizar listas no jerárquicas en una forma estandarizada. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
2. Los controles del container no proporcionan la conexión técnica entre la pantalla y el control de la aplicación. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
3. Para crear un objeto del programa de control para un evento, primero debemos definir una ____________. Seleccione la respuesta correcta. X
A clase
X
B estructura
X
C subscreen
X
D estático
4. Un método de programa de control puede ser un método de clase (estático) o un método de instancia de un objeto. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
333
Capítulo 7: Evaluación de la formación
5. Con un Add-In empresarial (BAdI), un programa de aplicación de SAP ofrece la opción de ampliación a través de un método de interfaz. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
6. Un objeto de la clase de adaptador de BAdI es instanciado por la llamada del método estático GET_INSTANCE de la clase CL_EXITHANDLER. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
7. Para implementar un Business Add-In (BAdI), el nombre de definición de BADI debe investigarse. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
8. El código de una implementación de BAdI se almacena en un __________ de una clase de cliente automáticamente generada. Seleccione la respuesta correcta.
334
X
A método
X
B estructura
X
C objeto
© Copyright . Reservados todos los derechos.
Capítulo 7 Respuestas a la Evaluación de la formación
1. El control Grid (ALV) ABAP List Viewer es una herramienta que se puede utilizar para visualizar listas no jerárquicas en una forma estandarizada. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
2. Los controles del container no proporcionan la conexión técnica entre la pantalla y el control de la aplicación. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
3. Para crear un objeto del programa de control para un evento, primero debemos definir una ____________. Seleccione la respuesta correcta. X
A clase
X
B estructura
X
C subscreen
X
D estático
4. Un método de programa de control puede ser un método de clase (estático) o un método de instancia de un objeto. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
335
Capítulo 7: Respuestas a la Evaluación de la formación
5. Con un Add-In empresarial (BAdI), un programa de aplicación de SAP ofrece la opción de ampliación a través de un método de interfaz. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
6. Un objeto de la clase de adaptador de BAdI es instanciado por la llamada del método estático GET_INSTANCE de la clase CL_EXITHANDLER. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
7. Para implementar un Business Add-In (BAdI), el nombre de definición de BADI debe investigarse. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
8. El código de una implementación de BAdI se almacena en un __________ de una clase de cliente automáticamente generada. Seleccione la respuesta correcta.
336
X
A método
X
B estructura
X
C objeto
© Copyright . Reservados todos los derechos.
CAPÍTULO 8
Patrones de diseño orientados a objetos
Lección 1 Implementación de técnicas especiales orientadas a objetos
338
Lección 2 Implementación del patrón singleton Ejercicio 21: Implementar el patrón singleton
345 349
Lección 3 Implementación de clases factory mediante amistad Ejercicio 22: Implementar una clase factory mediante amistad
358 361
OBJETIVOS DEL CAPÍTULO ●
Implementar clases abstractas
●
Implementar clases finales
●
Acceder a tablas internas con referencias de objeto
●
Llamar métodos de navegación
●
Limitar la visibilidad del constructor de instancia
●
Implementar métodos factory
●
Implementar el patrón singleton
●
Implementar relaciones de amistad
© Copyright . Reservados todos los derechos.
337
Capítulo 8 Lección 1 Implementación de técnicas especiales orientadas a objetos
RESUMEN DE LA LECCIÓN Este módulo explica cómo se implementan las clases abstractas y finales, cómo se accede a las tablas internas con referencias de objeto y cómo se llaman los métodos de navegación. Ejemplo empresarial Necesita añadir técnicas de programación especiales orientadas a objetos a sus implementaciones de objetos ABAP. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de cómo se definen las clases abstractas
●
Una buena comprensión de cómo se definen los métodos abstractos
●
Una buena comprensión de cómo se definen las clases finales
●
Una buena comprensión de cómo se definen los métodos finales
●
Una buena comprensión de cómo usar los atributos públicos de solo lectura
●
Una buena comprensión de cómo se llaman los métodos de navegación
●
Una buena comprensión de cómo se encadenan los métodos funcionales
●
Una buena comprensión de cómo se define la Visibilidad del constructor de instancias
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá:
338
●
Implementar clases abstractas
●
Implementar clases finales
●
Acceder a tablas internas con referencias de objeto
●
Llamar métodos de navegación
●
Limitar la visibilidad del constructor de instancia
© Copyright . Reservados todos los derechos.
Lección: Implementación de técnicas especiales orientadas a objetos
Clases abstractas
Figura 133: Clases abstractas y métodos abstractos
La clase abstracta contiene definición e implementación, pero no puede instanciarse. Utilice el suplemento ABSTRACT en la sentencia CLASS para crear una clase abstracta. Las clases superiores son un uso típico de las clases abstractas, ya que no se instancias por sí solas, pero sus subclases sí. En una clase abstracta, se pueden definir métodos abstractos (entre otras cosas). Esto significa que el método abstracto no puede implementarse en esa clase. En lugar de ello, se implementa en una subclase de la clase. Si la subclase de esa clase no es abstracta, los métodos abstractos deben redefinirse e implementarse en la subclase por primera vez.
Nota: El indicador relevante se encuentra en el generador de clases en la etiqueta Atributos de esa clase o ese método. Las referencias a estas clases abstractas puede utilizarse para el acceso polimórfico a instancias de subclase. Los métodos estáticos no pueden ser abstractos porque no pueden redefinirse.
© Copyright . Reservados todos los derechos.
339
Capítulo 8: Patrones de diseño orientados a objetos
Clases finales
Figura 134: Clases y métodos finales
Evite que una clase sea heredada utilizando el suplemento FINAL con la sentencia CLASS. Es posible impedir que un método sea redefinido mediante el suplemento FINAL con la sentencia METHODS.
Nota: El indicador relevante se encuentra en el generador de clases en la etiqueta Atributos de esa clase o ese método. Así, todos los métodos de una clase final son implícitamente finales. No puede repetir el suplemento FINAL en los métodos en sí. Las clases que son abstractas y finales solo deberían contener componentes estáticos.
Tablas internas con referencias de objeto En una sección anterior, hemos aprendido que las referencias de objeto pueden almacenarse en tablas internas. Esto se utiliza, particularmente, para implementar asociaciones. Sin embargo, todavía no hemos analizado cómo debemos recuperar un objeto específico de dicha lista. El siguiente gráfico nos ofrece un ejemplo de cómo debe lograrse:
340
© Copyright . Reservados todos los derechos.
Lección: Implementación de técnicas especiales orientadas a objetos
Figura 135: Consulte Acceso a una tabla con referencias de objeto.
Las referencias de objeto pueden almacenarse en tablas internas. El ejemplo de la figura explica cómo se recupera un objeto específico de esa lista. La referencia de objeto se almacena en una tabla junto con información clave. En el ejemplo, la información clave es la marca y el modelo del vehículo. La referencia de objeto puede recuperarse fácilmente a través de esta información clave. Esta técnica implica un almacenamiento redundante de información ya que los valores clave ya se encuentran almacenados en los atributos del objeto. Consulte Acceso mediante atributos públicos.
Figura 136: Consulte Acceso mediante atributos públicos.
© Copyright . Reservados todos los derechos.
341
Capítulo 8: Patrones de diseño orientados a objetos
Tal como se muestra en la figura, la redundancia de la información clave puede evitarse al hacer públicos los atributos clave. Los atributos públicos pueden utilizarse directamente en las sentencias para acceder a tablas internas como READ TABLE y LOOP AT. La expresión TABE_LINE que se utiliza aquí es una parte integrada del lenguaje ABAP. Cuando el tipo de línea de una tabla interna es un tipo de datos elemental en lugar de un tipo estructurado, es necesario utilizar TABLE_LINE. Estas tablas internas tienen solo una columna sin nombre. TABLE_LINE se utiliza como un nombre de columna genérico para esta columna individual.
Consejo: Hacer públicos los atributos va en contra de los principios fundamentales de la programación orientada a objetos. Lamentablemente, ABAP no permite el uso de métodos funcionales (como los métodos de nuestro ejemplo: GET_MAKE, GET_MODEL, etc.) sobre la parte izquierda de las cláusulas WHERE y los suplementos WITH KEY. Por lo tanto, los atributos públicos se utilizan exclusivamente en algunos casos especiales en modo de solo lectura.
Llamar métodos de navegación y concatenar llamadas de método
Figura 137: Métodos de navegación y concatenación de llamadas de métodos
Las asociaciones, como las agregaciones y las composiciones, son un principio de diseño importante de la programación orientada a objetos. Una asociación significa que, en tiempo de ejecución, una instancia de una clase almacena referencias a objetos de otra clase. Las clases que tienen otras clases asociadas a ellas contienen, a menudo, métodos que devuelven una de las referencias almacenadas al que realiza la llamada. Frecuentemente, estos métodos se denominan métodos de navegación ya que pueden utilizarse para navegar desde un objeto a otro. En el ejemplo, la clase LCL_VEHICLE se asocia a la clase LCL_RENTAL. La clase LCL_RENTAL proporciona el método de navegación GET_VEHICLE. Con frecuencia, el objetivo de la navegación de un objeto a otro es acceder a un método individual de este otro objeto. Antes del release de SAP NetWeaver 7.0 EhP2, era obligatorio
342
© Copyright . Reservados todos los derechos.
Lección: Implementación de técnicas especiales orientadas a objetos
almacenar la referencia al nuevo objeto en una variable de referencia. A partir de SAP NetWeaver 7.0 EhP2, podemos concatenar llamadas de métodos, es decir, podemos llamar directamente a un método del objeto que devuelve el método de navegación.
Consejo: Esta técnica no se limita a la concatenación de dos métodos. En los modelos de objetos más complicados, es posible concatenar cualquier cantidad de métodos.
Visibilidad del constructor de instancia
Figura 138: Parametrización implícita de visibilidad del constructor de instancia
En los objetos ABAP, nosotros podemos restringir la visibilidad del constructor de instancia. Si se restringe la visibilidad del constructor de instancia, las sentencias CREATE OBJECT para instanciar esta clase, solo están permitidas en ciertas partes de la codificación. Estos son los tipos de visibilidad del constructor de instancia: ● PRIVATE Si una clase tiene un constructor de instancia privado, solo puede instanciarse desde la clase misma; generalmente en métodos estáticos que se definen para ese objetivo. Estos métodos generalmente se denominan "métodos factory". ●
PROTECTED Si un constructor de instancia se encuentra protegido, la visibilidad se extiende a todas sus subclases; es decir, las subclases también pueden crear instancias de la clase.
●
PUBLIC Un constructor de instancia público es la parametrización de visibilidad propuesta: Las instancias de la clase pueden crearse dentro de la clase misma, dentro de otras clases o hasta en una parte no orientada a objetos del programa (p. ej., el programa principal).
Fije la visibilidad mediante el suplemento CREATE con la sentencia CLASS.
© Copyright . Reservados todos los derechos.
343
Capítulo 8: Patrones de diseño orientados a objetos
Nota: El indicador relevante se encuentra en el generador de clases, en la etiqueta Atributos de la clase relevante.
Consejo: La visibilidad del constructor no se fija colocando la definición del método CONSTRUCTOR en la sección correspondiente de la definición de clase. De hecho, antes de SAP NetWeaver 7.0, era obligatorio colocar sintácticamente el constructor en la sección pública. A partir de SAP NetWeaver 7.0, está permitido, pero no es obligatorio, colocar el constructor en la sección protegida o privada; si esto no es más restrictivo que el suplemento CREATE... en la definición de clase. Esto sirve para incrementar la legibilidad de la codificación.
RESUMEN DE LA LECCIÓN Ahora podrá:
344
●
Implementar clases abstractas
●
Implementar clases finales
●
Acceder a tablas internas con referencias de objeto
●
Llamar métodos de navegación
●
Limitar la visibilidad del constructor de instancia
© Copyright . Reservados todos los derechos.
Capítulo 8 Lección 2 Implementación del patrón singleton
RESUMEN DE LA LECCIÓN Este módulo explica los conceptos de los métodos factory, el patrón singleton y su implementación. Ejemplo empresarial: Necesita añadir técnicas de programación especiales orientadas a objetos a sus implementaciones de objetos ABAP. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión del método factory
●
Una buena comprensión del patrón singleton
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Implementar métodos factory
●
Implementar el patrón singleton
Métodos factory Sólo es lógico restringir la visibilidad del constructor de instancia si se realiza la instanciación en algún lugar dentro de la clase (o sus subclases, en caso de CREATE PROTECTED). Con frecuencia, dichas clases proporcionan un método estático público que crea una instancia de esta clase y devuelve la referencia de esta instancia al que realiza la llamada. Estos métodos generalmente se denominan métodos factory. Los métodos factory se ejecutan cuando una instancia de la clase se crea y tiene algunas ventajas en comparación con el constructor de instancia. A continuación se detallan algunas ventajas de los métodos factory: Un método factory puede tener una codificación que se ejecuta antes de la instanciación real.
●
Por ejemplo, el método puede hacer verificaciones, leer datos de la base de datos o fijar bloqueos antes de crear realmente una instancia. Si se produce un error durante estas etapas, no se creará una instancia y no se asignará memoria para ello. ●
Las clases pueden tener más de un método factory. Cada uno de los métodos puede tener una implementación y una firma diferentes. Los distintos métodos de factory permiten crear instancias de la misma clase según diferente información. Por ejemplo, un método factory crea una nueva instancia que ofrece parámetros de entrada para todos los atributos, mientras que otro método factory solo importa la información clave y luego recupera los demás valores de atributo desde la base de datos.
© Copyright . Reservados todos los derechos.
345
Capítulo 8: Patrones de diseño orientados a objetos
●
Utilice los métodos factory para administrar las instancias de una clase dentro de la misma clase. La administración de la instancia dentro de la clase se utiliza normalmente para evitar la creación de múltiples instancias idénticas. Se almacena una referencia de cada instancia nueva en un atributo estático privado de la clase (una tabla interna). Siempre que se llame a un método factory, verificará, en primer lugar, si ya existe una instancia con esta clave. De ser así, devolverá la instancia existente en vez de crear una nueva.
●
Utilice un método factory para instanciar una de las subclases en lugar de la clase misma. Por ejemplo, el método factory de una clase de avión puede verificar el tipo de avión y después instanciar un avión de carga o de pasajeros.
Ejemplo de una clase con método factory
Figura 139: Ejemplo de una clase con método factory
El ejemplo ilustra una clase con un método factory y el uso de un atributo estático para hacer referencia a todas sus instancias. La instanciación se restringe a la clase y solo se realiza en el método estático FACTORY. Cuando se llama al método, el método factory verifica si ya se ha creado una instancia idéntica. De ser así, devolverá la instancia existente en vez de crear una nueva.
Consejo: En este ejemplo, no es necesario hacer los atributos públicos para la sentencia READ TABLE. Como el método factory se encuentra en la clase, tiene acceso total a todos los atributos privados.
346
© Copyright . Reservados todos los derechos.
Lección: Implementación del patrón singleton
El patrón singleton
Figura 140: Clase singleton: mediante el uso de un Método factory
Utilice el concepto de singleton para evitar que una clase se instancie más de una vez para el mismo contexto del programa. Existen diferentes maneras de implementar una clase singleton. El primer patrón singleton es un caso especial del concepto factory. En lugar de almacenar varias instancias, la clase solo almacena una instancia. Cuando se llama por primera vez el método factory GET_INSTANCE, la clase se instanciará. Para todas las llamadas subsiguientes, devolverá la referencia al objeto existente.
© Copyright . Reservados todos los derechos.
347
Capítulo 8: Patrones de diseño orientados a objetos
Clase singleton: mediante el constructor estático
Figura 141: Clase singleton: mediante el constructor estático
La clase utiliza su constructor estático para crear de antemano la instancia individual. El método GET_INSTANCE no crea la instancia, solo devuelve una referencia a la instancia ya existente. Consejo: En una tercera variante de un patrón singleton, el atributo estático GO_INSTANCE se hace público y de solo lectura. El método GET_INSTANCE no es obligatorio.
348
© Copyright . Reservados todos los derechos.
Capítulo 8 Ejercicio 21 Implementar el patrón singleton
Ejemplo empresarial Para mejorar la solidez de su aplicación, es necesario crear dos tipos de aviones (de pasajeros y de carga) e implementarlos como clases finales para que no se especialicen. Solo los se crean aviones específicos, y la agencia de viajes solo puede instanciarse una vez. Modelo: SAPBC401_GCL_S2 Solución: SAPBC401_SPC_S1 Tarea 1 Utilice las técnicas de los objetos ABAP para evitar la especialización adicional de los aviones de pasajeros y de carga. 1. Complete su programa ZBC401_##_MAIN o copie el programa modelo. 2. Declare las clases LCL_PASSENGER_PLANE y LCL_CARGO_PLANE como clases FINAL. 3. ¿Qué sucede si declara la clase LCL_AIRPLANE como FINAL?
4. ¿Qué sucedería si solo declara el método DISPLAY_ATTRIBUTES de la clase LCL_AIRPLANE un método final?
Tarea 2 Utilice las técnicas de objetos ABAP para inhibir la instanciación de la clase LCL_AIRPLANE. 1. Declare LCL_AIRPLANE como una clase abstracta. 2. Demuestre que no está permitido instanciar la clase en sí. En su programa principal, declare la variable de referencia TYPE REF TO lcl_airplane e implemente una sentencia CREATE OBJECT para esta. Después de la verificación de sintaxis, elimine la sentencia CREATE OBJECT. Tarea 3 Asegúrese de que la clase LCL_TRAVEL_AGENCY solo pueda instanciarse una vez en su programa. Implemente uno de los patrones singleton analizados en el curso.
© Copyright . Reservados todos los derechos.
349
Capítulo 8: Patrones de diseño orientados a objetos
1. Restrinja la visibilidad del constructor de instancia e inhiba cualquier herencia de la clase. 2. Defina un atributo estático para almacenar allí una referencia a la instancia determinada. Según el patrón que implemente, hágalo privado o público y sólo de lectura. 3. Según el patrón que implemente, defina e implemente un constructor estático o un método GET_INSTANCE. Implemente la instanciación de la clase según el patrón singleton. 4. Ajuste el programa principal. Elimine la sentencia CREATE OBJECT para la agencia de viajes desde el programa principal. Según el patrón singleton que implementó, reemplácelo con una llamada al método GET_INSTANCE o con un acceso al atributo público. 5. Opcional: si ha implementado un patrón que incluye un método GET_INSTANCE, utilice una cadena de método para recuperar la instancia singleton y llamar a su método DISPLAY_ATTRIBUTE en una sentencia.
350
© Copyright . Reservados todos los derechos.
Capítulo 8 Solución 21 Implementar el patrón singleton
Ejemplo empresarial Para mejorar la solidez de su aplicación, es necesario crear dos tipos de aviones (de pasajeros y de carga) e implementarlos como clases finales para que no se especialicen. Solo los se crean aviones específicos, y la agencia de viajes solo puede instanciarse una vez. Modelo: SAPBC401_GCL_S2 Solución: SAPBC401_SPC_S1 Tarea 1 Utilice las técnicas de los objetos ABAP para evitar la especialización adicional de los aviones de pasajeros y de carga. 1. Complete su programa ZBC401_##_MAIN o copie el programa modelo. a) Realice este paso de la forma habitual. Encontrará información adicional en la biblioteca SAP. 2. Declare las clases LCL_PASSENGER_PLANE y LCL_CARGO_PLANE como clases FINAL. a) Véase el extracto del código fuente de la solución modelo. 3. ¿Qué sucede si declara la clase LCL_AIRPLANE como FINAL? Esto produce un error de sintaxis, ya que las clases LCL_CARGO_PLANE y LCL_PASSENGER_PLANE ya heredaron de esta clase. 4. ¿Qué sucedería si solo declara el método DISPLAY_ATTRIBUTES de la clase LCL_AIRPLANE un método final? Esto produce un error de sintaxis, ya que el método ya está redefinido en las clases LCL_CARGO_PLANE y LCL_PASSENGER_PLANE.
Tarea 2 Utilice las técnicas de objetos ABAP para inhibir la instanciación de la clase LCL_AIRPLANE. 1. Declare LCL_AIRPLANE como una clase abstracta. a) Véase el extracto del código fuente de la solución modelo. 2. Demuestre que no está permitido instanciar la clase en sí. En su programa principal, declare la variable de referencia TYPE REF TO lcl_airplane e implemente una sentencia CREATE OBJECT para esta. Después de la verificación de sintaxis, elimine la sentencia CREATE OBJECT.
© Copyright . Reservados todos los derechos.
351
Capítulo 8: Patrones de diseño orientados a objetos
a) Realice este paso de la forma habitual. Tarea 3 Asegúrese de que la clase LCL_TRAVEL_AGENCY solo pueda instanciarse una vez en su programa. Implemente uno de los patrones singleton analizados en el curso. 1. Restrinja la visibilidad del constructor de instancia e inhiba cualquier herencia de la clase. a) Utilice los suplementos FINAL y CREATE PRIVATE para la sentencia CLASS... DEFINITION. Opcionalmente, traslade la definición del constructor de instancia a la sección privada. Véase el extracto del código fuente de la solución modelo. 2. Defina un atributo estático para almacenar allí una referencia a la instancia determinada. Según el patrón que implemente, hágalo privado o público y sólo de lectura. a) Véase el extracto del código fuente de la solución modelo. 3. Según el patrón que implemente, defina e implemente un constructor estático o un método GET_INSTANCE. Implemente la instanciación de la clase según el patrón singleton. a) Véase el extracto del código fuente de la solución modelo. 4. Ajuste el programa principal. Elimine la sentencia CREATE OBJECT para la agencia de viajes desde el programa principal. Según el patrón singleton que implementó, reemplácelo con una llamada al método GET_INSTANCE o con un acceso al atributo público. a) Véase el extracto del código fuente de la solución modelo. 5. Opcional: si ha implementado un patrón que incluye un método GET_INSTANCE, utilice una cadena de método para recuperar la instancia singleton y llamar a su método DISPLAY_ATTRIBUTE en una sentencia. a) Véase el extracto del código fuente de la solución modelo. Include BC401_SPC_S1_CARRIER *------------------------------------------------* * CLASS lcl_airplane DEFINITION *------------------------------------------------* CLASS lcl_airplane DEFINITION ABSTRACT. ... ENDCLASS. "lcl_airplane DEFINITION *------------------------------------------------* * CLASS lcl_airplane IMPLEMENTATION *------------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. ... ENDCLASS. "lcl_airplane IMPLEMENTATION *------------------------------------------------* * CLASS lcl_cargo_plane DEFINITION *------------------------------------------------* CLASS lcl_cargo_plane DEFINITION INHERITING FROM lcl_airplane FINAL. ... ENDCLASS. "lcl_cargo_plane DEFINITION *------------------------------------------------* * CLASS lcl_cargo_plane IMPLEMENTATION
352
© Copyright . Reservados todos los derechos.
Lección: Implementación del patrón singleton
*------------------------------------------------* CLASS lcl_cargo_plane IMPLEMENTATION. ... ENDCLASS. "lcl_cargo_plane IMPLEMENTATION *------------------------------------------------* * CLASS lcl_passenger_plane DEFINITION *------------------------------------------------* CLASS lcl_passenger_plane DEFINITION INHERITING FROM lcl_airplane FINAL. ... ENDCLASS. "lcl_passenger_plane DEFINITION *------------------------------------------------* * CLASS lcl_passenger_plane IMPLEMENTATION *------------------------------------------------* CLASS lcl_passenger_plane IMPLEMENTATION. ... ENDCLASS. "lcl_passenger_plane IMPLEMENTATION Include BC401_SPC_S1_AGENCY *-------------------------------------------------* * CLASS lcl_travel_agency DEFINITION *-------------------------------------------------* CLASS lcl_travel_agency DEFINITION FINAL CREATE PRIVATE. PUBLIC SECTION. CLASS-METHODS: get_instance RETURNING value(ro_instance) TYPE REF TO lcl_travel_agency. METHODS: display_agency_partners, display_attributes. PRIVATE SECTION. DATA: mv_name TYPE string, mt_partners TYPE TABLE OF REF TO if_partner. CLASS-DATA: go_instance TYPE REF TO lcl_travel_agency. METHODS: constructor IMPORTING iv_name TYPE string. METHODS: on_partner_created FOR EVENT partner_created OF if_partner IMPORTING sender. ENDCLASS.
"lcl_travel_agency DEFINITION
*---------------------------------------------------* * CLASS lcl_travel_agency IMPLEMENTATION *---------------------------------------------------* CLASS lcl_travel_agency IMPLEMENTATION.
© Copyright . Reservados todos los derechos.
353
Capítulo 8: Patrones de diseño orientados a objetos
METHOD get_instance. IF go_instance IS NOT BOUND. CREATE OBJECT go_instance EXPORTING iv_name = 'Travel&Smile Travel'. ENDIF. ro_instance = go_instance. ENDMETHOD. "get_instance METHOD display_attributes. WRITE: / icon_private_files AS ICON, 'Travel Agency:'(007), mv_name. SKIP. display_agency_partners( ). ENDMETHOD. "display_attributes METHOD display_agency_partners. DATA: lo_partner TYPE REF TO if_partner. WRITE 'Here are the partners of the travel agency:'(008). ULINE. LOOP AT mt_partners INTO lo_partner. lo_partner->display_partner( ). ENDLOOP. ENDMETHOD. "display_agency_partners METHOD constructor. mv_name = iv_name. SET HANDLER on_partner_created FOR ALL INSTANCES. ENDMETHOD. "constructor METHOD on_partner_created. APPEND sender TO mt_partners. ENDMETHOD. "on_partner_created ENDCLASS. Programa principal SAPBC401_SPC_S1 REPORT
sapbc401_spc_s1.
TYPE-POOLS icon. INCLUDE bc401_spc_s1_agency. INCLUDE bc401_spc_s1_carrier. INCLUDE bc401_spc_s1_rental. DATA: go_hotel go_agency go_vehicle go_truck go_bus go_rental go_passenger go_cargo go_carrier
TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE
REF REF REF REF REF REF REF REF REF
TO TO TO TO TO TO TO TO TO
cl_hotel2, lcl_travel_agency, lcl_vehicle, lcl_truck, lcl_bus, lcl_rental, lcl_passenger_plane, lcl_cargo_plane, lcl_carrier.
START-OF-SELECTION. *******************
354
© Copyright . Reservados todos los derechos.
Lección: Implementación del patrón singleton
******* create travel_agency *********************** * CREATE OBJECT go_agency * EXPORTING * iv_name = 'Travel&Smile Travel'. go_agency = lcl_travel_agency=>get_instance( ). ******* create hotel ******************************* CREATE OBJECT go_hotel EXPORTING iv_name = 'Sleep Well Hotel' iv_beds = 345. ******* create rental ******************************* CREATE OBJECT go_rental EXPORTING iv_name = 'Happy Car Rental'. ******* create truck ********************************* CREATE OBJECT go_truck EXPORTING iv_make = 'MAN' iv_cargo = 45. ******* create truck ********************************* CREATE OBJECT go_bus EXPORTING iv_make = 'Mercedes' iv_passengers = 80. ******* create truck ********************************* CREATE OBJECT go_truck EXPORTING iv_make = 'VOLVO' iv_cargo = 48. ***** Create Carrier ********************************* CREATE OBJECT go_carrier EXPORTING iv_name = 'Smile&Fly Travel'. ***** Passenger Plane ******************************** CREATE OBJECT go_passenger EXPORTING iv_name = 'LH BERLIN' iv_planetype = '747-400' iv_seats = 345 EXCEPTIONS wrong_planetype = 1. IF sy-subrc <> 0. WRITE: / icon_failure AS ICON, 'Wrong plane type'. ENDIF. ***** cargo Plane ************************************ CREATE OBJECT go_cargo EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' iv_cargo = 533
© Copyright . Reservados todos los derechos.
355
Capítulo 8: Patrones de diseño orientados a objetos
EXCEPTIONS wrong_planetype = 1. IF sy-subrc <> 0. WRITE: / icon_failure AS ICON, 'Wrong plane type'. ENDIF. ***** show attributes of all partners of travel_agency go_agency->display_attributes( ). * Optional part: Use method chain: * * lcl_travel_agency=>get_instance( )->display_attributes( ).
356
© Copyright . Reservados todos los derechos.
Lección: Implementación del patrón singleton
RESUMEN DE LA LECCIÓN Ahora podrá: ●
Implementar métodos factory
●
Implementar el patrón singleton
© Copyright . Reservados todos los derechos.
357
Capítulo 8 Lección 3 Implementación de clases factory mediante amistad
RESUMEN DE LA LECCIÓN Este módulo explica el método de implementación de clases factory con la amistad. Ejemplo empresarial Como desarrollador, cree una clase factory de clases para aviones utilizando la amistad. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de la definición de relaciones de amistad
●
Una buena comprensión de la amistad y la herencia
●
Una buena comprensión de la implementación de clases factory
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Implementar relaciones de amistad
Definición de relaciones de amistad
Figura 142: Definición de una relación de amistad entre clases
En algunos casos, las clases tienen que trabajar tan estrechamente que una clase necesita acceder a los componentes protegidos y privados de otras clases. Del mismo modo, es posible que una clase pueda crear instancias de otras clases sin importar la visibilidad del
358
© Copyright . Reservados todos los derechos.
Lección: Implementación de clases factory mediante amistad
constructor. Para evitar que estas opciones estén disponibles para todos los usuarios de la clase, utilice el concepto de clase de amistad. Una clase puede garantizar amistad a otras clases e interfaces y, por lo tanto, a todas las clases que implementen la interfaz. Para crear la amistad, utilice el suplemento FRIENDS de la sentencia CLASS o la etiqueta FRIENDS en el generador de clases. Todas las clases e interfaces a las que se garantice amistad están enumeradas en este lugar. La garantía de amistad es unilateral. Una clase que garantice una amistad no es automáticamente una amiga de los amigos de la clase. Si una clase que garantiza amistad quiere acceder a los componentes que no son públicos de un amigo, este amigo debe garantizarle su amistad explícitamente.
Implementación de clases factory
Figura 143: Ejemplo de una clase factory
Una aplicación típica del concepto de amigos es la definición de una clase factory. Al igual que el método factory, una clase factory crea y administra las instancias de una clase. Al subcontratar la administración para una clase dedicada, la clase en sí se mantiene más pequeña y fácil de comprender. En el ejemplo, LCL_FACTORY funciona como una clase factory para los aviones. La clase LCL_FACTORY proporciona el método público CREATE_AIRPLANE en el que CREATE_AIRPLANE instancia la clase LCL_AIRPLANE o devuelve una referencia a una instancia existente. Para restringir la instanciación, la clase LCL_AIRPLANE se define con el suplemento CREATE PRIVATE. Al añadir FRIENDS LCL_FACTORY, la amistad permite que únicamente la clase factory pueda crear instancias de aviones y acceder a los atributos privados.
© Copyright . Reservados todos los derechos.
359
Capítulo 8: Patrones de diseño orientados a objetos
Consejo: Otra ventaja de la clase factory dedicada es que, si la clase tiene subclases, la decisión respecto a cuál de las clases debe instanciarse podría realizarse dentro de la clase factory en lugar del programa de llamada. En el ejemplo, el método CREATE_AIRPLANE puede crear y devolver una instancia de LCL_CARGO_PLANE o LCL_PASSENGER_PLANE según el tipo de avión.
Amistad y herencia El atributo de amigo es heredado. Las clases que heredan de amigos y las interfaces que contienen un amigo, como una interfaz de componente, también se convierten en amigos. Por lo tanto, se recomienda tener mucho cuidado cuando se garantiza una amistad. Cuanto más arriba esté un amigo en el árbol de herencia, más subclases podrán acceder a todos los componentes de una clase que garantiza amistad. Por el contrario, la garantía de amistad no se hereda. Por lo tanto, un amigo de una clase superior no es automáticamente amigo de sus subclases.
360
© Copyright . Reservados todos los derechos.
Capítulo 8 Ejercicio 22 Implementar una clase factory mediante amistad
Ejemplo empresarial En lugar de instanciar directamente objetos de avión en el programa principal, cree aviones utilizando una clase factory. La clase factory debe proporcionar un método factory individual. Según la entrada, la clase factory decide dentro del método factory si se creará un avión de carga o un avión de pasajeros. Modelo: SAPBC401_SPC_S1 Solución: SAPBC401_ SPC_S2 Tarea 1 En su programa, defina una clase factory (nombre propuesto: LCL_AIRPLANE_FACTORY) con un método factory público y estático para aviones (nombre sugerido: CREATE_AIRPLANE). El método factory debe tener parámetros tipificados correctamente para el nombre, el tipo de avión, la carga y los asientos. El método factory puede ser opcional para los parámetros de importación carga y asientos. También debe tener un parámetro de retorno individual para devolver una referencia a una instancia de avión: un avión de carga o de pasajeros. 1. Complete el programa ZBC401_##_MAIN (## es el número de grupo de dos cifras) o copie el programa modelo. 2. Trate el include que contiene las clases de los aviones. Allí añada la definición de la nueva clase. 3. Dentro de la clase, defina un método factory público y estático para aviones. Defina cuatro parámetros de importación para el nombre, el tipo de avión, la carga y los asientos. Nómbrelos y tipifíquelos de manera exacta en los constructores de sus clases de aviones. Haga que los parámetros para la carga y los asientos sean opcionales. Consejo: Utilice el suplemento OPTIONAL para hacerlo.
4. Defina un parámetro de retorno (nombre propuesto: RO_AIRPLANE). ¿Cómo debe tipificar los parámetros para que el método pueda devolver una referencia a una instancia de avión de carga o a una instancia de avión de pasajeros?
© Copyright . Reservados todos los derechos.
361
Capítulo 8: Patrones de diseño orientados a objetos
Tarea 2 Implemente el método factory. Según el parámetro opcional proporcionado, cree una instancia de avión de carga o una instancia de avión de pasajeros. Defina una excepción adecuada y emítala si se suministran ambos parámetros opcionales o no se suministra ninguno. 1. En el método factory, defina dos variables de referencia locales. Tipifique una con la clase para aviones de carga (LCL_CARGO_PLANE) y una con la clase para aviones de pasajeros (LCL_PASSENGER_PLANE). 2. Implemente una estructura IF en la que analice el contenido de los parámetros de importación para la carga y los asientos. Cree una instancia de la clase de avión de carga o de la clase de avión de pasajeros. Si la operación es exitosa, mueva la referencia al nuevo objeto del parámetro de retorno. 3. En la definición de la clase factory, añada dos excepciones. Una que emita si se especificó un tipo de avión incorrecto (nombre sugerido: WRONG_PLANETYPE) y otra que emita si se suministraron ambos parámetros opcionales o ninguno (nombre sugerido: WRONG_PARAM_COMBINATION). Tarea 3 Restrinja la creación de aviones de carga y de aviones de pasajeros para que sólo puedan crearse desde dentro de la clase factory. 1. Utilice el suplemento CREATE PRIVATE para restringir la instanciación de las clases para aviones de carga y aviones de pasajeros. Opcionalmente, mueva las definiciones de constructor de ambas clases para la sección privada. 2. Utilice el suplemento FRIENDS para permitir la instanciación de las clases para los aviones de carga y los aviones de pasajeros desde dentro de la clase factory. Consejo: Debe utilizar la sentencia CLASS... DEFINITION DEFERRED. antes de la definición de clases de avión. De lo contrario, la clase factory o, al menos, su nombre no será reconocido por la verificación de sintaxis cuando alcance el suplemento FRIENDS.
Tarea 4 Ajuste el programa principal. Elimine las instanciaciones directas de los aviones y reemplácelos por llamadas al método factory. 1. Reemplace las instanciaciones de aviones con llamadas al método factory. Consejo: Si ha utilizado exactamente los mismos nombres de parámetros que en los constructores, puede mantener el paso del parámetro.
362
© Copyright . Reservados todos los derechos.
Lección: Implementación de clases factory mediante amistad
2. ¿Debe recibir realmente las referencias a los nuevos objetos?
3. Active, realice un test y depure su programa.
© Copyright . Reservados todos los derechos.
363
Capítulo 8 Solución 22 Implementar una clase factory mediante amistad
Ejemplo empresarial En lugar de instanciar directamente objetos de avión en el programa principal, cree aviones utilizando una clase factory. La clase factory debe proporcionar un método factory individual. Según la entrada, la clase factory decide dentro del método factory si se creará un avión de carga o un avión de pasajeros. Modelo: SAPBC401_SPC_S1 Solución: SAPBC401_ SPC_S2 Tarea 1 En su programa, defina una clase factory (nombre propuesto: LCL_AIRPLANE_FACTORY) con un método factory público y estático para aviones (nombre sugerido: CREATE_AIRPLANE). El método factory debe tener parámetros tipificados correctamente para el nombre, el tipo de avión, la carga y los asientos. El método factory puede ser opcional para los parámetros de importación carga y asientos. También debe tener un parámetro de retorno individual para devolver una referencia a una instancia de avión: un avión de carga o de pasajeros. 1. Complete el programa ZBC401_##_MAIN (## es el número de grupo de dos cifras) o copie el programa modelo. a) Realice este paso de la forma habitual. Para más información, consulte la biblioteca SAP. 2. Trate el include que contiene las clases de los aviones. Allí añada la definición de la nueva clase. a) Consulte el extracto de código fuente de la solución modelo. 3. Dentro de la clase, defina un método factory público y estático para aviones. Defina cuatro parámetros de importación para el nombre, el tipo de avión, la carga y los asientos. Nómbrelos y tipifíquelos de manera exacta en los constructores de sus clases de aviones. Haga que los parámetros para la carga y los asientos sean opcionales. Consejo: Utilice el suplemento OPTIONAL para hacerlo.
364
© Copyright . Reservados todos los derechos.
Lección: Implementación de clases factory mediante amistad
a) Consulte el extracto de código fuente de la solución modelo. 4. Defina un parámetro de retorno (nombre propuesto: RO_AIRPLANE). ¿Cómo debe tipificar los parámetros para que el método pueda devolver una referencia a una instancia de avión de carga o a una instancia de avión de pasajeros? a) Debe indicar el parámetro con la clase superior común de los aviones de carga y de pasajeros, es decir TYPE REF TO lcl_airplane. Consulte el extracto de código fuente de la solución modelo.
Tarea 2 Implemente el método factory. Según el parámetro opcional proporcionado, cree una instancia de avión de carga o una instancia de avión de pasajeros. Defina una excepción adecuada y emítala si se suministran ambos parámetros opcionales o no se suministra ninguno. 1. En el método factory, defina dos variables de referencia locales. Tipifique una con la clase para aviones de carga (LCL_CARGO_PLANE) y una con la clase para aviones de pasajeros (LCL_PASSENGER_PLANE). a) Consulte el extracto de código fuente de la solución modelo. 2. Implemente una estructura IF en la que analice el contenido de los parámetros de importación para la carga y los asientos. Cree una instancia de la clase de avión de carga o de la clase de avión de pasajeros. Si la operación es exitosa, mueva la referencia al nuevo objeto del parámetro de retorno. a) Consulte el extracto de código fuente de la solución modelo. 3. En la definición de la clase factory, añada dos excepciones. Una que emita si se especificó un tipo de avión incorrecto (nombre sugerido: WRONG_PLANETYPE) y otra que emita si se suministraron ambos parámetros opcionales o ninguno (nombre sugerido: WRONG_PARAM_COMBINATION). a) Consulte el extracto de código fuente de la solución modelo. Tarea 3 Restrinja la creación de aviones de carga y de aviones de pasajeros para que sólo puedan crearse desde dentro de la clase factory. 1. Utilice el suplemento CREATE PRIVATE para restringir la instanciación de las clases para aviones de carga y aviones de pasajeros. Opcionalmente, mueva las definiciones de constructor de ambas clases para la sección privada. a) Consulte el extracto de código fuente de la solución modelo. 2. Utilice el suplemento FRIENDS para permitir la instanciación de las clases para los aviones de carga y los aviones de pasajeros desde dentro de la clase factory. Consejo: Debe utilizar la sentencia CLASS... DEFINITION DEFERRED. antes de la definición de clases de avión. De lo contrario, la clase factory o, al menos, su nombre no será reconocido por la verificación de sintaxis cuando alcance el suplemento FRIENDS.
© Copyright . Reservados todos los derechos.
365
Capítulo 8: Patrones de diseño orientados a objetos
a) Consulte el extracto de código fuente de la solución modelo. Tarea 4 Ajuste el programa principal. Elimine las instanciaciones directas de los aviones y reemplácelos por llamadas al método factory. 1. Reemplace las instanciaciones de aviones con llamadas al método factory. Consejo: Si ha utilizado exactamente los mismos nombres de parámetros que en los constructores, puede mantener el paso del parámetro. a) Consulte el extracto de código fuente de la solución modelo. 2. ¿Debe recibir realmente las referencias a los nuevos objetos? No. Mediante la gestión de mensajes implementada anteriormente, la instancia de compañía aérea se encarga de todas las nuevas instancias de aviones y las añade. 3. Active, realice un test y depure su programa. a) Realice este paso de la forma habitual. Para más información, consulte la biblioteca SAP. Include BC401_SPC_S2_CARRIER CLASS lcl_airplane_factory DEFINITION DEFERRED. *----------------------------------------------------* * CLASS lcl_airplane DEFINITION * *----------------------------------------------------* CLASS lcl_airplane DEFINITION ABSTRACT. ... ENDCLASS. "lcl_airplane DEFINITION *-----------------------------------------------------* * CLASS lcl_airplane IMPLEMENTATION * *-----------------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. ... ENDCLASS. "lcl_airplane IMPLEMENTATION *-----------------------------------------------------* * CLASS lcl_cargo_plane DEFINITION *-----------------------------------------------------* * *-----------------------------------------------------* CLASS lcl_cargo_plane DEFINITION INHERITING FROM lcl_airplane FINAL CREATE PRIVATE FRIENDS lcl_airplane_factory.
366
© Copyright . Reservados todos los derechos.
Lección: Implementación de clases factory mediante amistad
... ENDCLASS. "lcl_cargo_plane DEFINITION *-----------------------------------------------------* * CLASS lcl_cargo_plane IMPLEMENTATION *-----------------------------------------------------* CLASS lcl_cargo_plane IMPLEMENTATION. ... ENDCLASS. "lcl_cargo_plane IMPLEMENTATION *-----------------------------------------------------* * CLASS lcl_passenger_plane DEFINITION *-----------------------------------------------------* CLASS lcl_passenger_plane DEFINITION INHERITING FROM lcl_airplane FINAL CREATE PRIVATE FRIENDS lcl_airplane_factory. ... ENDCLASS. "lcl_passenger_plane DEFINITION *---------------------------------------------------* * CLASS lcl_passenger_plane IMPLEMENTATION *---------------------------------------------------* CLASS lcl_passenger_plane IMPLEMENTATION. ... ENDCLASS. "lcl_passenger_plane IMPLEMENTATION *--------------------------------------------------* * CLASS lcl_carrier DEFINITION *--------------------------------------------------* CLASS lcl_carrier DEFINITION. ... ENDCLASS. "lcl_carrier DEFINITION *--------------------------------------------------* * CLASS lcl_carrier IMPLEMENTATION *--------------------------------------------------* CLASS lcl_carrier IMPLEMENTATION. ... ENDCLASS.
"lcl_carrier IMPLEMENTATION
*--------------------------------------------------* * CLASS lcl_airplane_factory DEFINITION *--------------------------------------------------* CLASS lcl_airplane_factory DEFINITION. PUBLIC SECTION. CLASS-METHODS: create_airplane IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype iv_cargo TYPE s_plan_car OPTIONAL
© Copyright . Reservados todos los derechos.
367
Capítulo 8: Patrones de diseño orientados a objetos
iv_seats TYPE s_seatsmax OPTIONAL RETURNING value(ro_airplane) TYPE REF TO lcl_airplane EXCEPTIONS wrong_planetype wrong_param_combination. ENDCLASS. "lcl_airplane_factory DEFINITION *--------------------------------------------------* * CLASS lcl_airplane_factory IMPLEMENTATION *--------------------------------------------------* CLASS lcl_airplane_factory IMPLEMENTATION. METHOD create_airplane. DATA: lo_cargo TYPE REF TO lcl_cargo_plane, lo_passenger TYPE REF TO lcl_passenger_plane. IF iv_cargo IS NOT INITIAL AND iv_seats IS INITIAL. CREATE OBJECT lo_cargo EXPORTING iv_name = iv_name iv_planetype = iv_planetype iv_cargo = iv_cargo EXCEPTIONS wrong_planetype = 1. IF sy-subrc <> 0. RAISE wrong_planetype. ELSE. ro_airplane = lo_cargo. ENDIF. ELSEIF iv_cargo IS INITIAL AND iv_seats IS NOT INITIAL. CREATE OBJECT lo_passenger EXPORTING iv_name = iv_name iv_planetype = iv_planetype iv_seats = iv_seats EXCEPTIONS wrong_planetype = 1. IF sy-subrc <> 0. RAISE wrong_planetype. ELSE. ro_airplane = lo_passenger. ENDIF. ELSE. RAISE wrong_param_combination. ENDIF. ENDMETHOD. ENDCLASS.
"create_airplane "lcl_airplane_factory IMPLEMENTATION
SAPBC401_SPC_S2 REPORT
sapbc401_spc_s2.
TYPE-POOLS icon.
368
© Copyright . Reservados todos los derechos.
Lección: Implementación de clases factory mediante amistad
INCLUDE bc401_spc_s2_agency. INCLUDE bc401_spc_s2_carrier. INCLUDE bc401_spc_s2_rental. DATA: go_agency TYPE REF TO lcl_travel_agency, go_hotel TYPE REF TO cl_hotel2, go_vehicle TYPE REF TO lcl_vehicle, go_truck TYPE REF TO lcl_truck, go_bus TYPE REF TO lcl_bus, go_rental TYPE REF TO lcl_rental, *go_passenger TYPE REF TO lcl_passenger_plane, *go_cargo TYPE REF TO lcl_cargo_plane, go_carrier TYPE REF TO lcl_carrier. START-OF-SELECTION. ******************* ******* create travel_agency *********************** * CREATE OBJECT go_agency * EXPORTING * iv_name = 'Travel&Smile Travel'. go_agency = lcl_travel_agency=>get_instance( ). ******* create hotel ******************************* CREATE OBJECT go_hotel EXPORTING iv_name = 'Sleep Well Hotel' iv_beds = 345. ******* create rental ****************************** CREATE OBJECT go_rental EXPORTING iv_name = 'Happy Car Rental'. ******* create truck ******************************* CREATE OBJECT go_truck EXPORTING iv_make = 'MAN' iv_cargo = 45. ******* create truck ******************************* CREATE OBJECT go_bus EXPORTING iv_make = 'Mercedes' iv_passengers = 80. ******* create truck ******************************* CREATE OBJECT go_truck EXPORTING iv_make = 'VOLVO' iv_cargo = 48. ***** Create Carrier ******************************* CREATE OBJECT go_carrier EXPORTING iv_name = 'Smile&Fly-Travel'. ***** Passenger Plane ****************************** lcl_airplane_factory=>create_airplane( EXPORTING
© Copyright . Reservados todos los derechos.
369
Capítulo 8: Patrones de diseño orientados a objetos
iv_name = 'LH BERLIN' iv_planetype = '747-400' iv_seats = 345 EXCEPTIONS wrong_planetype = 1 wrong_param_combination = 2 ). IF sy-subrc = 1. WRITE: / icon_failure AS ICON, 'Wrong plane type'. ENDIF. ***** cargo Plane ********************************** lcl_airplane_factory=>create_airplane( EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' iv_cargo = 533 EXCEPTIONS wrong_planetype = 1 wrong_param_combination = 2 ). IF sy-subrc = 1. WRITE: / icon_failure AS ICON, 'Wrong plane type'. ENDIF. ***** show attributes of all partners of travel_agency go_agency->display_attributes( ).
370
© Copyright . Reservados todos los derechos.
Lección: Implementación de clases factory mediante amistad
RESUMEN DE LA LECCIÓN Ahora podrá: ●
Implementar relaciones de amistad
© Copyright . Reservados todos los derechos.
371
Capítulo 8: Patrones de diseño orientados a objetos
372
© Copyright . Reservados todos los derechos.
Capítulo 8 Evaluación de la formación
1. Los _____________ estáticos no pueden ser abstractos porque no pueden redefinirse. Seleccione la respuesta correcta. X
A clases
X
B estructuras
X
C métodos
X
D atributos
2. Es posible impedir que una clase sea heredada utilizando el suplemento Final con la sentencia de clase. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
3. Una asociación significa que, en tiempo de ejecución, una instancia de una clase almacena referencias a objetos de otra clase. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
4. Si la visibilidad del constructor de instancia se modifica de privado a protegido, la visibilidad se extiende a todas sus subclases. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
373
Capítulo 8: Evaluación de la formación
5. De las siguientes opciones, ¿cuáles son las ventajas del método factory? Seleccione las respuestas correctas. X
A Un método factory puede tener una codificación que se ejecuta antes de la instanciación real.
X
B Una clase puede tener más de un método factory con distinta implementación y firma.
X
C Los métodos factory no pueden utilizarse para administrar las instancias de una clase dentro de la misma clase.
X
D Un método factory no puede utilizarse para instanciar una de las subclases en lugar de la clase misma.
6. De las siguientes opciones, ¿cuál se realiza con el concepto de singleton? Seleccione las respuestas correctas. X
A Evitar que una clase se instancie más de una vez para el mismo contexto del programa.
X
B Limitar la visibilidad del constructor de instancia.
X
C Mantener una referencia a todas las instancias en un atributo estático
X
D Almacenar solo una instancia en lugar de varias
7. De los siguientes conceptos, ¿cuál se utiliza para proporcionar un acceso de clase a los componentes privados de otra clase? Seleccione la respuesta correcta.
374
X
A Singleton
X
B Amistad
X
C Interfaz
X
D Casting
© Copyright . Reservados todos los derechos.
Capítulo 8 Respuestas a la Evaluación de la formación
1. Los _____________ estáticos no pueden ser abstractos porque no pueden redefinirse. Seleccione la respuesta correcta. X
A clases
X
B estructuras
X
C métodos
X
D atributos
2. Es posible impedir que una clase sea heredada utilizando el suplemento Final con la sentencia de clase. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
3. Una asociación significa que, en tiempo de ejecución, una instancia de una clase almacena referencias a objetos de otra clase. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
4. Si la visibilidad del constructor de instancia se modifica de privado a protegido, la visibilidad se extiende a todas sus subclases. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
375
Capítulo 8: Respuestas a la Evaluación de la formación
5. De las siguientes opciones, ¿cuáles son las ventajas del método factory? Seleccione las respuestas correctas. X
A Un método factory puede tener una codificación que se ejecuta antes de la instanciación real.
X
B Una clase puede tener más de un método factory con distinta implementación y firma.
X
C Los métodos factory no pueden utilizarse para administrar las instancias de una clase dentro de la misma clase.
X
D Un método factory no puede utilizarse para instanciar una de las subclases en lugar de la clase misma.
6. De las siguientes opciones, ¿cuál se realiza con el concepto de singleton? Seleccione las respuestas correctas. X
A Evitar que una clase se instancie más de una vez para el mismo contexto del programa.
X
B Limitar la visibilidad del constructor de instancia.
X
C Mantener una referencia a todas las instancias en un atributo estático
X
D Almacenar solo una instancia en lugar de varias
7. De los siguientes conceptos, ¿cuál se utiliza para proporcionar un acceso de clase a los componentes privados de otra clase? Seleccione la respuesta correcta.
376
X
A Singleton
X
B Amistad
X
C Interfaz
X
D Casting
© Copyright . Reservados todos los derechos.
CAPÍTULO 9
Tratamiento de excepciones orientadas a objetos
Lección 1 Explicación de las excepciones basadas en clases
378
Lección 2 Definición y emisión de excepciones Ejercicio 23: Implementar las excepciones basadas en clases
384 391
Lección 3 Implementación de técnicas avanzadas de tratamiento de excepciones Ejercicio 24: Asignar excepciones unas a otras
405 413
OBJETIVOS DEL CAPÍTULO ●
Explicar excepciones basadas en clases
●
Tratar excepciones basadas en clases
●
Depurar excepciones basadas en clases
●
Definir clases de excepción globales
●
Emitir excepciones basadas en clases
●
Propagar excepciones
●
Explicar la jerarquía de las clases de excepción predefinidas
●
Explicar las distintas formas de tratar una excepción
●
Reintentar después de las excepciones
●
Implementar excepciones reanudables
●
Volver a emitir las excepciones
●
Asignar excepciones unas a otras
© Copyright . Reservados todos los derechos.
377
Capítulo 9 Lección 1 Explicación de las excepciones basadas en clases
RESUMEN DE LA LECCIÓN Este módulo explica cómo tratar y depurar excepciones basadas en clases. Ejemplo empresarial Debe utilizar el nuevo concepto de excepciones en sus programas de objetos ABAP. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de las excepciones basadas en clases
●
Una buena comprensión de cómo tratar las excepciones basadas en clases
●
Una buena comprensión de cómo depurar las excepciones basadas en clases
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Explicar excepciones basadas en clases
●
Tratar excepciones basadas en clases
●
Depurar excepciones basadas en clases
Excepciones basadas en clases Una excepción es una situación que surge cuando un programa se ejecuta y durante la cual no es posible continuar el flujo normal del programa. SAP Web AS 6.10 presentó un nuevo concepto de excepción de objetos ABAP de manera paralela al concepto existente basado en sy-subrc. Las excepciones y el tratamiento de excepciones se basan ahora en clases. Este nuevo concepto de excepción de objetos ABAP amplió la manera clásica de tratar excepciones con sy-subrc.
Consejo: Tenga en cuenta que el uso de excepciones basadas en clases no está limitado a contextos orientados a objetos. Las excepciones basadas en objetos pueden emitirse y tratarse en todos los bloques de procesamiento. En particular, todos los errores de tiempo de ejecución interceptables anteriormente pueden tratarse como excepciones basadas en clases.
378
© Copyright . Reservados todos los derechos.
Lección: Explicación de las excepciones basadas en clases
Figura 144: Un resumen del concepto de excepción basado en clases
En el nuevo concepto, una excepción se representa con un objeto de excepción. Un objeto de excepción es una instancia de una clase de excepción. Los valores de atributo del objeto de excepción contienen información sobre la situación de error correspondiente. La emisión de una excepción basada en clases normalmente significa instanciar una clase de excepción y fijar los atributos. La gestión de una excepción basada en clases implica la evaluación del objeto de excepción y sus valores de atributo. Las excepciones basadas en clases se emiten por parte de la sentencia RAISE EXCEPTION o por parte del entorno de tiempo de ejecución. Intercepta y trata las excepciones basadas en clases con la estructura TRY...CATCH...ENDTRY.
Jerarquía de las clases de excepciones
Figura 145: Clases de excepciones: la jerarquía de herencia
Puede definir sus propias clases de excepción, pero el sistema ya incluye un rango de clases de excepción predefinidas, particularmente para las excepciones en el entorno del tiempo de
© Copyright . Reservados todos los derechos.
379
Capítulo 9: Tratamiento de excepciones orientadas a objetos
ejecución. Generalmente, las clases de excepción se crean globalmente en el generador de clases, pero también se pueden definir clases de excepción local dentro de un programa o clase global. Los nombres de las clases de excepción global siempre comienzan con CX_. Estas clases de excepción global que utiliza el entorno de tiempo de ejecución comienzan con CX_SY_. SAP recomienda comenzar los nombres de las clases de excepción local con LCX_. Todas las clases de excepción se derivan de la clase de excepción CX_ROOT. Por lo tanto, puede acceder genéricamente a cualquier objeto de excepción mediante una variable de referencia REF TO CX_ROOT. Sin embargo, una nueva clase de excepción no está permitida para heredarla directamente de CX_ROOT. Debe derivar cualquier clase de excepción nueva de manera directa o indirecta desde una de las subclases CX_ROOT - CX_NO_CHECK, CX_DYNAMIC_CHECK o CX_STATIC_CHECK. A través de esto, todas las clases de excepción se subdividen en tres grupos. Según el grupo al que pertenece una excepción determinada, esta se tratará de manera diferente por la verificación de sintaxis y el entorno de tiempo de ejecución. El grupo predeterminado es CX_STATIC_CHECK, que garantiza una verificación de sintaxis y estabilidad de programa máximos. Los otros grupos solo deben utilizarse en casos especiales. El método GET_SOURCE_POSITION devuelve el nombre del programa principal o el programa include y también el número de línea del código fuente en el que se ha producido la excepción. El método GET_TEXT devuelve un texto de excepción en forma de un string. Este método no se define directamente en CX-ROOT pero sí en la interfaz IF_MESSAGE, que se implementa con CX-ROOT.
La estructura de control TRY-ENDTRY
Figura 146: Estructura de un bloque TRY-ENDTRY
Puede tratar una excepción si la sentencia que la emitió se encuentra en una estructura de control TRY-ENDTRY. Trata la excepción mediante la sentencia CATCH en la estructura TRY -ENDTRY. El bloque TRY contiene las sentencias para las que es necesario tratar las excepciones. Un bloque CATCH contiene el programa de control de excepciones que se ejecuta si una excepción especificada se ha producido en el bloque TRY asociado.
380
© Copyright . Reservados todos los derechos.
Lección: Explicación de las excepciones basadas en clases
Como todas las estructuras de control en objetos ABAP, puede anidar las estructuras TRY -ENDTRY hasta cualquier profundidad. Particularmente, los bloques TRY, CATCH y CLEANUP pueden contener estructuras TRY-ENDTRY completas. Especifique cualquier número de clases de excepción para la sentencia CATCH. De esta manera, se define un programa de control de excepciones para todas estas clases de excepción y sus subclases. Si se produce una excepción, el sistema busca la sentencia CATCH coincidente en la estructura TRY-ENDTRY que rodea inmediatamente a la sentencia. Busca a través de los bloques CATCH para la clase de excepción relevante o las clases superiores de la jerarquía de herencia. Si encuentra alguna de las clases de excepción relevantes, el programa navega directamente hacia el programa de control. Si el sistema no encuentra una sentencia CATCH que coincida, busca gradualmente hacia el exterior en las estructuras TRY-ENDTY circundantes. Si no puede encontrar un programa de control dentro del mismo procedimiento, el sistema intenta propagar la excepción al programa de llamada. Este proceso se discutirá de manera más detallada posteriormente. Si una estructura TRY-ENDTRY contiene un bloque CLEANUP, este bloque se ejecuta cuando se retira la estructura TRY-ENDTRY, porque el sistema no puede encontrar un controlador dentro de la estructura TRY-ENDTRY, pero sí en una estructura TRY-ENDTRY circundante o en un programa de llamadas. Ejemplo de sintaxis para tratar excepciones predefinidas
Figura 147: Ejemplo de sintaxis para tratar excepciones predefinidas
La figura muestra un ejemplo de la sintaxis para tratar excepciones predefinidas. Para analizar el objeto de excepción en un controlador de excepción, utilice la sentencia CATCH en la forma CATCH ... INTO ... Debe especificar una referencia de objeto tipificada correctamente después del suplemento opcional INTO. La referencia puede ser una referencia a la clase de excepción en sí o a cualquiera de sus clases superiores. Justo antes de que el sistema ejecute el bloque CATCH, se completará esta variable de referencia para apuntar al objeto de excepción que describe la situación de error que se presenta. Si se supera el ámbito de valores para tipos de datos en el cálculo, el sistema de tiempo de ejecución emitirá la excepción CX_SY_ARITHMETIC_OVERFLOW. Esta excepción se trata en
© Copyright . Reservados todos los derechos.
381
Capítulo 9: Tratamiento de excepciones orientadas a objetos
el bloque CATCH implementado. La referencia a la instancia adecuada se almacena en el objeto de datos GO_EXC del ejemplo. El programa de control puede acceder al texto de excepción de la instancia utilizando el método funcional GET_TEXT. El texto de excepción se almacena en el objeto de datos GV_TEXT con el tipo STRING, y después se visualiza en forma de mensaje de información. Puede acceder cualquier otro componente público del objeto de excepción durante el tratamiento de excepciones de acuerdo con el tipo estático de la variable de referencia. En el ejemplo anterior, la variable de referencia se indica como REF TO CX_ROOT, que restringe el acceso a aquellos componentes definidos en CX_ROOT. Para acceder a componentes más específicos del objeto de excepción, necesita un tipo más específico para el tipo de variable de referencia. También puede utilizar la clase superior CX_SY_ARITHMETIC_ERROR y la clase superior CX_DYNAMIC_CHECK para acceder a los componentes específicos del objeto de excepción. La documentación de palabras clave ABAP de cada sentencia enumera las clases cuyas excepciones pueden aparecer cuando se ejecuta la sentencia.
Análisis de las excepciones basadas en clases en el Debugger
Figura 148: Excepciones basadas en clases en modo debugging
Si se emite una excepción, el sistema muestra el nombre de la clase de excepción en el campo Excepción emitida en modo debugging. Si un bloque CATCH atrapa la excepción, se visualiza un mensaje de éxito. El puntero de la sentencia actual se mueve entonces a este bloque CATCH. Si se produce una excepción, aparecerán dos pulsadores. Utilice los pulsadores para analizar el objeto de excepción y navegar al punto en el código fuente donde se produjo la excepción.
382
© Copyright . Reservados todos los derechos.
Lección: Explicación de las excepciones basadas en clases
Consejo: Por motivos de rendimiento, el sistema no crea realmente objetos de excepción si el suplemento INTO falta en la sentencia CATCH correspondiente. En dichos casos, el pulsador Último objeto de excepción no aparece normalmente. Para configurar el ABAP Debugger para que siempre cree el objeto de excepción, seleccione la opción correspondiente en las opciones del depurador.
RESUMEN DE LA LECCIÓN Ahora podrá: ●
Explicar excepciones basadas en clases
●
Tratar excepciones basadas en clases
●
Depurar excepciones basadas en clases
© Copyright . Reservados todos los derechos.
383
Capítulo 9 Lección 2 Definición y emisión de excepciones
RESUMEN DE LA LECCIÓN Este módulo explica cómo definir y emitir clases de excepción globales. Ejemplo empresarial Necesita definir las clases de excepción globales para sus programa de objetos ABAP. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de la definición de clases de excepción global
●
Una buena comprensión de cómo emitir las excepciones basadas en clases
●
Una buena comprensión de cómo implementar la propagación de la excepción
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá:
384
●
Definir clases de excepción globales
●
Emitir excepciones basadas en clases
●
Propagar excepciones
© Copyright . Reservados todos los derechos.
Lección: Definición y emisión de excepciones
Definición de las clases de excepción globales
Figura 149: Creación de clases de excepción globales
Utilice el generador de clases para crear una clase global tal como se describe en la biblioteca SAP. Cuando introduce el nombre de la clase global, utiliza el prefijo CX_. Seleccione la opción Clase de excepción como el tipo de clase.
Nota: A partir de SAP NetWeaver Application Server 6.40 (SAP NW AS 6.40), aún puede seleccionar la casilla de selección con clase de mensaje al crear una clase de excepción. Después toma los textos, que deberían aparecer cuando hay excepciones, de las clases de mensaje identificadas en la sentencia de mensaje. Encontrará estos mensajes conocidos y estas clases de mensaje en la tabla T100. En releases anteriores a SAP NW AS 6.40, los textos de excepción se almacenaron únicamente en el OTR (Online Text Repository). Cuando cree una clase de excepción, no cambie la entrada propuesta por Hereda de, a no ser que tenga claras las consecuencias de este cambio. Defina los atributos adicionales en su clase de excepción según sea necesario (por ejemplo, para extensiones genéricas de textos de excepción).
© Copyright . Reservados todos los derechos.
385
Capítulo 9: Tratamiento de excepciones orientadas a objetos
Consejo: Si dicho atributo es público, el Generador de clases ajusta automáticamente el constructor de instancia de la clase de excepción. Se genera un nuevo parámetro de entrada y puede fijarse un valor para este atributo cuando se emite una excepción. El parámetro de importación se genera con el mismo nombre que el atributo. El parámetro es opcional de manera predeterminada. Puede declararlo obligatorio al tratar la firma del constructor. Definición de textos de excepción variables
Figura 150: Definición de textos de excepción variables
Grabe todos los textos de excepción que necesite. Cuando graba textos de excepción, puede insertar sus atributos como parámetros en el texto estático utilizando la forma &&.
Nota: Para el primer texto que cree por sí mismo, utilice siempre la constante estática predefinida como ID. La constante siempre tiene el mismo nombre que la clase de excepción misma. Si el que emite la excepción no especifica un texto al emitir la excepción, el sistema utiliza el texto con esta ID. Define otros ID para los demás textos. El generador de clases genera automáticamente constantes estáticas con nombres idénticos. Cuando se emite la excepción, transmite una de estas constantes al parámetro de importación TEXTID para especificar el texto correspondiente a la instancia de excepción.
386
© Copyright . Reservados todos los derechos.
Lección: Definición y emisión de excepciones
Nota: En releases anteriores a SAP NW AS 6.40, los textos de excepción para las clases de excepción global y sus traducciones se almacenan en el OTR. Puede asignar varios textos a una sola clase. Asigna un texto a una excepción con el atributo TEXTID, que contiene el ID único global del objeto de texto en el OTR en una instancia en tiempo de ejecución. Después el método GET_TEXT exporta este texto, sustituye cualquier parámetro de texto con los contenidos de los atributos relevantes según sea necesario, y devuelve el texto como una cadena de caracteres. Active la clase de la excepción después de completar los textos de la excepción.
Emisión de excepciones basadas en clases
Figura 151: Variantes de la sentencia RAISE EXCEPTION
La figura muestra ejemplos para la sentencia RAISE EXCEPTION. La emisión de excepciones basadas en clases se realiza mediante la sentencia RAISE EXCEPTION. Existen dos variantes de esta sentencia. Variantes de la sentencia RAISE EXCEPTION... RAISE EXCEPTION TYPE [EXPORTING ...]. Esta sentencia crea un nuevo objeto de excepción que es una instancia de la clase . RAISE EXCEPTION . Esta sentencia utiliza un objeto de excepción existente al cual señala . El objeto de excepción se creó directamente utilizando una sentencia CREATE OBJECT o se interceptó en una sentencia anterior CATCH... INTO ...statement.
© Copyright . Reservados todos los derechos.
387
Capítulo 9: Tratamiento de excepciones orientadas a objetos
Cuando se utiliza la primera variante, es posible proporcionar los valores para los parámetros del constructor mediante el suplemento EXPORTING. Unos de estos parámetros se utiliza para fijar el texto de excepción en el nuevo objeto de excepción.
Configurar el texto de la excepción
Figura 152: Configuración del texto de excepción
Todas las clases de excepción ofrecen una parámetro opcional TEXTID en sus constructores. Use este parámetro si más de un texto de mensaje está disponible en la clase de excepción y si no desea emitir la excepción con el texto por defecto. Para cada texto definido en la etiqueta Textos, el Generador de clases genera una constante pública del mismo nombre. Las constantes también pueden heredarse de las clases superiores de la clase de excepción. Por defecto, el sistema emite una excepción con el texto que tiene el mismo nombre que la clase de excepción. Para emitir la excepción con otro texto, use la constante correspondiente como el parámetro real para el parámetro de constructor TEXTID.
Nota: El tipo de constantes y el parámetro TEXTID del constructor se determinan al definir si la clase de excepción se creó, o no, con el indicador Con clase de mensaje. Si la clase de excepción aún utiliza los textos OTR, las constantes son del tipo CHAR y contienen una ID técnica del texto OTR. Si la clase de excepción utiliza una clase de mensaje, las constantes son estructuras que contienen el nombre de las clases de mensajes, el número de mensaje, etc.
388
© Copyright . Reservados todos los derechos.
Lección: Definición y emisión de excepciones
Propagación de excepciones
Figura 153: Propagación de excepciones basadas en clases
El tratamiento de excepciones que ocurran dentro de procedimientos no debe situarse dentro del mismo procedimiento. En lugar de ello, el procedimiento puede propagar la excepción a su programa de llamada. El programa de llamada puede tratar la excepción él mismo o propagarla a su propio programa de llamada, y así sucesivamente. Los niveles superiores a los que puede propagarse una excepción son bloques de procesamiento sin áreas de datos locales, es decir, bloques de evento o módulos de diálogo. Estos bloques de procesamiento deben tratar las excepciones propagadas. De lo contrario, se produce un error en tiempo de ejecución. Lo mismo ocurre para las excepciones emitidas dentro de estos bloques de procesamiento. Para propagar una excepción desde un procedimiento, se utiliza generalmente el suplemento RAISING cuando define la interfaz de procedimiento. En métodos de clases locales y subrutinas, especifique directamente el suplemento RAISING al definir el procedimiento. Por ejemplo: METHODS meth_name ... RAISING cx_... cx_... o FORM subr_name ... RAISING cx_... cx_.... Al suplemento RAISING le sigue una lista de las clases de excepción cuyas instancias deben propagarse. En métodos de clases globales, introduce las clases de excepción cuyas instancias se deben propagar en la tabla de excepciones del método en el generador de clases. También se debe fijar la marca Clase de excepción para cada tabla de excepciones. El proceso es similar para módulos de funciones. Para fijar el indicador en el Function Builder, seleccione la etiqueta Excepciones.
Consejo: Un solo método, formulario o módulo de función puede emitir solo un tipo de excepción, es decir, basada en clase o convencional.
© Copyright . Reservados todos los derechos.
389
Capítulo 9: Tratamiento de excepciones orientadas a objetos
Propagación de excepciones por múltiples niveles de jerarquía
Figura 154: Propagación de excepciones por múltiples niveles de jerarquía
La propagación de excepciones basadas en clase no requiere que el método de llamada realmente trate la excepción. Es posible que el programa de llamada transmita la excepción a su propio programa de llamada sin verlo. En el ejemplo, el constructor propaga la excepción CX_EXC emitida por el método GET_TECH_ATTR. Cuando se produce un error y el programa emite la excepción, el flujo del programa pasará directamente al bloque CATCH en el programa principal.
Nota: Si el constructor implementa el bloque opcional CLEANUP, el sistema ejecuta este bloque antes del bloque CATCH del programa principal.
390
© Copyright . Reservados todos los derechos.
Capítulo 9 Ejercicio 23 Implementar las excepciones basadas en clases
Ejemplo empresarial Su programa debe utilizar el concepto de excepción basada en clase si se proporciona un tipo de avión no válido al crear una instancia de avión. Modelo: SAPBC401_GCL_S2 Solución: SAPBC401_EXC_S1 (programa principal) CX_INVALID_PLANETYPE (clase de excepción) Tarea 1 Cree una clase de excepción global para un tipo de avión no válido. 1. Cree una clase de excepción global llamada ZCX_##_INVALID_PLANETYPE (donde ## es su número de grupo de dos cifras). ●
Desea realizar la verificación de sintaxis para asegurarse de que las excepciones basadas en esta clase se traten o propaguen directamente. Seleccione la clase superior según corresponda.
En la clase de excepción, use textos de una clase de mensaje en vez de textos definidos libremente. Consejo: Para definir si los mensajes de una clase de mensaje se usan, seleccione la casilla de selección Clase de mensaje al crear la clase de excepción. 2. Añada un atributo para el tipo de avión (nombre propuesto: PLANETYPE) y asígnele el tipo S_PLANETYPE. Asegúrese de que esté definido el parámetro correspondiente en la firma de constructor. Consejo: No puede definir el constructor de una clase de excepción directamente. Si define el atributo como público, el marco añade el parámetro de importación correspondiente al constructor. 3. Cree un mensaje de error por defecto. El texto del mensaje debe incluir placeholder para que pueda ser mejorado de manera dinámica para incluir el tipo de avión.
© Copyright . Reservados todos los derechos.
391
Capítulo 9: Tratamiento de excepciones orientadas a objetos
Consejo: Puede definir su propia clase de mensaje y el mensaje o utilizar el mensaje 020 de la clase de mensaje BC401.
Tarea 2 Emita la nueva excepción en el método GET_TECHNICAL ATTRIBUTES de la clase local LCL_AIRPLANE. 1. Complete el programa ZBC401_##_MAIN o copie el programa modelo. 2. Trate la definición de clase local LCL_AIRPLANE. Elimine la excepción clásica, no basada en clases WRONG_PLANETYPE, de la firma del método GET_TECHNICAL_ATTRIBUTES y reemplácela con la nueva excepción basada en clases ZCX_##_INVALID_PLANETYPE. 3. Trate la implementación del método GET_TECHNICAL_ATTRIBUTES y emita la excepción basada en clase en vez de la excepción clásica. Asegúrese de que el valor incorrecto del tipo de avión se transfiera al constructor y que esté almacenado en el objeto de excepción. Tarea 3 Propague la excepción basada en clase explícitamente a través de toda la jerarquía de llamada de modo que solo la trate una vez en el programa principal. 1. Trate la definición de clase local LCL_AIRPLANE. Elimine la excepción clásica no basada en clases WRONG_PLANETYPE, de la firma del método GET_TECHNICAL_ATTRIBUTES, y reemplácela con la nueva excepción basada en clases ZCX_##_INVALID_PLANETYPE. 2. Trate la implementación del constructor de clase local LCL_AIRPLANE. Mientras llama el método GET_TECHNICAL_ATTRIBUTES, quite el tratamiento de la excepción clásica WRONG_PLANETYPE. 3. ¿Por qué no es necesario tratar la excepción basada en clases ZCX_##_INVALID_PLANETYPE aquí?
4. Trate la definición de clase local LCL_PASSENGER_PLANE. Elimine la excepción clásica, no basada en clases, WRONG_PLANETYPE de la firma del método CONSTRUCTOR y reemplácela con la nueva excepción basada en clases ZCX_##_INVALID_PLANETYPE. Trate la implementación del constructor de clase local LCL_PASSENGER_PLANE. En la llamada de SUPER->CONSTRUCTOR, elimine el tratamiento de excepción clásica WRONG_PLANETYPE. 5. Repita estos pasos anteriores con la clase local LCL_CARGO_PLANE. Tarea 4 Trate la excepción emitida en el programa principal cuando se cree un objeto de avión.
392
© Copyright . Reservados todos los derechos.
Lección: Definición y emisión de excepciones
1. Defina una variable de referencia global para este propósito (nombre propuesto: GO_INV_PLANETYPE) y tipifíquela con la clase de excepción ZCX_##_INVALID_PLANETYPE. 2. En la sentencia CREATE OBJECT para aviones (las instancias de LCL_AIRPLANE, LCL_PASSENGER_PLANE y LCL_CARGO_PLANE) elimine el tratamiento de la excepción clásica, no basada en clases, WRONG_PLANETYPE. 3. Rodee cada sentencia CREATE OBJECT para aviones con una estructura TRY-ENDTRY. Añada un bloque CATCH para la excepción ZCX_##_INVALID_PLANETYPE. En el caso de excepción, permita que la variable de referencia GO_INV_PLANETYPE apunte al objeto de excepción. 4. Lea el texto de error desde el objeto de excepción y muéstrelo en la lista ABAP. Consejo: No es posible usar el resultado de métodos funcionales directamente en la sentencia WRITE. Debe definir una variable para almacenar el texto (nombre propuesto: GV_TEXT con el tipo de datos STRING). 5. Active y realice un test del programa. Para fines de test, cree un avión con un tipo de avión incorrecto y depure la propagación de la excepción.
© Copyright . Reservados todos los derechos.
393
Capítulo 9 Solución 23 Implementar las excepciones basadas en clases
Ejemplo empresarial Su programa debe utilizar el concepto de excepción basada en clase si se proporciona un tipo de avión no válido al crear una instancia de avión. Modelo: SAPBC401_GCL_S2 Solución: SAPBC401_EXC_S1 (programa principal) CX_INVALID_PLANETYPE (clase de excepción) Tarea 1 Cree una clase de excepción global para un tipo de avión no válido. 1. Cree una clase de excepción global llamada ZCX_##_INVALID_PLANETYPE (donde ## es su número de grupo de dos cifras). ●
Desea realizar la verificación de sintaxis para asegurarse de que las excepciones basadas en esta clase se traten o propaguen directamente. Seleccione la clase superior según corresponda.
En la clase de excepción, use textos de una clase de mensaje en vez de textos definidos libremente. Consejo: Para definir si los mensajes de una clase de mensaje se usan, seleccione la casilla de selección Clase de mensaje al crear la clase de excepción. a) Cree una clase global. b) En la siguiente ventana, seleccione la clase superior CX_STATIC_CHECK. c) Seleccione la opción Clase de excepción y seleccione la casilla de selección Clase de mensaje. 2. Añada un atributo para el tipo de avión (nombre propuesto: PLANETYPE) y asígnele el tipo S_PLANETYPE. Asegúrese de que esté definido el parámetro correspondiente en la firma de constructor.
394
© Copyright . Reservados todos los derechos.
Lección: Definición y emisión de excepciones
Consejo: No puede definir el constructor de una clase de excepción directamente. Si define el atributo como público, el marco añade el parámetro de importación correspondiente al constructor. a) Vaya a la etiqueta Atributos. Indique el nombre y la clase del atributo y seleccione la visibilidad. 3. Cree un mensaje de error por defecto. El texto del mensaje debe incluir placeholder para que pueda ser mejorado de manera dinámica para incluir el tipo de avión. Consejo: Puede definir su propia clase de mensaje y el mensaje o utilizar el mensaje 020 de la clase de mensaje BC401. a) Vaya a la etiqueta Textos. Seleccione el texto por defecto y seleccione Texto de mensaje. b) Indique la clase de mensaje y el número de mensaje en los campos correspondientes. En el campo Atr. 1, use el valor que ayuda a seleccionar el atributo PLANETYPE.
Tarea 2 Emita la nueva excepción en el método GET_TECHNICAL ATTRIBUTES de la clase local LCL_AIRPLANE. 1. Complete el programa ZBC401_##_MAIN o copie el programa modelo. a) Lleve a cabo este paso de la manera habitual. Hay información adicional disponible en la biblioteca SAP. 2. Trate la definición de clase local LCL_AIRPLANE. Elimine la excepción clásica, no basada en clases WRONG_PLANETYPE, de la firma del método GET_TECHNICAL_ATTRIBUTES y reemplácela con la nueva excepción basada en clases ZCX_##_INVALID_PLANETYPE. a) Véase el extracto del código fuente de la solución modelo. 3. Trate la implementación del método GET_TECHNICAL_ATTRIBUTES y emita la excepción basada en clase en vez de la excepción clásica. Asegúrese de que el valor incorrecto del tipo de avión se transfiera al constructor y que esté almacenado en el objeto de excepción. a) Véase el extracto del código fuente de la solución modelo. Tarea 3 Propague la excepción basada en clase explícitamente a través de toda la jerarquía de llamada de modo que solo la trate una vez en el programa principal. 1. Trate la definición de clase local LCL_AIRPLANE. Elimine la excepción clásica no basada en clases WRONG_PLANETYPE, de la firma del método GET_TECHNICAL_ATTRIBUTES, y reemplácela con la nueva excepción basada en clases ZCX_##_INVALID_PLANETYPE. a) Véase el extracto del código fuente de la solución modelo.
© Copyright . Reservados todos los derechos.
395
Capítulo 9: Tratamiento de excepciones orientadas a objetos
2. Trate la implementación del constructor de clase local LCL_AIRPLANE. Mientras llama el método GET_TECHNICAL_ATTRIBUTES, quite el tratamiento de la excepción clásica WRONG_PLANETYPE. a) Véase el extracto del código fuente de la solución modelo. 3. ¿Por qué no es necesario tratar la excepción basada en clases ZCX_##_INVALID_PLANETYPE aquí? El motivo es que esta excepción se propaga en la firma del constructor de LCL_AIRPLANE. 4. Trate la definición de clase local LCL_PASSENGER_PLANE. Elimine la excepción clásica, no basada en clases, WRONG_PLANETYPE de la firma del método CONSTRUCTOR y reemplácela con la nueva excepción basada en clases ZCX_##_INVALID_PLANETYPE. Trate la implementación del constructor de clase local LCL_PASSENGER_PLANE. En la llamada de SUPER->CONSTRUCTOR, elimine el tratamiento de excepción clásica WRONG_PLANETYPE. a) Véase el extracto del código fuente de la solución modelo. 5. Repita estos pasos anteriores con la clase local LCL_CARGO_PLANE. a) Véase el extracto del código fuente de la solución modelo. Tarea 4 Trate la excepción emitida en el programa principal cuando se cree un objeto de avión. 1. Defina una variable de referencia global para este propósito (nombre propuesto: GO_INV_PLANETYPE) y tipifíquela con la clase de excepción ZCX_##_INVALID_PLANETYPE. a) Véase el extracto del código fuente de la solución modelo. 2. En la sentencia CREATE OBJECT para aviones (las instancias de LCL_AIRPLANE, LCL_PASSENGER_PLANE y LCL_CARGO_PLANE) elimine el tratamiento de la excepción clásica, no basada en clases, WRONG_PLANETYPE. a) Véase el extracto del código fuente de la solución modelo. 3. Rodee cada sentencia CREATE OBJECT para aviones con una estructura TRY-ENDTRY. Añada un bloque CATCH para la excepción ZCX_##_INVALID_PLANETYPE. En el caso de excepción, permita que la variable de referencia GO_INV_PLANETYPE apunte al objeto de excepción. a) Véase el extracto del código fuente de la solución modelo. 4. Lea el texto de error desde el objeto de excepción y muéstrelo en la lista ABAP. Consejo: No es posible usar el resultado de métodos funcionales directamente en la sentencia WRITE. Debe definir una variable para almacenar el texto (nombre propuesto: GV_TEXT con el tipo de datos STRING). a) Véase el extracto del código fuente de la solución modelo. 5. Active y realice un test del programa. Para fines de test, cree un avión con un tipo de avión incorrecto y depure la propagación de la excepción.
396
© Copyright . Reservados todos los derechos.
Lección: Definición y emisión de excepciones
a) Lleve a cabo este paso de la manera habitual. Include BC401_EXC_S1_CARRIER *------------------------------------------------* * CLASS lcl_airplane DEFINITION *------------------------------------------------* CLASS lcl_airplane DEFINITION. PUBLIC SECTION.
* *
METHODS: constructor IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype EXCEPTIONS wrong_planetype, RAISING cx_invalid_planetype, display_attributes. CLASS-METHODS: display_n_o_airplanes, class_constructor. EVENTS: airplane_created. PROTECTED SECTION. CONSTANTS: c_pos_1 TYPE i VALUE 30. PRIVATE SECTION. TYPES: ty_planetypes TYPE STANDARD TABLE OF saplane WITH NON-UNIQUE KEY planetype. DATA: mv_name mv_planetype mv_weight mv_tankcap
TYPE TYPE TYPE TYPE
string, saplane-planetype, saplane-weight, saplane-tankcap.
CLASS-DATA: gv_n_o_airplanes TYPE i, gt_planetypes TYPE ty_planetypes.
* *
CLASS-METHODS: get_technical_attributes IMPORTING iv_type TYPE saplane-planetype EXPORTING ev_weight TYPE saplane-weight ev_tankcap TYPE saplane-tankcap EXCEPTIONS wrong_planetype. RAISING cx_invalid_planetype.
© Copyright . Reservados todos los derechos.
397
Capítulo 9: Tratamiento de excepciones orientadas a objetos
ENDCLASS.
"lcl_airplane DEFINITION
*-------------------------------------------------* * CLASS lcl_airplane IMPLEMENTATION *-------------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. METHOD class_constructor. SELECT * FROM saplane INTO TABLE gt_planetypes. ENDMETHOD. "class_constructor METHOD constructor. mv_name = iv_name. mv_planetype = iv_planetype. get_technical_attributes( EXPORTING iv_type = iv_planetype IMPORTING ev_weight = mv_weight ev_tankcap = mv_tankcap ). gv_n_o_airplanes = gv_n_o_airplanes + 1. RAISE EVENT airplane_created. * * * * * * * * * * * * * * *
get_technical_attributes( EXPORTING iv_type = iv_planetype IMPORTING ev_weight = mv_weight ev_tankcap = mv_tankcap EXCEPTIONS wrong_planetype = 1 ). IF sy-subrc <> 0. RAISE wrong_planetype. ELSE. gv_n_o_airplanes = gv_n_o_airplanes + 1. RAISE EVENT airplane_created. ENDIF. ENDMETHOD. "constructor METHOD display_attributes. WRITE: / icon_ws_plane AS ICON, / 'Name of Airplane'(001) , / 'Type of Airplane:'(002), / 'Weight:'(003), LEFT-JUSTIFIED, / 'Tank capacity:'(004), LEFT-JUSTIFIED. ENDMETHOD.
AT c_pos_1 mv_name, AT c_pos_1 mv_planetype, AT c_pos_1 mv_weight AT c_pos_1 mv_tankcap
"display_attributes
METHOD display_n_o_airplanes. SKIP. WRITE: / 'Number of airplanes:'(ca1), AT c_pos_1 gv_n_o_airplanes LEFT-JUSTIFIED. ENDMETHOD. "display_n_o_airplanes METHOD get_technical_attributes.
398
© Copyright . Reservados todos los derechos.
Lección: Definición y emisión de excepciones
DATA: ls_planetype TYPE saplane. READ TABLE gt_planetypes INTO ls_planetype WITH TABLE KEY planetype = iv_type TRANSPORTING weight tankcap. IF sy-subrc = 0. ev_weight = ls_planetype-weight. ev_tankcap = ls_planetype-tankcap. ELSE. * RAISE wrong_planetype. RAISE EXCEPTION TYPE cx_invalid_planetype EXPORTING planetype = iv_type. ENDIF. ENDMETHOD. "get_technical_attributes ENDCLASS.
"lcl_airplane IMPLEMENTATION
*-------------------------------------------------* * CLASS lcl_cargo_plane DEFINITION *---------------------------------------------------* CLASS lcl_cargo_plane DEFINITION INHERITING FROM lcl_airplane. PUBLIC SECTION.
* *
METHODS: constructor IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype iv_cargo TYPE s_plan_car RAISING cx_invalid_planetype, EXCEPTIONS wrong_planetype, display_attributes REDEFINITION. PRIVATE SECTION. DATA: mv_cargo TYPE s_plan_car.
ENDCLASS.
"lcl_cargo_plane DEFINITION
*-----------------------------------------------* * CLASS lcl_cargo_plane IMPLEMENTATION *-----------------------------------------------* CLASS lcl_cargo_plane IMPLEMENTATION.
* * * * *
METHOD constructor. super->constructor( EXPORTING iv_name = iv_name iv_planetype = iv_planetype ). EXCEPTIONS wrong_planetype = 1 ). IF sy-subrc <> 0. RAISE wrong_planetype. ENDIF.
© Copyright . Reservados todos los derechos.
399
Capítulo 9: Tratamiento de excepciones orientadas a objetos
mv_cargo = iv_cargo. ENDMETHOD. "constructor METHOD display_attributes. super->display_attributes( ). WRITE: / 'Max Cargo:'(005), AT c_pos_1 mv_cargo LEFT-JUSTIFIED. ULINE. ENDMETHOD. "display_attributes ENDCLASS.
"lcl_cargo_plane IMPLEMENTATION
*------------------------------------------------* * CLASS lcl_passenger_plane DEFINITION *------------------------------------------------* CLASS lcl_passenger_plane DEFINITION INHERITING FROM lcl_airplane. PUBLIC SECTION.
* *
METHODS: constructor IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype iv_seats TYPE s_seatsmax EXCEPTIONS wrong_planetype RAISING cx_invalid_planetype, display_attributes REDEFINITION. PRIVATE SECTION. DATA: mv_seats TYPE s_seatsmax.
ENDCLASS.
"lcl_passenger_plane DEFINITION
*-----------------------------------------------* * CLASS lcl_passenger_plane IMPLEMENTATION *-----------------------------------------------* CLASS lcl_passenger_plane IMPLEMENTATION. METHOD constructor. super->constructor( EXPORTING iv_name = iv_name iv_planetype = iv_planetype ). * * * * *
EXCEPTIONS wrong_planetype = 1 ). IF sy-subrc <> 0. RAISE wrong_planetype. ENDIF. mv_seats = iv_seats. ENDMETHOD. "constructor METHOD display_attributes.
400
© Copyright . Reservados todos los derechos.
Lección: Definición y emisión de excepciones
super->display_attributes( ). WRITE: / 'Max Seats:'(006), AT c_pos_1 mv_seats LEFT-JUSTIFIED. ULINE. ENDMETHOD. "display_attributes ENDCLASS. "lcl_passenger_plane IMPLEMENTATION *---------------------------------------------------* * CLASS lcl_carrier DEFINITION *---------------------------------------------------* CLASS lcl_carrier DEFINITION. ... ENDCLASS.
"lcl_carrier DEFINITION
*---------------------------------------------------* * CLASS lcl_carrier IMPLEMENTATION *---------------------------------------------------* CLASS lcl_carrier IMPLEMENTATION. ... ENDCLASS.
"lcl_carrier IMPLEMENTATION
Programa principal SAPBC401_EXC_S1 REPORT
sapbc401_exc_s1.
TYPE-POOLS icon. INCLUDE bc401_exc_s1_agency. INCLUDE bc401_exc_s1_carrier. INCLUDE bc401_exc_s1_rental. DATA: go_hotel go_vehicle go_truck go_bus go_rental go_passenger go_cargo go_carrier go_agency
TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE
REF REF REF REF REF REF REF REF REF
TO TO TO TO TO TO TO TO TO
cl_hotel2, lcl_vehicle, lcl_truck, lcl_bus, lcl_rental, lcl_passenger_plane, lcl_cargo_plane, lcl_carrier, lcl_travel_agency.
DATA: gv_text TYPE string, gx_inv_planetype TYPE REF TO cx_invalid_planetype. START-OF-SELECTION. ******************* ******* create travel_agency CREATE OBJECT go_agency EXPORTING iv_name = 'Travel&Smile Travel'. ******* create hotel
© Copyright . Reservados todos los derechos.
401
Capítulo 9: Tratamiento de excepciones orientadas a objetos
CREATE OBJECT go_hotel EXPORTING iv_name = 'Sleep Well Hotel' iv_beds = 345. ******* create rental CREATE OBJECT go_rental EXPORTING iv_name = 'Happy Car Rental'. ******* create truck CREATE OBJECT go_truck EXPORTING iv_make = 'MAN' iv_cargo = 45. ******* create truck CREATE OBJECT go_bus EXPORTING iv_make = 'Mercedes' iv_passengers = 80. ******* create truck CREATE OBJECT go_truck EXPORTING iv_make = 'VOLVO' iv_cargo = 48. ***** Create Carrier CREATE OBJECT go_carrier EXPORTING iv_name = 'Smile&Fly'. ***** Passenger Plane TRY. CREATE OBJECT go_passenger EXPORTING iv_name = 'LH BERLIN' iv_planetype = '747-500' iv_seats = 345. CATCH cx_invalid_planetype INTO gx_inv_planetype. gv_text = gx_inv_planetype->get_text( ). WRITE: / icon_failure AS ICON, gv_text. ENDTRY. * * * * * * * * * * * *
402
CREATE OBJECT go_passenger EXPORTING iv_name = 'LH BERLIN' iv_planetype = '747-400' iv_seats = 345 EXCEPTIONS wrong_planetype = 1. IF sy-subrc <> 0. WRITE: / icon_failure AS ICON, 'Wrong plane type'. ENDIF.
© Copyright . Reservados todos los derechos.
Lección: Definición y emisión de excepciones
***** cargo Plane TRY. CREATE OBJECT go_cargo EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' iv_cargo = 533. CATCH cx_invalid_planetype INTO gx_inv_planetype. gv_text = gx_inv_planetype->get_text( ). WRITE: / icon_failure AS ICON, gv_text. ENDTRY. * * * * * * * * * * * * *
CREATE OBJECT go_cargo EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' iv_cargo = 533 EXCEPTIONS wrong_planetype = 1. IF sy-subrc <> 0. WRITE: / icon_failure AS ICON, 'Wrong plane type'. ENDIF.
******* show attributes of all partners of travel_agency go_agency->display_attributes( ).
© Copyright . Reservados todos los derechos.
403
Capítulo 9: Tratamiento de excepciones orientadas a objetos
RESUMEN DE LA LECCIÓN Ahora podrá:
404
●
Definir clases de excepción globales
●
Emitir excepciones basadas en clases
●
Propagar excepciones
© Copyright . Reservados todos los derechos.
Capítulo 9 Lección 3 Implementación de técnicas avanzadas de tratamiento de excepciones
RESUMEN DE LA LECCIÓN Este módulo explica la implementación de las técnicas avanzadas de tratamiento de excepciones. Ejemplo empresarial Necesita usar las técnicas avanzadas de tratamiento de excepciones para interceptar excepciones y reintentar el tratamiento de excepciones en sus programas de objetos ABAP. Por este motivo, se requieren los siguientes conocimientos: ●
Una buena comprensión de las clases de excepciones predefinidas
●
Una buena comprensión de cómo tratar una clase de excepción
●
Una buena comprensión de cómo reintentar después de una excepción
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Explicar la jerarquía de las clases de excepción predefinidas
●
Explicar las distintas formas de tratar una excepción
●
Reintentar después de las excepciones
●
Implementar excepciones reanudables
●
Volver a emitir las excepciones
●
Asignar excepciones unas a otras
© Copyright . Reservados todos los derechos.
405
Capítulo 9: Tratamiento de excepciones orientadas a objetos
La jerarquía de las clases de excepción predefinidas
Figura 155: Integración de excepciones estándar en el sistema de tiempo de ejecución
La figura indica cómo las excepciones estándar del sistema de tiempo de ejecución son integradas en la jerarquía de herencia de las clases de excepción. La selección de la clase superior influye en la forma en que la verificación de sintaxis y del entorno de tiempo de ejecución gestionan una excepción determinada. Algunas de las clases de excepción estándar son las siguientes: ● CX_STATIC_CHECK Si una clase de excepción hereda de CX_STATIC_CHECK, debe tratar la excepción relevante o propagarla con el suplemento RAISING. Si la excepción no se trata ni propaga con el suplemento RAISING, la verificación de sintaxis muestra una advertencia. Cuando define nuevas clases de excepción globales, CX_STATIC_CHECK se define como la clase superior de manera predeterminada. ●
CX_DYNAMIC_CHECK Para las subclases de CX_DYNAMIC_CHECK, la verificación de sintaxis no muestra advertencias si las excepciones no se gestionan ni propagan con el suplemento RAISING. Si se emite una excepción en el tiempo de ejecución y no la gestiona ni propaga, el sistema finaliza el programa con un error de tiempo de ejecución. Nota: Ejemplos típicos de esta situación son las excepciones predefinidas CX_SY_... para los errores que ocurren en el entorno de tiempo de ejecución. Suelen ser subclases de CX_DYNAMIC_CHECK.
●
406
CX_NO_CHECK
© Copyright . Reservados todos los derechos.
Lección: Implementación de técnicas avanzadas de tratamiento de excepciones
Para las subclases de CX_NO_CHECK, no puede propagar las excepciones correspondientes explícitamente mediante el suplemento RAISING. Si no gestiona estas excepciones en el bloque de tratamiento donde se producen, se propagan de manera automática. Si el bloque de llamada no gestiona las excepciones, continúan propagándose automáticamente en el mayor nivel de jerarquía de la llamada. Si las excepciones no se tratan en el nivel superior, se produce un error en tiempo de ejecución al momento en que fueron emitidas. Algunas excepciones predefinidas con el prefijo CX_SY_... para situaciones de error en el entorno de tiempo de ejecución son subclases de CX_NO_CHECK.
Distintas formas de tratar una excepción Después de que una excepción se interceptó en una sentencia CATCH, puede tratarla de muchas maneras diferentes. Puede ver una de las siguientes técnicas para tratar una excepción interceptada en una sentencia CATCH: 1. Continúe el programa detrás de una sentencia ENDTRY después de tomar una de estas medidas: ●
Ignorar la excepción (no hacer nada)
●
Emitir una advertencia
●
Escribir en un protocolo
●
Corregir la situación
2. Quitar la causa del error y comenzar nuevamente a partir de uno de estos puntos: ●
●
Desde el principio del bloque TRY correspondiente, utilizando la sentencia RETRY que es nueva a partir de SAP NW 7.0 EhP 2. Desde el lugar donde se produjo la excepción (utilizando la sentencia RESUME que es nueva a partir de SAP NW 7.0 EhP 2).
3. Emitir y propagar una de las siguientes excepciones: ●
El mismo objeto de excepción nuevamente con RAISE EXCEPTION .
●
Una nueva excepción con RAISE EXCEPTION TYPE .
© Copyright . Reservados todos los derechos.
407
Capítulo 9: Tratamiento de excepciones orientadas a objetos
Implementación de Reintentar después de las excepciones
Figura 156: Sentencia RETRY
Cuando trata una excepción en un bloque CATCH, utiliza la sentencia RETRY para regresar a la sentencia TRY de la estructura TRY-ENTRY correspondiente, por ejemplo, si la causa de la excepción se eliminó durante el tratamiento. Consejo: Esta es una nueva técnica del release SAP NetWeaver 7.0 EhP 2.
En el ejemplo, el programa principal intercepta la excepción que el constructor emitió y propagó. Después de analizar el objeto de excepción y de corregir la situación de error, el programa principal repite el bloque TRY completo con la sentencia RETRY.
Atención: Debe usar RETRY con cuidado. Si no elimina la causa de la excepción del modo adecuado, su programa ingresará en un bucle sin fin.
408
© Copyright . Reservados todos los derechos.
Lección: Implementación de técnicas avanzadas de tratamiento de excepciones
Implementación de excepciones reanudables
Figura 157: Reanudar la ejecución tras una excepción reanudable
Consejo: Esta es una nueva técnica del release SAP NW 7.0 EhP 2.
Utilice la sentencia RESUME para reanudar un programa inmediatamente después de la sentencia que emitió la excepción en el código fuente. Debe satisfacer los siguientes requisitos previos para usar la sentencia RESUME: 1. La excepción debe interceptarse con la sentencia CATCH y el suplemento BEFORE UNWIND. Esto garantiza que el contexto de la excepción se mantendrá activo para un posible RESUME. Si el bloque CATCH salió sin sentencia RESUME, el sistema borra el contexto de la excepción después de salir del bloque CATCH. 2. La excepción deberá emitirse con la variante RAISE RESUMABLE ... de la sentencia RAISE EXCEPTION. Esto prepara el bloque de tratamiento de emisiones para RESUME. 3. Si la excepción se propaga, debe marcarla como reanudable en todos lo niveles de jerarquía al utilizar el suplemento RAISING RESUMABLE ( ... ) con el nombre de la clase de excepción entre paréntesis. Esto prepara todos los métodos que propagan la excepción para un posible RESUME.
© Copyright . Reservados todos los derechos.
409
Capítulo 9: Tratamiento de excepciones orientadas a objetos
Consejo: Las casillas de selección correspondientes están disponibles en el Generador de clases y en Function Builder cuando se define la firma del método o la interfaz del módulo de función. El programa de control de una excepción determinada verifica, en tiempo de ejecución, si dicha excepción se emitió o propagó como reanudable o no. Todos los objetos de excepción brindan el atributo de instancia pública IS_RESUMABLE, que se fija en 'X' o ' ' por el framework, de acuerdo con el modo en que se emitió y propagó la excepción. Si reanuda una excepción no reanudable, producirá un error en tiempo de ejecución (clase de excepción CX_SY_ILLEGAL_HANDLER). Reanudar la ejecución tras una excepción reanudable En el ejemplo que se muestra en la figura, el método GET_TECH_ATTR emite y propaga la excepción; y el constructor sigue propagando la excepción. Todas las emisiones y propagaciones se configuran como reanudables. El programa principal trata la excepción con CATCH BEFORE UNWIND ..., verifica que la excepción sea realmente reanudable y emite la sentencia RESUME. El sistema reanuda la ejecución de GET_TECH_ATTR inmediatamente después de que la sentencia RAISE RESUMABLE EXCEPTION se ejecuta.
Consejo: En este ejemplo, mantiene el contexto de la excepción. Sin el suplemento BEFORE UNWIND, el sistema elimina la instancia creada recientemente antes de ejecutar el bloque CATCH. No se podrán reanudar el método GET_TECH_ATTR ni el constructor.
Implementación de la nueva emisión de las excepciones
Figura 158: Nueva emisión de un objeto de excepción existente
410
© Copyright . Reservados todos los derechos.
Lección: Implementación de técnicas avanzadas de tratamiento de excepciones
Puede emitir las excepciones basadas en clase con una de las siguientes variantes de la sentencia RAISE EXCEPTION: ●
RAISE EXCEPTION TYPE [EXPORTING ...] Esta sentencia crea un nuevo objeto de excepción que es una instancia de la clase . De manera opcional, los valores pueden proporcionarse para el constructor utilizando el suplemento EXPORTING.
●
RAISE EXCEPTION Esta sentencia utiliza un objeto de excepción existente, concretamente, cualquier objeto de excepción al cual señala . Este objeto de excepción se creó directamente con una sentencia CREATE OBJECT o, más comúnmente, se interceptó en una sentencia anterior CATCH... Sentencia INTO ... y pasa a la llamada de manera explícita.
En el ejemplo, el constructor intercepta la excepción CX_EXC que se emite por el método GET_TECH_ATTR. El constructor analiza el objeto de excepción, realiza los ajustes necesarios, emite una advertencia, etc. Después el constructor decide pasar la excepción al programa principal, donde la excepción se trata nuevamente.
Asignación de excepciones unas a otras
Figura 159: Asignación de excepciones unas a otras
Después de interceptar una excepción, el programa puede emitir una segunda excepción, etc. Un objeto de excepción no es válido cuando el programa sale del bloque CATCH. Por lo tanto, el programa de control en el nivel superior solo tiene acceso al último objeto de excepción. Sin embargo, puede concatenar objetos de excepción, es decir, puede dejar que un objeto de excepción apunte a uno anterior que apunta a su anterior, y así sucesivamente. De este modo, el programa de control de una excepción puede seguir la cadena y evaluar cada objeto de excepción en la secuencia. Todas las clases de excepción brindan el atributo de instancia pública PREVIOUS. Indica el atributo con REF TO CX_ROOT para que apunte a objetos de excepción arbitrarios. Los
© Copyright . Reservados todos los derechos.
411
Capítulo 9: Tratamiento de excepciones orientadas a objetos
constructores de todas las clases de excepción tienen un parámetro de importación, PREVIOUS, del mismo tipo que puede usarse para enlazar un objeto de excepción existente a uno nuevo. En el ejemplo de la figura, el constructor intercepta la excepción que emitió el método GET_TECH_ATTR. Después de analizar la excepción, el constructor emite una nueva excepción de una clase de excepción diferente. Encadena el objeto de excepción existente y el nuevo al transmitir una referencia de objeto existente al constructor del nuevo. Como resultado, el atributo PREVIOUS del nuevo objeto de excepción apunta al objeto de excepción que lo precede. El programa principal intercepta la segunda excepción y accede al segundo objeto de excepción. Sin embargo, al utilizar el atributo público PREVIOUS, el programa principal puede navegar al otro objeto de excepción y analizarlo. El programa principal puede acceder a cada instancia en una cadena de excepciones y, de este modo, realizar un seguimiento del historial de la emisión de excepciones en la jerarquía de llamadas.
412
© Copyright . Reservados todos los derechos.
Capítulo 9 Ejercicio 24 Asignar excepciones unas a otras
Ejemplo empresarial Desea que su programa utilice el concepto de excepción basada en clase si se proporciona un tipo de avión no válido al crear una instancia de avión. En lugar de solo propagar la excepción emitida por GET_TECHNICAL_ATTRIBUTES, el constructor necesita tratarla y emitir una excepción diferente. Se recomienda encadenar las dos excepciones juntas para que las evalúe el programa principal. Modelo: SAPBC401_EXC_S1 Solución: SAPBC401_EXC_S2 Tarea 1 En el constructor de clase local LCL_AIRPLANE, trate la excepción emitida por el método GET_TECHNICAL_ATTRIBUTES. 1. Complete el programa ZBC401_##_MAIN o copie el programa modelo. 2. Trate la implementación del constructor de clase local LCL_AIRPLANE. Defina una referencia de objeto local (nombre propuesto: LX_INV_PLANETYPE) y seleccione su tipo de manera tal que la referencia pueda apuntar al objeto de excepción emitido por el método GET_TECHNICAL_ATTRIBUTES. 3. Implemente una estructura TRY-ENDTRY para el tratamiento de excepciones. Intercepte el objeto de excepción, pero deje vacío el bloque CATCH por ahora.
Tarea 2 Emita una nueva excepción y asígnela a la excepción original. Ajuste el constructor para propagar la nueva excepción al programa principal. 1. En el constructor de LCL_AIRPLANE, emita una nueva excepción de TYPE CX_INVALID_VALUE durante el tratamiento de la excepción emitida por GET_TECHNICAL_ATTRIBUTES. ●
Consejo: Verifique la firma de la clase de excepción CX_INVALID_VALUE, para consultar si contiene algún atributo para el que tenga que proporcionar valores. Transfiera la referencia a la instancia de excepción original para el constructor de instancias de excepción.
© Copyright . Reservados todos los derechos.
413
Capítulo 9: Tratamiento de excepciones orientadas a objetos
2. Asegúrese de que el atributo de instancia PREVIOUS del nuevo objeto de excepción apunte al objeto de excepción ya existente. Utilice el parámetro de importación PREVIOUS del método del constructor. 3. Ajuste la firma del constructor para que propague la nueva excepción. 4. ¿Qué otras firmas de métodos debe ajustar para propagar la excepción hasta el programa principal?
Tarea 3 En el programa principal, trate la nueva excepción y evalúe la información de la instancia de excepción original y nueva. 1. Intercepte su nueva excepción en el programa principal siempre que cree una instancia de un avión. Defina una variable de referencia local para este propósito con un tipo de referencia adecuado (nombre sugerido: GX_INV_VALUE). 2. Utilice esta referencia para extraer el texto de su nueva excepción. Visualice el texto en la lista. 3. Utilice las mismas variables para extraer el texto de la excepción original. Visualice el texto en la lista.
414
© Copyright . Reservados todos los derechos.
Capítulo 9 Solución 24 Asignar excepciones unas a otras
Ejemplo empresarial Desea que su programa utilice el concepto de excepción basada en clase si se proporciona un tipo de avión no válido al crear una instancia de avión. En lugar de solo propagar la excepción emitida por GET_TECHNICAL_ATTRIBUTES, el constructor necesita tratarla y emitir una excepción diferente. Se recomienda encadenar las dos excepciones juntas para que las evalúe el programa principal. Modelo: SAPBC401_EXC_S1 Solución: SAPBC401_EXC_S2 Tarea 1 En el constructor de clase local LCL_AIRPLANE, trate la excepción emitida por el método GET_TECHNICAL_ATTRIBUTES. 1. Complete el programa ZBC401_##_MAIN o copie el programa modelo. a) Lleve a cabo este paso de la manera habitual. Para más información, consulte la biblioteca SAP. 2. Trate la implementación del constructor de clase local LCL_AIRPLANE. Defina una referencia de objeto local (nombre propuesto: LX_INV_PLANETYPE) y seleccione su tipo de manera tal que la referencia pueda apuntar al objeto de excepción emitido por el método GET_TECHNICAL_ATTRIBUTES. a) Véase el extracto del código fuente de la solución modelo. 3. Implemente una estructura TRY-ENDTRY para el tratamiento de excepciones. Intercepte el objeto de excepción, pero deje vacío el bloque CATCH por ahora. a) Véase el extracto del código fuente de la solución modelo.
Tarea 2 Emita una nueva excepción y asígnela a la excepción original. Ajuste el constructor para propagar la nueva excepción al programa principal. 1. En el constructor de LCL_AIRPLANE, emita una nueva excepción de TYPE CX_INVALID_VALUE durante el tratamiento de la excepción emitida por GET_TECHNICAL_ATTRIBUTES.
© Copyright . Reservados todos los derechos.
415
Capítulo 9: Tratamiento de excepciones orientadas a objetos
●
Consejo: Verifique la firma de la clase de excepción CX_INVALID_VALUE, para consultar si contiene algún atributo para el que tenga que proporcionar valores. Transfiera la referencia a la instancia de excepción original para el constructor de instancias de excepción. a) Véase el extracto del código fuente de la solución modelo. 2. Asegúrese de que el atributo de instancia PREVIOUS del nuevo objeto de excepción apunte al objeto de excepción ya existente. Utilice el parámetro de importación PREVIOUS del método del constructor. a) Véase el extracto del código fuente de la solución modelo. 3. Ajuste la firma del constructor para que propague la nueva excepción. a) Véase el extracto del código fuente de la solución modelo. 4. ¿Qué otras firmas de métodos debe ajustar para propagar la excepción hasta el programa principal? Los constructores de LCL_CARGO_PLANE y LCL_PASSENGER_PLANE. Tarea 3 En el programa principal, trate la nueva excepción y evalúe la información de la instancia de excepción original y nueva. 1. Intercepte su nueva excepción en el programa principal siempre que cree una instancia de un avión. Defina una variable de referencia local para este propósito con un tipo de referencia adecuado (nombre sugerido: GX_INV_VALUE). a) Véase el extracto del código fuente de la solución modelo. 2. Utilice esta referencia para extraer el texto de su nueva excepción. Visualice el texto en la lista. a) Véase el extracto del código fuente de la solución modelo. 3. Utilice las mismas variables para extraer el texto de la excepción original. Visualice el texto en la lista. a) Véase el extracto del código fuente de la solución modelo. Include BC401_EXC_S2_CARRIER *---------------------------------------------------* * CLASS lcl_airplane DEFINITION *---------------------------------------------------* CLASS lcl_airplane DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING
416
© Copyright . Reservados todos los derechos.
Lección: Implementación de técnicas avanzadas de tratamiento de excepciones
iv_name TYPE string iv_planetype TYPE saplane-planetype RAISING cx_invalid_value, cx_invalid_planetype,
*
display_attributes. CLASS-METHODS: display_n_o_airplanes, class_constructor. EVENTS: airplane_created. PROTECTED SECTION. CONSTANTS: c_pos_1 TYPE i VALUE 30. PRIVATE SECTION. TYPES: ty_planetypes TYPE STANDARD TABLE OF saplane WITH NON-UNIQUE KEY planetype. DATA: mv_name mv_planetype mv_weight mv_tankcap
TYPE TYPE TYPE TYPE
string, saplane-planetype, saplane-weight, saplane-tankcap.
CLASS-DATA: gv_n_o_airplanes TYPE i, gt_planetypes TYPE ty_planetypes. CLASS-METHODS: get_technical_attributes IMPORTING iv_type TYPE saplane-planetype EXPORTING ev_weight TYPE saplane-weight ev_tankcap TYPE saplane-tankcap RAISING cx_invalid_planetype. ENDCLASS.
"lcl_airplane DEFINITION
*-----------------------------------------------* * CLASS lcl_airplane IMPLEMENTATION * *-----------------------------------------------* CLASS lcl_airplane IMPLEMENTATION. METHOD class_constructor. SELECT * FROM saplane INTO TABLE gt_planetypes. ENDMETHOD. "class_constructor METHOD constructor. DATA: lx_inv_planetype TYPE REF TO cx_invalid_planetype. mv_name = iv_name.
© Copyright . Reservados todos los derechos.
417
Capítulo 9: Tratamiento de excepciones orientadas a objetos
mv_planetype
= iv_planetype.
TRY.
get_technical_attributes( EXPORTING iv_type = iv_planetype IMPORTING ev_weight = mv_weight ev_tankcap = mv_tankcap ).
gv_n_o_airplanes = gv_n_o_airplanes + 1. RAISE EVENT airplane_created. CATCH cx_invalid_planetype INTO lx_inv_planetype. RAISE EXCEPTION TYPE cx_invalid_value EXPORTING parnam = 'IV_PLANETYPE' previous = lx_inv_planetype. ENDTRY. ENDMETHOD.
"constructor
METHOD display_attributes. WRITE: / icon_ws_plane AS ICON, / 'Name of Airplane'(001) , / 'Type of Airplane:'(002), / 'Weight:'(003), LEFT-JUSTIFIED, / 'Tank capacity:'(004), LEFT-JUSTIFIED. ENDMETHOD.
AT c_pos_1 mv_name, AT c_pos_1 mv_planetype, AT c_pos_1 mv_weight AT c_pos_1 mv_tankcap
"display_attributes
METHOD display_n_o_airplanes. SKIP. WRITE: / 'Number of airplanes:'(ca1), AT c_pos_1 gv_n_o_airplanes LEFT-JUSTIFIED. ENDMETHOD. "display_n_o_airplanes METHOD get_technical_attributes. DATA: ls_planetype TYPE saplane. READ TABLE gt_planetypes INTO ls_planetype WITH TABLE KEY planetype = iv_type TRANSPORTING weight tankcap. IF sy-subrc = 0. ev_weight = ls_planetype-weight. ev_tankcap = ls_planetype-tankcap. ELSE. * RAISE wrong_planetype. RAISE EXCEPTION TYPE cx_invalid_planetype EXPORTING planetype = iv_type. ENDIF. ENDMETHOD. "get_technical_attributes ENDCLASS.
418
"lcl_airplane IMPLEMENTATION
© Copyright . Reservados todos los derechos.
Lección: Implementación de técnicas avanzadas de tratamiento de excepciones
*------------------------------------------------* * CLASS lcl_cargo_plane DEFINITION *------------------------------------------------* * *----------------------------------------------------* CLASS lcl_cargo_plane DEFINITION INHERITING FROM lcl_airplane. PUBLIC SECTION.
*
METHODS: constructor IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype iv_cargo TYPE s_plan_car RAISING cx_invalid_value, cx_invalid_planetype, display_attributes REDEFINITION. PRIVATE SECTION. DATA: mv_cargo TYPE s_plan_car.
ENDCLASS.
"lcl_cargo_plane DEFINITION
*-------------------------------------------------* * CLASS lcl_cargo_plane IMPLEMENTATION *-------------------------------------------------* CLASS lcl_cargo_plane IMPLEMENTATION. ... ENDCLASS.
"lcl_cargo_plane IMPLEMENTATION
*-------------------------------------------------* * CLASS lcl_passenger_plane DEFINITION *-------------------------------------------------* CLASS lcl_passenger_plane DEFINITION INHERITING FROM lcl_airplane. PUBLIC SECTION.
*
METHODS: constructor IMPORTING iv_name TYPE string iv_planetype TYPE saplane-planetype iv_seats TYPE s_seatsmax RAISING cx_invalid_value, cx_invalid_planetype, display_attributes REDEFINITION. PRIVATE SECTION.
DATA: mv_seats TYPE s_seatsmax. ENDCLASS. "lcl_passenger_plane DEFINITION
© Copyright . Reservados todos los derechos.
419
Capítulo 9: Tratamiento de excepciones orientadas a objetos
*------------------------------------------------* * CLASS lcl_passenger_plane IMPLEMENTATION *------------------------------------------------* CLASS lcl_passenger_plane IMPLEMENTATION. ... ENDCLASS.
"lcl_passenger_plane IMPLEMENTATION
*------------------------------------------------* * CLASS lcl_carrier DEFINITION *------------------------------------------------* CLASS lcl_carrier DEFINITION. ... ENDCLASS. "lcl_carrier DEFINITION *------------------------------------------------* * CLASS lcl_carrier IMPLEMENTATION *------------------------------------------------* CLASS lcl_carrier IMPLEMENTATION. ... ENDCLASS.
"lcl_carrier IMPLEMENTATION
Programa principal SAPBC401_EXC_S2 REPORT
sapbc401_exc_s2.
TYPE-POOLS icon. INCLUDE bc401_exc_s2_agency. INCLUDE bc401_exc_s2_carrier. INCLUDE bc401_exc_s2_rental. DATA: go_hotel go_vehicle go_truck go_bus go_rental go_passenger go_cargo go_carrier go_agency
TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE
REF REF REF REF REF REF REF REF REF
TO TO TO TO TO TO TO TO TO
cl_hotel2, lcl_vehicle, lcl_truck, lcl_bus, lcl_rental, lcl_passenger_plane, lcl_cargo_plane, lcl_carrier, lcl_travel_agency.
DATA: gv_text TYPE string, gx_inv_value TYPE REF TO cx_invalid_value. * gx_inv_planetype TYPE REF TO cx_invalid_planetype. START-OF-SELECTION. ******************* ******* create travel_agency CREATE OBJECT go_agency EXPORTING iv_name = 'Travel&Smile Travel'.
420
© Copyright . Reservados todos los derechos.
Lección: Implementación de técnicas avanzadas de tratamiento de excepciones
******* create hotel CREATE OBJECT go_hotel EXPORTING iv_name = 'Sleep Well Hotel' iv_beds = 345. ******* create rental CREATE OBJECT go_rental EXPORTING iv_name = 'Happy Car Rental'. ******* create truck CREATE OBJECT go_truck EXPORTING iv_make = 'MAN' iv_cargo = 45. ******* create truck CREATE OBJECT go_bus EXPORTING iv_make = 'Mercedes' iv_passengers = 80. ******* create truck CREATE OBJECT go_truck EXPORTING iv_make = 'VOLVO' iv_cargo = 48. ***** Create Carrier CREATE OBJECT go_carrier EXPORTING iv_name = 'Smile&Fly'. ***** Passenger Plane TRY. CREATE OBJECT go_passenger EXPORTING iv_name = 'LH BERLIN' iv_planetype = '747-500' iv_seats = 345. CATCH cx_invalid_value INTO gx_inv_value. gv_text = gx_inv_value->get_text( ). WRITE: / icon_failure AS ICON, gv_text. gv_text = gx_inv_value->previous->get_text( ). WRITE: / icon_failure AS ICON, gv_text. * * * * *
CATCH cx_invalid_planetype INTO gx_inv_planetype. gv_text = gx_inv_planetype->get_text( ). WRITE: / icon_failure AS ICON, gv_text. ENDTRY.
***** cargo Plane TRY.
© Copyright . Reservados todos los derechos.
421
Capítulo 9: Tratamiento de excepciones orientadas a objetos
CREATE OBJECT go_cargo EXPORTING iv_name = 'US Hercules' iv_planetype = '747-200F' iv_cargo = 533. CATCH cx_invalid_value INTO gx_inv_value. gv_text = gx_inv_value->get_text( ). WRITE: / icon_failure AS ICON, gv_text. gv_text = gx_inv_value->previous->get_text( ). WRITE: / icon_failure AS ICON, gv_text. * * * * *
CATCH cx_invalid_planetype INTO gx_inv_planetype. gv_text = gx_inv_planetype->get_text( ). WRITE: / icon_failure AS ICON, gv_text. ENDTRY.
***** show attributes of all partners of travel_agency go_agency->display_attributes( ).
422
© Copyright . Reservados todos los derechos.
Lección: Implementación de técnicas avanzadas de tratamiento de excepciones
RESUMEN DE LA LECCIÓN Ahora podrá: ●
Explicar la jerarquía de las clases de excepción predefinidas
●
Explicar las distintas formas de tratar una excepción
●
Reintentar después de las excepciones
●
Implementar excepciones reanudables
●
Volver a emitir las excepciones
●
Asignar excepciones unas a otras
© Copyright . Reservados todos los derechos.
423
Capítulo 9: Tratamiento de excepciones orientadas a objetos
424
© Copyright . Reservados todos los derechos.
Capítulo 9 Evaluación de la formación
1. ¿Cuál de las siguientes afirmaciones se utiliza para emitir excepciones basadas en clases? Seleccione la respuesta correcta. X
A EXPORTING
X
B RAISE EXCEPTION
X
C CREATE OBJECT
X
D CATCH
2. De los siguientes bloques, ¿cuál se utiliza para interceptar y tratar excepciones? Seleccione la respuesta correcta. X
A IMPORTING….RETURNING
X
B METHOD…. ENDMETHOD
X
C TRY … ENDTRY
X
D TRY...CATCH...ENDTRY
3. Solo puede tratarse una excepción si la sentencia que la emitió se encuentra en una estructura de control TRY-ENDTRY. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
4. Las estructuras TRY-ENDTRY pueden anidarse a cualquier profundidad. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
425
Capítulo 9: Evaluación de la formación
5. Es posible especificar solo dos clases de excepción para la sentencia CATCH. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
6. Si se emite una excepción, el nombre de la clase de excepción se visualizará en el campo __________ en modo debugging. Seleccione la respuesta correcta. X
A excepción emitida
X
B último objeto de excepción
X
C watchpoint
X
D disposición
7. De las siguientes opciones, ¿cuál es el paso para definir las clases de excepción global? Seleccione la respuesta correcta. X
A Crear una clase global con el tipo de clase como clase de excepción.
X
B Definir atributos adicionales.
X
C Grabar como textos de excepción.
X
D Active la clase de la excepción.
8. De los siguientes suplementos de sintaxis, ¿cuál se usa para propagar una excepción de un procedimiento? Seleccione la respuesta correcta.
426
X
A CATCH
X
B RAISING
X
C METHODS
X
D FORM
© Copyright . Reservados todos los derechos.
Capítulo 9: Evaluación de la formación
9. Para subclases de ____________, las excepciones correspondientes no pueden propagarse explícitamente mediante el suplemento RAISING. Seleccione la respuesta correcta. X
A CX_STATIC_CHECK
X
B CX_NO_CHECK
X
C CX_DYNAMIC_CHECK
10. De las siguientes opciones, ¿cuál o cuáles son las formas de tratar una excepción? Seleccione las respuestas correctas. X
A Continuar la ejecución del programa
X
B Quitar la causa del error
X
C No propagar una excepción
X
D Llamar el método CX_SYSTEM_HANDLE
11. De las siguientes opciones, ¿cuál se utiliza para retroceder hacia la sentencia TRY? Seleccione la respuesta correcta. X
A RETRY
X
B CATCH
X
C TRY-ENTRY
X
D RAISE
12. De las siguientes opciones, ¿cuál es una condición previa para el uso de la sentencia RESUME? Seleccione las respuestas correctas. X
A La excepción debe interceptarse con el suplemento BEFORE UNWIND.
X
B La excepción debe marcarse como reanudable.
X
C La excepción debe propagarse con el suplemento RESUMABLE( ).
X
D La excepción debe emitirse con el suplemento RESUMABLE.
© Copyright . Reservados todos los derechos.
427
Capítulo 9: Evaluación de la formación
13. De las siguientes sentencias, ¿cuál emite un nuevo objeto de excepción? Seleccione las respuestas correctas.
428
X
A RAISE
X
B RESUME
X
C CATCH
© Copyright . Reservados todos los derechos.
Capítulo 9 Respuestas a la Evaluación de la formación
1. ¿Cuál de las siguientes afirmaciones se utiliza para emitir excepciones basadas en clases? Seleccione la respuesta correcta. X
A EXPORTING
X
B RAISE EXCEPTION
X
C CREATE OBJECT
X
D CATCH
2. De los siguientes bloques, ¿cuál se utiliza para interceptar y tratar excepciones? Seleccione la respuesta correcta. X
A IMPORTING….RETURNING
X
B METHOD…. ENDMETHOD
X
C TRY … ENDTRY
X
D TRY...CATCH...ENDTRY
3. Solo puede tratarse una excepción si la sentencia que la emitió se encuentra en una estructura de control TRY-ENDTRY. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
4. Las estructuras TRY-ENDTRY pueden anidarse a cualquier profundidad. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
429
Capítulo 9: Respuestas a la Evaluación de la formación
5. Es posible especificar solo dos clases de excepción para la sentencia CATCH. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
6. Si se emite una excepción, el nombre de la clase de excepción se visualizará en el campo __________ en modo debugging. Seleccione la respuesta correcta. X
A excepción emitida
X
B último objeto de excepción
X
C watchpoint
X
D disposición
7. De las siguientes opciones, ¿cuál es el paso para definir las clases de excepción global? Seleccione la respuesta correcta. X
A Crear una clase global con el tipo de clase como clase de excepción.
X
B Definir atributos adicionales.
X
C Grabar como textos de excepción.
X
D Active la clase de la excepción.
8. De los siguientes suplementos de sintaxis, ¿cuál se usa para propagar una excepción de un procedimiento? Seleccione la respuesta correcta.
430
X
A CATCH
X
B RAISING
X
C METHODS
X
D FORM
© Copyright . Reservados todos los derechos.
Capítulo 9: Respuestas a la Evaluación de la formación
9. Para subclases de ____________, las excepciones correspondientes no pueden propagarse explícitamente mediante el suplemento RAISING. Seleccione la respuesta correcta. X
A CX_STATIC_CHECK
X
B CX_NO_CHECK
X
C CX_DYNAMIC_CHECK
10. De las siguientes opciones, ¿cuál o cuáles son las formas de tratar una excepción? Seleccione las respuestas correctas. X
A Continuar la ejecución del programa
X
B Quitar la causa del error
X
C No propagar una excepción
X
D Llamar el método CX_SYSTEM_HANDLE
11. De las siguientes opciones, ¿cuál se utiliza para retroceder hacia la sentencia TRY? Seleccione la respuesta correcta. X
A RETRY
X
B CATCH
X
C TRY-ENTRY
X
D RAISE
12. De las siguientes opciones, ¿cuál es una condición previa para el uso de la sentencia RESUME? Seleccione las respuestas correctas. X
A La excepción debe interceptarse con el suplemento BEFORE UNWIND.
X
B La excepción debe marcarse como reanudable.
X
C La excepción debe propagarse con el suplemento RESUMABLE( ).
X
D La excepción debe emitirse con el suplemento RESUMABLE.
© Copyright . Reservados todos los derechos.
431
Capítulo 9: Respuestas a la Evaluación de la formación
13. De las siguientes sentencias, ¿cuál emite un nuevo objeto de excepción? Seleccione las respuestas correctas.
432
X
A RAISE
X
B RESUME
X
C CATCH
© Copyright . Reservados todos los derechos.
CAPÍTULO 10
Llamadas de programa y gestión de memoria
Lección 1 Uso de objetos compartidos Ejercicio 25: Utilizar objetos compartidos
434 451
OBJETIVOS DEL CAPÍTULO ●
Explicar los objetos compartidos
●
Utilizar objetos compartidos
© Copyright . Reservados todos los derechos.
433
Capítulo 10 Lección 1 Uso de objetos compartidos
RESUMEN DE LA LECCIÓN En este módulo se explica cómo puede grabar datos como objetos compartidos en memoria compartida y examinar este concepto y su implementación. Ejemplo empresarial Desea desarrollar una transacción en la cual muchos usuarios pueden acceder a los mismos datos simultáneamente sin tener que leerlos cada vez de la base de datos. Sabe que los objetos compartidos pueden utilizarse para poder acceder a los datos de la memoria principal sin límites de modo. Por consiguiente, debe familiarizarse con esta técnica. Por este motivo, se requieren los siguientes conocimientos: ●
●
●
Un resumen de cómo se crean clases para objetos compartidos Un resumen de cómo se pueden utilizar objetos compartidos para implementar aplicaciones Un resumen del acceso a objetos compartidos desde un programa ABAP
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Explicar los objetos compartidos
●
Utilizar objetos compartidos
Motivación A partir de SAP NetWeaver 2004, puede grabar datos como objetos compartidos en la memoria compartida, en diferentes programas e incluso en diferentes sesiones de usuario. Por consiguiente, puede crear aplicaciones en las que los usuarios escriben datos en este área. Otros usuarios pueden leer estos datos más adelante. Los usos potenciales de los objetos compartidos son los siguientes: ●
Grabar un catálogo Un “autor” escribe el catálogo en el área de objetos compartidos. Muchos usuarios pueden acceder a este catálogo al mismo tiempo.
●
Grabar una cesta de la compra El encargado de compras rellena la cesta de la compra y el vendedor lee la cesta de la compra rellena más adelante.
434
© Copyright . Reservados todos los derechos.
Lección: Uso de objetos compartidos
Memoria compartida
Figura 160: Modelo de memoria de un servidor de aplicación
La memoria compartida es un área de la memoria de un servidor de aplicación al que pueden acceder todos los programas ABAP que se ejecutan en el mismo servidor. Antes de que SAP introdujera los objetos compartidos, las sentencias ABAP debían utilizar las sentencias EXPORT e IMPORT con los suplementos HARED BUFFER y SHARED MEMORY para acceder a esta área de la memoria. Las instancias de clases estaban activas exclusivamente en el modo interno de un programa ABAP. Con la introducción de los objetos compartidos en SAP NetWeaver 2004, la memoria compartida se ha ampliado con Memoria de objetos compartidos, donde el usuario puede grabar los objetos compartidos. Puede grabar objetos compartidos en áreas de la memoria compartida.
Nota: Se pueden grabar las instancias de clases. Aún no es posible grabar ningún objeto de datos como objeto compartido. Sin embargo, puede grabar objetos de datos además de las variables de referencia como atributos de clases.
© Copyright . Reservados todos los derechos.
435
Capítulo 10: Llamadas de programa y gestión de memoria
Acceder a objetos compartidos
Figura 161: Acceso a objetos compartidos
En la figura de arriba se explica cómo se visualiza un objeto compartido mediante dos sesiones de usuario de manera simultánea.
Objetos compartidos Estos son puntos importantes sobre los objetos compartidos: ●
Grabación en la memoria intermedia de todos los programas de datos que se leen con frecuencia, pero raramente se escriben.
●
Los accesos de lectura concurrentes son admitidos por los objetos compartidos.
●
El acceso es controlado por un mecanismo de bloqueo.
●
Los datos se graban como atributos de objetos.
●
Los cuellos de botella de memoria derivan en errores en tiempo de ejecución y debe identificarlos.
Los accesos de escritura no deben ser frecuentes debido a que la escritura de datos en el área de objetos compartidos consume mucho rendimiento. En concreto, desea optimizar el tiempo de ejecución, lo cual no sería posible en caso de que el acceso de lectura se realizara con mayor frecuencia.
Nota: SAP también utiliza objetos compartidos en SAP NetWeaver 2004. Por ejemplo, esta técnica se utiliza para navegar en Workbench ABAP. Además del ahorro de memoria, que es aproximadamente de 3 MB por inicio de sesión del usuario, la navegación durante el primer acceso es más rápido en un factor de 100.
436
© Copyright . Reservados todos los derechos.
Lección: Uso de objetos compartidos
Un requisito previo para grabar un objeto en la memoria compartida es que debe definir la clase del objeto con el suplemento SHARED MEMORY ENABLED de la sentencia CLASS. Además, puede seleccionar el atributo SHARED MEMORY ENABLED en el CLASS BUILDER.
Áreas e instancias de área
Figura 162: Áreas e instancias de área
Un área es una plantilla para instancias de área en la memoria compartida. Un área puede generar varias instancias de área con diferentes nombres. Además, una instancia de área puede tener varias versiones con distintos ID de versión o números de versión. En el más sencillo de los casos, sin gestión de versiones, una instancia de área consta de una única versión.
Clases de área y handles de área
Figura 163: Creación de un área
© Copyright . Reservados todos los derechos.
437
Capítulo 10: Llamadas de programa y gestión de memoria
Defina un área en la transacción SHMA. Se crea una clase de área final global con el mismo nombre. Se trata de una subclase de CL_SHM_AREA. En un programa ABAP, puede acceder al área exclusivamente mediante métodos de la clase de área generada.
Consejo: Dado que el área y la clase de área tienen el mismo nombre, es recomendable asignar un nombre al área según las convenciones para fijar nombres correspondientes a las clases – ZCL_*, por ejemplo, en el área para nombres del cliente. Puede utilizar métodos estáticos (métodos para vincular) de una clase de área para vincular un programa ABAP, o su modo interno donde el sistema procesa el programa ABAP, a una instancia de área en la memoria compartida. Al vincular un programa ABAP, se crea una instancia de la clase de área como un manejador de área. En la figura también se muestra otra clase, que es la clase de raíz de área. Puede crear cualquier número de objetos en una instancia de área, dependiendo del programa específico. Acceda a estos objetos de manera uniforme a través de la instancia de la clase de raíz de área.
Nota: En un ejemplo específico, se limitarán a dos clases.
Aplicación de ejemplo
Figura 164: Aplicación de ejemplo
En este módulo, desarrollará una sencilla aplicación de catálogo como ejemplo. Desea utilizar objetos compartidos para crear un catálogo de fechas de vuelo donde los usuarios puedan seleccionar rápidamente cualquier vuelo.
438
© Copyright . Reservados todos los derechos.
Lección: Uso de objetos compartidos
Acceder a áreas
Figura 165: Acceso a áreas
En la figura se destaca el hecho de que cualquier programa puede acceder a objetos en la memoria de objetos compartidos. En este caso, dos aplicaciones, que se ejecutan en diferentes modos de usuario, acceden a objetos en la misma área. Para la aplicación de ejemplo, estos son los requisitos: ● Creación de un área ●
Desarrollo de un programa para crear una instancia de área
●
Desarrollo de un programa para leer datos desde el área
Área de memoria compartida – Definición
Figura 166: Gestión de área
Grabe objetos compartidos en áreas de la memoria compartida. Utilice la transacción SHMA para crear y gestionar áreas y sus atributos.
© Copyright . Reservados todos los derechos.
439
Capítulo 10: Llamadas de programa y gestión de memoria
Consejo: Tenga en cuenta que debe llamar el código de transacción SHMA directamente en SAP NetWeaver 2004, debido a que aún no se ha agregado al árbol de menú. Llame el código de transacción SHMA e introduzca el nombre del área. Se aplican las reglas habituales del área de nombres, es decir, el nombre de área debe empezar por Y o Z en el sistema del cliente. El sistema también admite áreas de nombres que contengan barras diagonales.
Consejo: Para esta área, el sistema genera una clase de área global y final con nombre idéntico como una subclase de CL_SHM_AREA. Por lo tanto, se recomienda seleccionar el nombre de área con inteligencia, tal como se muestra en el ejemplo. En un programa ABAP, se accede a un área exclusivamente mediante métodos de la clase de área generada. Actualización de áreas
Figura 167: Actualización de áreas
Una vez que seleccione uno de los pulsadores Crear, Modificar o Visualizar, el sistema muestra la pantalla de actualización de áreas. El sistema ha vinculado cada área con una clase de raíz de área global, cuyos atributos pueden contener datos de propiedad y referencias a otras clases compartidas de memoria habilitada. Cuando se actualice, deberá asignar la clase de raíz de área a un área. Si una versión de instancia de área no está vacía, debe contener, al menos, una instancia de la clase de raíz de área como su objeto raíz, que el sistema utiliza como referencia a otros objetos. Al
440
© Copyright . Reservados todos los derechos.
Lección: Uso de objetos compartidos
generar la clase de área, el sistema genera y tipifica un atributo ROOT con el tipo estático de la clase de raíz de área. Estos son los términos importantes para crear un área: ● Área dependiente del mandante Las áreas y, por tanto, los objetos de un área, no tienen un ID de mandante por defecto. No obstante, puede especificar un área como dependiente del mandante. En las áreas dependientes del mandante, los métodos de la clase de área para acceder a una instancia de área hacen referencia al mandante activo por defecto. Puede utilizar el parámetro de importación opcional CLIENT para acceder explícitamente a otro mandante. ●
Área transaccional Una versión de instancias de área de un área transaccional no está activa inmediatamente después de eliminar un bloqueo de modificación con el método DETACH_COMMIT. No está activa hasta el próximo commit de base de datos. Esto resulta particularmente útil en la implementación de cestas de la compra en la memoria de objetos compartidos.
Área de memoria compartida – Acceso de escritura
Figura 168: Antes de crear una instancia de área
Ha definido un área. También ha creado las clases que se instanciarán. Ahora, examine las sentencias que pueden utilizarse para crear una instancia de área. Continúe utilizando el ejemplo anterior. Al crear un área, el sistema crea una clase final global con el mismo nombre. Para configurar un área o un acceso a un área existente, es necesaria una variable de referencia que pueda tipificar con la clase de área generada. Esta referencia se utiliza como un handle para acceder al área.
© Copyright . Reservados todos los derechos.
441
Capítulo 10: Llamadas de programa y gestión de memoria
Creación de instancia de área
Figura 169: Creación de instancia de área
Al crear una instancia de clase de área, el sistema crea una instancia del área en la memoria compartida. El programa debe obtener además el handle para la instancia de área. Realiza todas las operaciones mediante este handle. Generación de objetos en la memoria compartida
Figura 170: Generación de objetos en la memoria compartida
Una vez que cree la instancia de área, puede crear los objetos en la memoria de objetos compartida. Para ello, utilice el suplemento AREA HANDLE para la sentencia CREATE
442
© Copyright . Reservados todos los derechos.
Lección: Uso de objetos compartidos
OBJECT. Esta sentencia le informa al sistema sobre la instancia de área donde debería crear los objetos. Generación de objetos en la memoria compartida II
Figura 171: Generación de objetos en la memoria compartida II
En la figura se muestra cómo puede instanciar ambos objetos desde el programa. Otra opción es crear una instancia del objeto raíz desde el programa. Puede crear los demás objetos en esta instancia de área a partir del constructor de la raíz sin asignar referencias (en este caso). Configuración del objeto raíz
Figura 172: Configuración del objeto raíz
© Copyright . Reservados todos los derechos.
443
Capítulo 10: Llamadas de programa y gestión de memoria
Para poder direccionar los objetos que cree en la instancia de área, asigne el objeto raíz al atributo ROOT del manejador de área. Para hacerlo, utilice el método SET_ROOT del manejador de área. Como consecuencia, cualquier programa de cualquier aplicación puede acceder a este área. Para ello, la aplicación solamente tiene que llamar una referencia en la instancia de área y, a continuación, podrá acceder inmediatamente a los objetos que contiene dicha instancia de área. Liberación de bloqueo de escritura
Figura 173: Liberación de bloqueo de escritura
El acceso de lectura de una instancia de área no es posible hasta que la liberación del bloqueo de escritura. Para el acceso de lectura, utilice el método DETACH_COMMIT, que hereda la clase de área de la clase CL_SHM_AREA.
444
© Copyright . Reservados todos los derechos.
Lección: Uso de objetos compartidos
Área de memoria compartida – Acceso de lectura
Figura 174: Acceso a un objeto existente en la memoria compartida
Una vez que se ha configurado una instancia de área, cualquier usuario y aplicación podrá acceder a ella. Los programas de lectura deben realizar los siguientes pasos: 1. Los programas de lectura necesitan primero una variable de referencia que tipificó con la clase de área. Esta variable de referencia sirve como un handle para acceder a la instancia de área. 2. El programa obtiene el handle para la instancia de área mediante el método ATTACH_FOR_READ, que proporciona la clase CL_SHM_AREA. Esto fija un bloqueo de lectura que evita que el sistema elimine la instancia de área durante el acceso. 3. Ahora se puede acceder a los objetos de esta instancia de área siempre utilizando el manejador de área.
© Copyright . Reservados todos los derechos.
445
Capítulo 10: Llamadas de programa y gestión de memoria
Cancelación del bloqueo de lectura
Figura 175: Cancelación del bloqueo de lectura
Una vez que esté completa la actividad de lectura, la aplicación libera el bloqueo de lectura mediante el método DETACH del manejador de área. La aplicación libera automáticamente el bloqueo de lectura cuando la sesión interna se cierra después de una sentencia DETACH.
Área de memoria compartida – Versión
Figura 176: Configuración de un bloqueo de lectura en la versión activa
Al crear un área, puede especificar que el sistema permita varias versiones de una instancia de área. Para determinar qué significan exactamente estas versiones instancias de área, necesita examinar un ejemplo.
446
© Copyright . Reservados todos los derechos.
Lección: Uso de objetos compartidos
Un estado normal es cuando se ha configurado una instancia de área. Cuando la configuración haya finalizado mediante el método DETACH_COMMIT y el sistema haya enviado un commit en base de datos, se activa la versión de instancia de área. Versión objeto de la configuración
Figura 177: Versión objeto de la configuración
Si el atributo NUMBER OF VERSIONS del área está correctamente establecido, pueden existir versiones adicionales de la instancia de área además de la versión activa. Una vez que se ha configurado un nuevo catálogo, existen varias versiones temporales de la misma instancia de área. Tan pronto como una aplicación establece un bloqueo de modificación para una instancia de área, se crea una “versión objeto de configuración” en paralelo con la versión activa.
© Copyright . Reservados todos los derechos.
447
Capítulo 10: Llamadas de programa y gestión de memoria
Escritura finalizada – La versión anterior está desfasada
Figura 178: Escritura finalizada – La versión anterior está desfasada
Si finaliza la configuración de la nueva versión durante un acceso de lectura de la versión actualmente activa, se activa la versión objeto de configuración. A la versión anteriormente activa se le asigna el atributo OUTDATED. Nuevos bloqueos de lectura para la nueva versión activa
Figura 179: Nuevos bloqueos de lectura para la nueva versión activa
Los bloqueos de lectura de la versión desfasada se mantienen hasta que finalicen las operaciones de lectura. En contraste, los nuevos bloqueos de lectura para la instancia de área
448
© Copyright . Reservados todos los derechos.
Lección: Uso de objetos compartidos
están siempre establecidos para la versión activa. Por lo tanto, dos lectores diferentes pueden producir dos resultados de lectura distintos en este caso. No existen más bloqueos de lectura para la versión desfasada – Versión vencida
Figura 180: No existen más bloqueos de lectura para la versión desfasada – Versión vencida
Cuando elimina el último bloqueo de lectura existente de la versión desfasada, esta vence. El recolector de basura elimina la versión vencida. No puede fijar ningún bloqueo de lectura para las versiones que venden ni utilizarlo para determinar el número de versiones. Eso es importante si el sistema limita la cantidad de versiones de instancia de área. Nuevos bloqueos de lectura para la versión activa
Figura 181: Nuevos bloqueos de lectura para la versión activa
© Copyright . Reservados todos los derechos.
449
Capítulo 10: Llamadas de programa y gestión de memoria
Siempre se establecen nuevos bloqueos de lectura para la versión activa. Sólo puede haber una versión activa para cada instancia. Dependiendo del número máximo de versiones, pueden existir en paralelo a la nueva versión varias versiones desfasadas para las cuales aún están establecidos bloqueos de lectura.
450
© Copyright . Reservados todos los derechos.
Capítulo 10 Ejercicio 25 Utilizar objetos compartidos
Ejemplo empresarial Desea poner en funcionamiento una tienda en Internet basándose en un sistema SAP. Para que sus clientes de Internet puedan acceder lo más rápido posible a su catálogo, grábelo en la memoria de objetos compartidos. Escriba un programa para gestionar y describir el catálogo y desarrollar una aplicación de test para leer los datos. Modelo Ninguno Solución CL_BC402_SHS_ROOT (clase global) CL_BC402_SHS_CATALOG (clase global) BC402_SHS_WRITE_CATALOG (programa ejecutable) BC402_SHS_READ_CATALOG (programa ejecutable) Cree un área de objetos compartidos, escriba y lea datos en esta área. Tarea 1 Crear un área en la memoria de objetos compartidos (nombre sugerido: ZCL_BC402_##_AREA, donde ## representa su número de grupo). 1. Utilice la transacción SHMA para crear un área en la memoria compartida. Este área deberá contener los siguientes atributos: ●
Área específica del mandante
●
Con la versión
●
Desplazamiento imposible
El sistema le solicita automáticamente que especifique una clase raíz. Cree una clase de área raíz (nombre sugerido: ZCL_BC402_##_ROOT). 2. Implemente la clase de raíz de área. Simplemente debe contener una referencia a la clase de catálogo que creará en la siguiente tarea del ejercicio. Tarea 2 Cree una clase global donde se grabarán los datos del catálogo (nombre sugerido: CL_BC402_##_CATALOG). Esta clase requiere un método para escribir los datos de catálogo y otro método para recuperar los datos. También requiere un atributo global y una tabla interna que grabe los datos de catálogo.
© Copyright . Reservados todos los derechos.
451
Capítulo 10: Llamadas de programa y gestión de memoria
1. Cree una clase global para hoteles. Tenga en cuenta que, en esta clase, la memoria compartida debería estar habilitada. 2. Cree un atributo de instancia privado en la clase (nombre sugerido: MT_CATALOG). Introdúzcalo con un tipo de tabla que posee la estructura SDYN_CONN como tipo de línea. 3. Cree un método de instancia público para rellenar el catálogo (nombre sugerido: FILL_CATALOG). Este método requiere un parámetro de importación que asignará la tabla interna con datos. Implemente el método. 4. Cree un segundo método de instancia público que pueda utilizarse para responder consultas sobre fechas de vuelo (nombre sugerido: GET_FLIGHTS). Este método requiere un parámetro de importación para las ciudades de salida y de destino, así como dos parámetros adicionales para las diferentes fechas de vuelo. El método necesita también un parámetro de exportación que devuelva los vuelos coincidentes. Implemente el método. Tarea 3 Cree un programa ejecutable que construya el área en la memoria de objetos compartidos (nombre sugerido: ZBC402_##_WRITE_CATALOG). Se supone además que este programa lee los datos de catálogo de la base de datos y los pasa a la clase adecuada. 1. Cree un programa ejecutable. 2. Defina tres variables de referencia, una para el manejador de área, otra para la clase de raíz de área y otra para la clase de catálogo. 3. Cree un área, una instancia de la clase de catálogo y una instancia de la clase de raíz de área. Configure el área. Lea los datos de catálogo necesarios de las tablas SPFLI y SFLIGHT. 4. No olvide eliminar el bloqueo de escritura una vez que los datos se hayan escrito correctamente. 5. Ejecute el programa y, a continuación, utilice el Monitor de objetos compartidos para examinar el área de memoria compartida. Tarea 4 Implemente un programa de lectura para leer datos del área que acaba de crear (nombre sugerido: ZBC402_##_READ_CATALOG). Muestre los datos en un diálogo de usuario simple (utilizando el módulo de funciones proporcionado BC402_DISPLAY_TABLE, por ejemplo). 1. Cree un programa ejecutable. 2. Defina una imagen de selección donde el usuario pueda introducir las ciudades de salida y de destino. El usuario debe poder introducir la fecha de vuelo más cercana y la más lejana posible. 3. Asegúrese de que los datos se leen del objeto de catálogo. Muestre los datos en el diálogo de usuario.
452
© Copyright . Reservados todos los derechos.
Capítulo 10 Solución 25 Utilizar objetos compartidos
Ejemplo empresarial Desea poner en funcionamiento una tienda en Internet basándose en un sistema SAP. Para que sus clientes de Internet puedan acceder lo más rápido posible a su catálogo, grábelo en la memoria de objetos compartidos. Escriba un programa para gestionar y describir el catálogo y desarrollar una aplicación de test para leer los datos. Modelo Ninguno Solución CL_BC402_SHS_ROOT (clase global) CL_BC402_SHS_CATALOG (clase global) BC402_SHS_WRITE_CATALOG (programa ejecutable) BC402_SHS_READ_CATALOG (programa ejecutable) Cree un área de objetos compartidos, escriba y lea datos en esta área. Tarea 1 Crear un área en la memoria de objetos compartidos (nombre sugerido: ZCL_BC402_##_AREA, donde ## representa su número de grupo). 1. Utilice la transacción SHMA para crear un área en la memoria compartida. Este área deberá contener los siguientes atributos: ●
Área específica del mandante
●
Con la versión
●
Desplazamiento imposible
El sistema le solicita automáticamente que especifique una clase raíz. Cree una clase de área raíz (nombre sugerido: ZCL_BC402_##_ROOT). a) Siga la demostración del instructor. 2. Implemente la clase de raíz de área. Simplemente debe contener una referencia a la clase de catálogo que creará en la siguiente tarea del ejercicio. a) Consulte el extracto del código fuente de la solución modelo. Tarea 2 Cree una clase global donde se grabarán los datos del catálogo (nombre sugerido: CL_BC402_##_CATALOG). Esta clase requiere un método para escribir los datos de catálogo y otro método para recuperar los datos. También requiere un atributo global y una tabla interna que grabe los datos de catálogo.
© Copyright . Reservados todos los derechos.
453
Capítulo 10: Llamadas de programa y gestión de memoria
1. Cree una clase global para hoteles. Tenga en cuenta que, en esta clase, la memoria compartida debería estar habilitada. a) Cree la clase en el GENERADOR DE CLASES. Utilice la solución modelo como guía. 2. Cree un atributo de instancia privado en la clase (nombre sugerido: MT_CATALOG). Introdúzcalo con un tipo de tabla que posee la estructura SDYN_CONN como tipo de línea. a) Consulte el extracto del código fuente de la solución modelo. 3. Cree un método de instancia público para rellenar el catálogo (nombre sugerido: FILL_CATALOG). Este método requiere un parámetro de importación que asignará la tabla interna con datos. Implemente el método. a) Consulte el extracto del código fuente de la solución modelo. 4. Cree un segundo método de instancia público que pueda utilizarse para responder consultas sobre fechas de vuelo (nombre sugerido: GET_FLIGHTS). Este método requiere un parámetro de importación para las ciudades de salida y de destino, así como dos parámetros adicionales para las diferentes fechas de vuelo. El método necesita también un parámetro de exportación que devuelva los vuelos coincidentes. Implemente el método. a) Consulte el extracto del código fuente de la solución modelo. Tarea 3 Cree un programa ejecutable que construya el área en la memoria de objetos compartidos (nombre sugerido: ZBC402_##_WRITE_CATALOG). Se supone además que este programa lee los datos de catálogo de la base de datos y los pasa a la clase adecuada. 1. Cree un programa ejecutable. a) Realice este paso de la forma habitual. 2. Defina tres variables de referencia, una para el manejador de área, otra para la clase de raíz de área y otra para la clase de catálogo. a) Consulte el extracto del código fuente de la solución modelo. 3. Cree un área, una instancia de la clase de catálogo y una instancia de la clase de raíz de área. Configure el área. Lea los datos de catálogo necesarios de las tablas SPFLI y SFLIGHT. a) Consulte el extracto del código fuente de la solución modelo. 4. No olvide eliminar el bloqueo de escritura una vez que los datos se hayan escrito correctamente. a) Consulte el extracto del código fuente de la solución modelo. 5. Ejecute el programa y, a continuación, utilice el Monitor de objetos compartidos para examinar el área de memoria compartida. a) Ejecute el programa y, a continuación, ejecute la transacción SHMM para examinar los detalles de la instancia del área de memoria compartida. Tarea 4 Implemente un programa de lectura para leer datos del área que acaba de crear (nombre sugerido: ZBC402_##_READ_CATALOG). Muestre los datos en un diálogo de usuario simple (utilizando el módulo de funciones proporcionado BC402_DISPLAY_TABLE, por ejemplo). 1. Cree un programa ejecutable. a) Realice este paso de la forma habitual.
454
© Copyright . Reservados todos los derechos.
Lección: Uso de objetos compartidos
2. Defina una imagen de selección donde el usuario pueda introducir las ciudades de salida y de destino. El usuario debe poder introducir la fecha de vuelo más cercana y la más lejana posible. a) Consulte el extracto del código fuente de la solución modelo. 3. Asegúrese de que los datos se leen del objeto de catálogo. Muestre los datos en el diálogo de usuario. a) Consulte el extracto del código fuente de la solución modelo. Clase CL_BC402_SHS_CATALOG: Implementación
METHOD fill_catalog. gt_catalog = it_catalog. ENDMETHOD. METHOD get_flights. FIELD-SYMBOLS: TYPE sdyn_conn. LOOP AT gt_catalog ASSIGNING WHERE cityfrom cityto fldate fldate
= = > <
iv_from_city AND iv_to_city AND iv_earliest AND iv_latest.
APPEND TO et_flights. ENDLOOP. ENDMETHOD.
Programa BC402_SHS_WRITE_CATALOG
REPORT
bc402_shs_write_catalog.
DATA: go_handle TYPE REF TO cl_bc402_shs_area, go_root TYPE REF TO cl_bc402_shs_root, go_catalog TYPE REF TO cl_bc402_shs_catalog, gt_flights TYPE
bc402_t_sdynconn.
START-OF-SELECTION. go_handle = cl_bc402_shs_area=>attach_for_write( ). CREATE OBJECT go_root AREA HANDLE go_handle. CREATE OBJECT go_catalog AREA HANDLE go_handle.
© Copyright . Reservados todos los derechos.
455
Capítulo 10: Llamadas de programa y gestión de memoria
go_root->mo_catalog = go_catalog. go_handle->set_root( root = go_root ). SELECT * FROM spfli JOIN sflight ON spfli~carrid = sflight~carrid AND spfli~connid = sflight~connid INTO CORRESPONDING FIELDS OF TABLE gt_flights. go_handle->root->mo_catalog->fill_catalog( it_catalog = gt_flights ). go_handle->detach_commit( ).
Programa BC402_SHS_READ_CATALOG
REPORT
bc402_shs_read_catalog.
DATA: go_handle gt_flights gs_flight
TYPE REF TO TYPE LIKE LINE OF
cl_bc402_shs_area, bc402_t_sdynconn, gt_flights,
gv_startdate TYPE sydatum, gv_enddate TYPE sydatum. PARAMETERS: pa_from pa_to SELECT-OPTIONS: so_date
TYPE spfli-cityfrom, TYPE spfli-cityto. FOR sy-datum NO-EXTENSION.
AT SELECTION-SCREEN. READ TABLE so_date INDEX 1. IF so_date IS INITIAL. so_date-low = sy-datum. so_date-high = sy-datum + 365. ENDIF. gv_startdate = sy-datum. gv_enddate = sy-datum + 365. IF so_date-low > sy-datum. gv_startdate = sy-datum. ENDIF. IF so_date-high < gv_enddate. gv_enddate = so_date-high. ENDIF. START-OF-SELECTION. go_handle = cl_bc402_shs_area=>attach_for_read( ).
456
© Copyright . Reservados todos los derechos.
Lección: Uso de objetos compartidos
go_handle->root->mo_catalog->get_flights( EXPORTING iv_from_city = pa_from iv_to_city = pa_to iv_earliest = gv_startdate iv_latest = gv_enddate IMPORTING et_flights = gt_flights ). go_handle->detach( ). CALL FUNCTION 'BC402_DISPLAY_TABLE' CHANGING ct_table = gt_flights.
© Copyright . Reservados todos los derechos.
457
Capítulo 10: Llamadas de programa y gestión de memoria
RESUMEN DE LA LECCIÓN Ahora podrá:
458
●
Explicar los objetos compartidos
●
Utilizar objetos compartidos
© Copyright . Reservados todos los derechos.
Capítulo 10 Evaluación de la formación
1. La memoria compartida es un área de la memoria de un servidor de aplicación al que pueden acceder los programas ABAP que se ejecutan en dicho servidor. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
2. El método __________ del manejador de área está disponible para la aplicación para liberar el bloqueo de lectura. Seleccione la respuesta correcta. X
A DETACH_COMMIT
X
B OUTDATED
X
C DETACH
© Copyright . Reservados todos los derechos.
459
Capítulo 10 Respuestas a la Evaluación de la formación
1. La memoria compartida es un área de la memoria de un servidor de aplicación al que pueden acceder los programas ABAP que se ejecutan en dicho servidor. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
2. El método __________ del manejador de área está disponible para la aplicación para liberar el bloqueo de lectura. Seleccione la respuesta correcta.
460
X
A DETACH_COMMIT
X
B OUTDATED
X
C DETACH
© Copyright . Reservados todos los derechos.
CAPÍTULO 11
Programación dinámica
Lección 1 Uso de los tipos de datos genéricos 462 Ejercicio 26: Utilizar Field Symbols tipificados de manera dinámica en sentencias SQL 469 dinámicas Ejercicio 27: Acceder a componentes de estructuras de manera dinámica 477
Lección 2 Descripción de tipos de datos, objetos de datos y objetos en tiempo de ejecución Ejercicio 28: Proporcionar cabeceras de columna con la identificación de tipos en tiempo de ejecución
486 497
Lección 3 Creación de tipos de datos, objetos de datos y objetos en tiempo de ejecución Ejercicio 29: Crear objetos de datos en tiempo de ejecución Ejercicio 30: Crear tipos de datos en tiempo de ejecución con la creación de tipos en tiempo de ejecución (RTTC)
OBJETIVOS DEL CAPÍTULO ●
Explicar los tipos de datos genéricos de ABAP
●
Utilizar tipos de datos genéricos
●
Acceder a objetos de datos de manera dinámica
●
Utilizar referencias de datos de tipo genérico
●
Explicar el principio de RTTI
●
Describir tipos de datos y objetos de datos en tiempo de ejecución
●
Describir tipos de objetos y objetos en tiempo de ejecución
●
Crear objetos (instancias) en tiempo de ejecución
●
Crear objetos de datos en tiempo de ejecución
●
Crear tipos de datos en tiempo de ejecución
© Copyright . Reservados todos los derechos.
461
507 513 523
Capítulo 11 Lección 1 Uso de los tipos de datos genéricos
RESUMEN DE LA LECCIÓN En este módulo se analiza cómo utilizar tipos de datos genéricos en ABAP para la programación dinámica. También analiza las limitaciones que la sintaxis de ABAP tiene en las referencias de datos genéricos y cómo estas limitaciones afectan el uso de datos genéricos. Ejemplo empresarial Necesita desarrollar una aplicación flexible. Por lo tanto, desea averiguar acerca de los tipos de datos genéricos en ABAP y conocer la forma de tipificar parámetros, Field Symbols y referencias de datos de manera genérica. Por este motivo, se requieren los siguientes conocimientos: ●
●
●
●
Un resumen de tipos genéricos y sus usos Un resumen de cómo utilizar parámetros, Field Symbols y referencias de datos de tipo genérico Un resumen de cómo utilizar símbolos de campos para acceder a objetos de datos de manera dinámica Un resumen de cómo utilizar símbolos de campos para acceder a atributos y componentes de estructura de manera dinámica
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá:
462
●
Explicar los tipos de datos genéricos de ABAP
●
Utilizar tipos de datos genéricos
●
Acceder a objetos de datos de manera dinámica
●
Utilizar referencias de datos de tipo genérico
© Copyright . Reservados todos los derechos.
Lección: Uso de los tipos de datos genéricos
Tipos de datos ABAP genéricos integrados
Figura 182: Tipo de datos ABAP genéricos
En la figura se muestran los tipos de datos genéricos predefinidos que admite la sintaxis ABAP. Además de los tipos de datos completos, ABAP también incluye varios tipos de datos genéricos. A diferencia de los tipos completos, no puede utilizar los tipos genéricos para definir las propiedades de los objetos de datos. Solo utilice tipos genéricos para tipificar parámetros formales y Field Symbols. Nota: Actualmente, los dos tipos integrados, ... TYPE REF TO OBJECT y ... TYPE REF TO DATA son los únicos tipos disponibles para tipificar las variables de referencia de manera genérica. Tipo de datos ABAP genéricos – Tablas internas
Figura 183: Tipo de datos ABAP genéricos – Tablas internas
© Copyright . Reservados todos los derechos.
463
Capítulo 11: Programación dinámica
Consejo: La mayoría de los tipos genéricos, como clike, csequence, numeric, simple y xsequence, están disponibles a partir de SAP Web AS 6.10. El tipo genérico decfloat está disponible a partir de SAP NetWeaver 7.0 EhP 2. En la figura se muestran los tipos de datos ABAP genéricos, que son compatibles con el set de tipos ABAP. Cuando llame a un procedimiento, el sistema verifica si el tipo del parámetro real es compatible con el tipo del parámetro formal. Cuando asigne un Field Symbol de tipo genérico, la verificación de sintaxis prueba si el tipo de objeto de datos es compatible con el tipo genérico del Field Symbol.
Nota: El tipo DATA tiene el mismo comportamiento que ANY. La diferenciación es exclusivamente teórica en este momento. Sin embargo, en el futuro, las variables de referencia con el tipo TYPE REF TO ANY pueden ser posibles para señalar los objetos de datos o las instancias de clases. ANY TABLE, INDEX TABLE, SORTED TABLE y otros tipos son tipos de datos genéricos especiales que solo son compatibles con las tablas internas. Puede restringirlos a tablas internas con un tipo de tabla específico. Sin embargo, el tipo de línea y la definición de clave permanecen abiertos.
Tipos de tabla genéricos definidos libremente
Figura 184: Tipos de tabla genéricos – Definidos por el usuario
Además de estos tipos de tabla genéricos integrados, ABAP también contiene tipos de tabla genéricos que los desarrolladores crean como tipos genéricos. Estos tipos de tabla genéricos se crean en el Diccionario ABAP o en el código de fuente del programa con la sentencia TYPES. En la figura se muestra un ejemplo de los tipos de tabla genéricos definidos en el ámbito local. En estos tipos de tabla genéricos, define el tipo de línea, pero el tipo de tabla o la definición de clave permanecen abiertos.
464
© Copyright . Reservados todos los derechos.
Lección: Uso de los tipos de datos genéricos
Nota: Para crear tipos genéricos adecuados en el Diccionario ABAP, controle las opciones correspondientes en Acceso y Clave. Además de los tipos de tabla genéricos, no hay tipos de tabla genéricos definidos por el usuario en ABAP.
Parámetros de tipo genérico
Figura 185: Problemas cuando los parámetros son demasiado generales
Cuando los parámetros formales de un procedimiento, como subrutina, módulo de funciones o método, se tipifican genéricamente, el procedimiento es más flexible. Utilice la verificación de sintaxis para asegurarse de que el procedimiento trate los diferentes tipos. La verificación de sintaxis asegura que el sistema traspase solo los parámetros reales con tipos compatibles para parámetros formales tipificados de forma genérica. Cuando los parámetros de tipo genérico se direccionan en las sentencias ABAP, espere para determinar si el tipo de objeto de datos subyacente o su contenido actual es lógico en la posición de operando correspondiente. Si se produce un conflicto, el sistema presenta errores de tiempo de ejecución que no se interceptan en la mayoría de los casos. En la figura se muestra un ejemplo. Si asigna una tabla interna o una estructura que no es plana ni alfanumérica al parámetro, la sentencia WRITE emite una excepción interceptable, OBJECTS_NOT_CHARCONV. La verificación de sintaxis ayuda a evitar errores de tiempo de ejecución, particularmente, en las posiciones de operando que solo admiten tablas internas, como SELECT ... INTO TABLE ... y LOOP AT TABLE .... La sintaxis solo acepta los tipos de tablas genéricos en estas posiciones de operando. Por consiguiente, asegúrese de que aparezca una tabla interna después del parámetro formal.
© Copyright . Reservados todos los derechos.
465
Capítulo 11: Programación dinámica
Para evitar errores de sintaxis y de tiempo de ejecución, seleccione los tipos genéricos que son lo suficientemente específicos para utilizarse con todos los tipos compatibles en la posición de operando deseada. Tipifique de manera precisa para evitar errores
Figura 186: Evitar errores asignando tipos con la mayor precisión posible
Si utiliza el tipo genérico SIMPLE, la sentencia WRITE no provoca errores de tiempo de ejecución. Puede convertir todos los tipos de datos que son compatibles con SIMPLE a un string de caracteres. Los errores de sintaxis se corrigen porque el parámetro it_data ahora solo acepta tablas internas, debido a su tipo, ANY TABLE.
Consejo: Aún puede producirse un error de tiempo de ejecución si el método contiene un acceso mediante índice a it_data; específicamente, si el parámetro real es una tabla Hashed. Utilice el tipo genérico INDEX TABLE para limitar aún más el parámetro formal.
466
© Copyright . Reservados todos los derechos.
Lección: Uso de los tipos de datos genéricos
Field Symbols de tipo genérico
Figura 187: Ejemplo – Field Symbol genérico en SELECT dinámica
Los Field Symbols son punteros que asigna a objetos de datos de manera dinámica. Cuando el Field Symbol se utiliza en una sentencia ABAP, defina de manera dinámica los objetos de datos específicos a los que hace referencia el Field Symbol. Si el Field Symbol es de tipo completo, todos los objetos de datos potenciales tienen el mismo tipo, lo cual limita los posibles usos de los Field Symbols de manera significativa. La asignación de tipos genéricos permite que el Field Symbol haga referencia a los objetos de datos con tipos diferentes. Como resultado, puede direccionar objetos de datos diferentes en la misma posición de operando de una sentencia ABAP. En la figura se muestra un ejemplo de cómo utilizar un Field Symbol en una sentencia SELECT dinámica. Para comandar el programa a acceder una de las dos tabals de base de datos, SCARR o SBOOK, según el contenido del objeto de datos lv_table_name, programe una sentencia SELECT dinámica. Para garantizar que el tipo de línea de la tabla interna coincida con la lista de campo de la tabla de base de datos, utilice un Field Symbol de tipo genérico como destino que señala la tabla interna lt_scarr o lt_sbook según sea necesario.
Consejo: El Field Symbol no puede tener el tipo ANY. Si asigna este tipo a las dos tablas internas sin problemas, causa un error de sintaxis cuando se utiliza en la sentencia SELECT.
Nota: Este ejemplo es solo dinámico hasta cierto punto por los objetos de datos deben definirse de manera estática.
© Copyright . Reservados todos los derechos.
467
Capítulo 11: Programación dinámica
Casting de tipo para Field Symbols
Figura 188: Casting de tipo para Field Symbols
Para eliminar las limitaciones del tipo original del objeto de datos, utilice el suplemento CASTING para asignar un objeto de datos a un Field Symbol. Este Field Symbol tiene un tipo diferente. El objeto de datos se interpreta como si tuviera el tipo de datos del Field Symbol. Para acceder al objeto de datos utilizando el Field Symbol como si el objeto tuviera un tipo especificado explícitamente, utilice el suplemento CASTING TYPE. La sentencia CASTING TYPE se utiliza para asignar un objeto de datos a un Field Symbol. Este Field Symbol tiene un tipo diferente. En la figura, observe que el campo de sistema es un componente alfanumérico elemental de longitud 8.
468
© Copyright . Reservados todos los derechos.
Capítulo 11 Ejercicio 26 Utilizar Field Symbols tipificados de manera dinámica en sentencias SQL dinámicas
Ejemplo empresarial Debe desarrollar un programa sencillo que visualice los contenidos de cualquier tabla de base de datos. Averigüe las opciones disponibles en la programación dinámica. Defina la tabla de base de datos en una sentencia SELECT de manera dinámica y utilice un Field Symbol tipificado genéricamente para especificar el intervalo de destino de una sentencia SELECT de manera dinámica. Tarea 1 Copie el programa BC402_DYS_DYN_CALL o su propio programa, ZBC402_##_DYN_CALL y denomínelo ZBC402_##_DYN_SQL, donde ## es su número de grupo. Familiarícese con el programa y su funcionamiento. 1. Copie el programa y todos sus subcomponentes. 2. Active y realice un test del programa. Analice el código fuente. ¿Cómo se leen los datos desde la base de datos y en que objetos de datos se rellena?
Tarea 2 Reemplace las dos sentencias SELECT con una sentencia SELECT individual después de la sentencia ENDCASE. Especifique el nombre de la tabla como un objeto de datos alfanumérico. También utilice un Field Symbol de tipo genérico como intervalo de destino (cláusula INTO) al cual asigna un objeto de datos adecuado de manera dinámica. 1. Defina un objeto de datos alfanumérico para el nombre de la tabla (el nombre sugerido es gv_tabname). Rellene el objeto de datos con los nombres de tablas correspondientes en los bloques WHEN. 2. Cree un Field Symbol (el nombre sugerido es ) cuyo tipo se asigne como objeto de datos gt_conn o gt_cust. 3. ¿Por qué el tipo ANY no es adecuado? 4. Asigne el Field Symbol a las tablas internas correspondientes en los bloques WHEN; aquellas que desea rellenar en la sentencia genérica SELECT. 5. Mueva una de las dos sentencias llamadas SELECT del bloque WHEN después de la sentencia ENDCASE y elimine la otra. Convierta el acceso a la base de datos restante en dinámico. Reemplace el nombre de la tabla estática con el objeto de datos gv_tabname y reemplace el intervalo de destino (tabla interna) con el Field Symbol.
© Copyright . Reservados todos los derechos.
469
Capítulo 11: Programación dinámica
Tarea 3 Opcional Intercepte los errores de tiempo de ejecución específicos que se producen cuando utiliza sentencias SQL dinámicas. 1. Lea la documentación de palabras clave para averiguar acerca de las excepciones que se producen cuando utiliza las sentencias SQL dinámicas. Implemente el tratamiento de excepciones con TRY... CATCH ... ENDTRY. Implemente un bloque CATCH diferente para cada una de las clases de excepción o utilice un bloque CATCH individual para la clase superior compartida. Si se produce un error, responda con el mensaje de error 061 de la clase de mensaje BC402.
470
© Copyright . Reservados todos los derechos.
Capítulo 11 Solución 26 Utilizar Field Symbols tipificados de manera dinámica en sentencias SQL dinámicas
Ejemplo empresarial Debe desarrollar un programa sencillo que visualice los contenidos de cualquier tabla de base de datos. Averigüe las opciones disponibles en la programación dinámica. Defina la tabla de base de datos en una sentencia SELECT de manera dinámica y utilice un Field Symbol tipificado genéricamente para especificar el intervalo de destino de una sentencia SELECT de manera dinámica. Tarea 1 Copie el programa BC402_DYS_DYN_CALL o su propio programa, ZBC402_##_DYN_CALL y denomínelo ZBC402_##_DYN_SQL, donde ## es su número de grupo. Familiarícese con el programa y su funcionamiento. 1. Copie el programa y todos sus subcomponentes. a) Realice este paso como siempre. 2. Active y realice un test del programa. Analice el código fuente. ¿Cómo se leen los datos desde la base de datos y en que objetos de datos se rellena? a) Los datos se leen de la base de datos en las sentencias estáticas SELECT. En el proceso, se rellena una de las dos tablas internas definidas estáticamente.
Tarea 2 Reemplace las dos sentencias SELECT con una sentencia SELECT individual después de la sentencia ENDCASE. Especifique el nombre de la tabla como un objeto de datos alfanumérico. También utilice un Field Symbol de tipo genérico como intervalo de destino (cláusula INTO) al cual asigna un objeto de datos adecuado de manera dinámica. 1. Defina un objeto de datos alfanumérico para el nombre de la tabla (el nombre sugerido es gv_tabname). Rellene el objeto de datos con los nombres de tablas correspondientes en los bloques WHEN. a) Consulte el extracto del código fuente de la solución modelo. 2. Cree un Field Symbol (el nombre sugerido es ) cuyo tipo se asigne como objeto de datos gt_conn o gt_cust. a) Consulte el extracto del código fuente de la solución modelo. 3. ¿Por qué el tipo ANY no es adecuado?
© Copyright . Reservados todos los derechos.
471
Capítulo 11: Programación dinámica
a) El Field Symbol debe especificarse después de INTO TABLE en la sentencia SELECT. En este caso, la verificación de sintaxis solo admite valores genéricos con, al menos, el tipo ANY TABLE. 4. Asigne el Field Symbol a las tablas internas correspondientes en los bloques WHEN; aquellas que desea rellenar en la sentencia genérica SELECT. a) Consulte el extracto del código fuente de la solución modelo. 5. Mueva una de las dos sentencias llamadas SELECT del bloque WHEN después de la sentencia ENDCASE y elimine la otra. Convierta el acceso a la base de datos restante en dinámico. Reemplace el nombre de la tabla estática con el objeto de datos gv_tabname y reemplace el intervalo de destino (tabla interna) con el Field Symbol. a) Consulte el extracto del código fuente de la solución modelo.
Tarea 3 Opcional Intercepte los errores de tiempo de ejecución específicos que se producen cuando utiliza sentencias SQL dinámicas. 1. Lea la documentación de palabras clave para averiguar acerca de las excepciones que se producen cuando utiliza las sentencias SQL dinámicas. Implemente el tratamiento de excepciones con TRY... CATCH ... ENDTRY. Implemente un bloque CATCH diferente para cada una de las clases de excepción o utilice un bloque CATCH individual para la clase superior compartida. Si se produce un error, responda con el mensaje de error 061 de la clase de mensaje BC402. a) Consulte el extracto del código fuente de la solución modelo. REPORT
bc402_dys_dyn_sql MESSAGE-ID bc402.
TYPE-POOLS: abap. DATA: gt_cust gt_conn
TYPE ty_customers, TYPE ty_connections.
DATA: gv_methname TYPE string, gt_parmbind TYPE abap_parmbind_tab, gs_parmbind TYPE abap_parmbind. DATA: gv_tabname
TYPE string.
FIELD-SYMBOLS: TYPE ANY TABLE. SELECTION-SCREEN COMMENT 1(80) text-sel. PARAMETERS: pa_xconn TYPE xfeld RADIOBUTTON GROUP tab DEFAULT 'X', pa_xcust TYPE xfeld RADIOBUTTON GROUP tab . PARAMETERS: pa_nol TYPE i DEFAULT '100'.
472
© Copyright . Reservados todos los derechos.
Lección: Uso de los tipos de datos genéricos
START-OF-SELECTION. * specific part *------------------------------------------* CASE 'X'. WHEN pa_xconn. gv_tabname = 'SPFLI'. ASSIGN gt_conn TO . gv_methname = 'WRITE_CONNECTIONS'. gs_parmbind-name = 'IT_CONN'. GET REFERENCE OF gt_conn INTO gs_parmbind-value. INSERT gs_parmbind INTO TABLE gt_parmbind. WHEN pa_xcust. gv_tabname = 'SCUSTOM'. ASSIGN gt_cust TO . gv_methname = 'WRITE_CUSTOMERS'. gs_parmbind-name = 'IT_CUST'. GET REFERENCE OF gt_cust INTO gs_parmbind-value. INSERT gs_parmbind INTO TABLE gt_parmbind. ENDCASE. * dynamic part *---------------------------------------------* TRY.
SELECT * FROM (gv_tabname) INTO TABLE UP TO pa_nol ROWS. CATCH cx_sy_dynamic_osql_error. MESSAGE e061. ENDTRY. TRY.
CALL METHOD cl_bc402_utilities=>(gv_methname) PARAMETER-TABLE gt_parmbind.
CATCH cx_sy_dyn_call_error. MESSAGE e060. ENDTRY.
© Copyright . Reservados todos los derechos.
473
Capítulo 11: Programación dinámica
Acceso dinámico a los objetos de datos
Figura 189: Acceso dinámico a los objetos de datos
En la mayoría de las sentencias ABAP, no reemplace los objetos de datos en las posiciones de operando directamente con objetos de datos alfanuméricos entre paréntesis. En cambio, utilice la sentencia ASSIGN para el objeto de datos al que debe asignar el Field Symbol. Utilice este enfoque para direccionar el objeto de datos dinámicamente por su nombre. Asigne un Field Symbol de tipo general para el objeto de datos que utiliza la sintaxis de la figura y, a continuación, utilice el Field Symbol en la sentencia ABAP. También puede utilizar alternativas más fáciles y menos proclives a los errores para acceder a atributos y componentes de estructuras.
Acceso dinámico a atributos de instancias y atributos de clases
Figura 190: Acceso dinámico a atributos de objetos y atributos de clases
474
© Copyright . Reservados todos los derechos.
Lección: Uso de los tipos de datos genéricos
Además de utilizar el identificador completo para el acceso dinámico a los atributos de clases e instancias, utilice otra variante para especificar únicamente el nombre del atributo con un objeto de datos alfanumérico. Especifique la referencia de objetos y el selector de componentes de manera estática. También puede especificar el nombre de clase para los atributos estáticos de manera dinámica, si fuera necesario. Esta sintaxis es similar a la de las llamadas dinámicas de métodos.
Consejo: Dado que la verificación de sintaxis admite la parte estática de la sentencia, estas variantes son menos proclives a los errores y, por lo tanto, se prefieren.
Acceso dinámico a los componentes de estructuras
Figura 191: Acceso dinámico a los componentes de estructuras
Utilice una variante especial de la sentencia ASSIGN para acceder a los componentes de estructura de manera dinámica. Especifique la estructura de manera estática o a través de un Field Symbol diferente en la sentencia ASSIGN COMPONENT ... OF STRUCTURE .... Direccione los componentes por nombre o por posición (número) dentro de la estructura. Consejo: Dado que la verificación de sintaxis admite la parte estática de la sentencia, estas variantes son menos proclives a los errores y, por lo tanto, se prefieren. Dado que el sistema direcciona los componentes de una estructura por sus posiciones en la secuencia, usted puede procesar cualquier estructura de manera completa, componente por componente.
© Copyright . Reservados todos los derechos.
475
Capítulo 11: Programación dinámica
Procesamiento completo de cualquier estructura plana no anidada
Figura 192: Procesamiento completo de cualquier estructura plana no anidada
Atención: En la figura, se produce un error de tiempo de ejecución ASSIGN_TYPE_CONFLICT que no puede interceptarse si la estructura transferida contiene un componente que no es compatible con el tipo genérico SIMPLE de los Field Symbols. De forma similar, se produce un error de tiempo de ejecución durante la sentencia WRITE si tipifica el Field Symbol con ANY.
476
© Copyright . Reservados todos los derechos.
Capítulo 11 Ejercicio 27 Acceder a componentes de estructuras de manera dinámica
Ejemplo empresarial Debe desarrollar un programa sencillo que visualice los contenidos de cualquier tabla de base de datos. Por ello, desea averiguar las opciones disponibles en la programación dinámica. Para implementar un método genérico que le permite mostrar los contenidos de cualquier tabla en una lista (si el tipo de línea de la tabla interna cuenta con una estructura plana), reemplace la llamada dinámica de los dos métodos específicos con una llamada estática de un método genérico. Utilice parámetros de interfaz de tipo general, símbolos de tipo general y acceda a los componentes de estructura de manera dinámica. Tarea 1 Copie la clase global CL_BC402_DYT_GEN_TYPES y denomínela ZCL_BC402_##_GEN_TYPES, donde ## es su número de grupo. Familiarícese con la firma de clase. 1. Copie la clase global. 2. Analice la firma de clase. ¿Qué métodos se definen? ¿Cuál es su objetivo? 3. ¿Qué parámetros tienen estos métodos? ¿Cómo se tipifican los parámetros?
Tarea 2 Implemente el método write_any_struct y muestre todos los componentes de estructura gs_struct individualmente con una sentencia WRITE programando un loop por el cual accede a todos los componentes en la estructura gs_struct de manera consecutiva. 1. Cree un Field Symbol (nombre sugerido: ) que tenga un tipo genérico que permita la asignación de cualquier componente plano de la estructura. 2. Programe un loop DO. Utilice el contador de loops sy-index para acceder a todos los componentes de gs_struct de manera consecutiva con el Field Symbol. 3. Verifique si la asignación de Field Symbol fue exitosa. Si lo fue, muestre el componente con una sentencia WRITE. De lo contrario, salga del loop.
Tarea 3 Implemente el método write_any_table. Visualice los contenidos de la tabla interna it_table en una lista por líneas programando un loop sobre la tabla interna gt_table. Llame al método implementado anteriormente, write_any_struct, para cada línea.
© Copyright . Reservados todos los derechos.
477
Capítulo 11: Programación dinámica
1. Cree un Field Symbol (nombre sugerido: ) que tenga un tipo genérico que permita la asignación de una línea de la tabla interna genérica it_table. 2. Programe un LOOP en la tabla interna it_table. Asigne las líneas en la tabla interna al Field Symbol de manera consecutiva. 3. Llame al método write_any_struct para cada línea.
Tarea 4 Copie el programa BC402_DYS_DYN_SQL o su propio programa ZBC402_##_DYN_SQL y denomínelo ZBC402_##_GEN_TYPES, donde ## representa su número de grupo. Familiarícese con el programa y su funcionamiento. 1. Copie el programa y todos sus subcomponentes. 2. Active y realice un test del programa. Analice el código fuente.
Tarea 5 Reemplace la llamada de método dinámica al final del programa con una llamada de su nuevo método, write_any_table. Elimine todas las partes del código fuente que ya no necesita, o márquelas como comentarios. 1. Elimine la llamada de método dinámica o márquela como comentario. En su lugar, implemente una llamada de método write_any_table. Proporcione al método el Field Symbol genérico que señale la tabla interna con los datos. 2. Elimine las definiciones de los objetos de datos que se necesitan para la llamada de método dinámica o márquelos como comentarios. 3. Active y realice un test del programa.
478
© Copyright . Reservados todos los derechos.
Capítulo 11 Solución 27 Acceder a componentes de estructuras de manera dinámica
Ejemplo empresarial Debe desarrollar un programa sencillo que visualice los contenidos de cualquier tabla de base de datos. Por ello, desea averiguar las opciones disponibles en la programación dinámica. Para implementar un método genérico que le permite mostrar los contenidos de cualquier tabla en una lista (si el tipo de línea de la tabla interna cuenta con una estructura plana), reemplace la llamada dinámica de los dos métodos específicos con una llamada estática de un método genérico. Utilice parámetros de interfaz de tipo general, símbolos de tipo general y acceda a los componentes de estructura de manera dinámica. Tarea 1 Copie la clase global CL_BC402_DYT_GEN_TYPES y denomínela ZCL_BC402_##_GEN_TYPES, donde ## es su número de grupo. Familiarícese con la firma de clase. 1. Copie la clase global. a) Lleve a cabo este paso de la manera habitual. 2. Analice la firma de clase. ¿Qué métodos se definen? ¿Cuál es su objetivo? a) write_any_struct y write_any_table para la salida de listas de cualquier estructura plana o cualquier tabla interna con el tipo de línea plana. 3. ¿Qué parámetros tienen estos métodos? ¿Cómo se tipifican los parámetros? a) Los dos parámetros son gs_struct TYPE ANY y gt_struct TYPE ANY TABLE.
Tarea 2 Implemente el método write_any_struct y muestre todos los componentes de estructura gs_struct individualmente con una sentencia WRITE programando un loop por el cual accede a todos los componentes en la estructura gs_struct de manera consecutiva. 1. Cree un Field Symbol (nombre sugerido: ) que tenga un tipo genérico que permita la asignación de cualquier componente plano de la estructura. a) Consulte el extracto del código fuente de la solución modelo. 2. Programe un loop DO. Utilice el contador de loops sy-index para acceder a todos los componentes de gs_struct de manera consecutiva con el Field Symbol. a) Consulte el extracto del código fuente de la solución modelo.
© Copyright . Reservados todos los derechos.
479
Capítulo 11: Programación dinámica
3. Verifique si la asignación de Field Symbol fue exitosa. Si lo fue, muestre el componente con una sentencia WRITE. De lo contrario, salga del loop. a) Consulte el extracto del código fuente de la solución modelo.
Tarea 3 Implemente el método write_any_table. Visualice los contenidos de la tabla interna it_table en una lista por líneas programando un loop sobre la tabla interna gt_table. Llame al método implementado anteriormente, write_any_struct, para cada línea. 1. Cree un Field Symbol (nombre sugerido: ) que tenga un tipo genérico que permita la asignación de una línea de la tabla interna genérica it_table. a) Consulte el extracto del código fuente de la solución modelo. 2. Programe un LOOP en la tabla interna it_table. Asigne las líneas en la tabla interna al Field Symbol de manera consecutiva. a) Consulte el extracto del código fuente de la solución modelo. 3. Llame al método write_any_struct para cada línea. a) Consulte el extracto del código fuente de la solución modelo.
Tarea 4 Copie el programa BC402_DYS_DYN_SQL o su propio programa ZBC402_##_DYN_SQL y denomínelo ZBC402_##_GEN_TYPES, donde ## representa su número de grupo. Familiarícese con el programa y su funcionamiento. 1. Copie el programa y todos sus subcomponentes. a) Realice este paso como siempre. 2. Active y realice un test del programa. Analice el código fuente. a) Realice este paso como siempre.
Tarea 5 Reemplace la llamada de método dinámica al final del programa con una llamada de su nuevo método, write_any_table. Elimine todas las partes del código fuente que ya no necesita, o márquelas como comentarios. 1. Elimine la llamada de método dinámica o márquela como comentario. En su lugar, implemente una llamada de método write_any_table. Proporcione al método el Field Symbol genérico que señale la tabla interna con los datos. a) Consulte el extracto del código fuente de la solución modelo. 2. Elimine las definiciones de los objetos de datos que se necesitan para la llamada de método dinámica o márquelos como comentarios. a) Consulte el extracto del código fuente de la solución modelo. 3. Active y realice un test del programa. a) Realice este paso como siempre.
480
© Copyright . Reservados todos los derechos.
Lección: Uso de los tipos de datos genéricos
Método write_any_struct (Clase CL_BC402_DYS_GEN_TYPE) method WRITE_ANY_STRUCT. FIELD-SYMBOLS TYPE simple. NEW-LINE. DO. ASSIGN COMPONENT sy-index OF STRUCTURE is_struct TO . IF sy-subrc = 0. WRITE . ELSE. EXIT. ENDIF. ENDDO. endmethod. Método write_any_table (Clase CL_BC402_DYS_GEN_TYPE) method WRITE_ANY_TABLE. FIELD-SYMBOLS: TYPE ANY. LOOP AT it_table ASSIGNING . write_any_struct( ). ENDLOOP. endmethod. Programa ejecutable BC402_DYS_GEN_TYPES REPORT
bc402_dys_gen_types MESSAGE-ID bc402.
*TYPE-POOLS: abap. DATA: gt_cust gt_conn
TYPE ty_customers, TYPE ty_connections.
*DATA: * gv_methname TYPE string, * gt_parmbind TYPE abap_parmbind_tab, * gs_parmbind TYPE abap_parmbind. DATA: gv_tabname
TYPE string.
FIELD-SYMBOLS: TYPE ANY TABLE. SELECTION-SCREEN COMMENT 1(80) text-sel. PARAMETERS: pa_xconn TYPE xfeld RADIOBUTTON GROUP tab DEFAULT 'X', pa_xcust TYPE xfeld RADIOBUTTON GROUP tab . PARAMETERS: pa_nol TYPE i DEFAULT '100'.
© Copyright . Reservados todos los derechos.
481
Capítulo 11: Programación dinámica
START-OF-SELECTION. * specific part *----------------------------------------------------* CASE 'X'. WHEN pa_xconn. gv_tabname = 'SPFLI'. ASSIGN gt_conn TO . WHEN pa_xcust. gv_tabname = 'SCUSTOM'. ASSIGN gt_cust TO . ENDCASE. * dynamic part *------------------------------------------------------* TRY.
SELECT * FROM (gv_tabname) INTO TABLE UP TO pa_nol ROWS. CATCH cx_sy_dynamic_osql_error. MESSAGE e061. ENDTRY. * * * * * * * *
TRY.
CALL METHOD cl_bc402_utilities=>(gv_methname) PARAMETER-TABLE gt_parmbind.
CATCH cx_sy_dyn_call_error. MESSAGE e060. ENDTRY. cl_bc402_dys_gen_types=>write_any_table( fs_table ).
482
© Copyright . Reservados todos los derechos.
Lección: Uso de los tipos de datos genéricos
Referencias de datos de tipo genérico Puede tipificar variables de referencia de manera genérica. Sin embargo, a diferencia de los Field Symbols, solo los tipos genéricos DATA (para referencias de datos) y OBJECT (para referencias de objetos) están disponibles para las variables de referencia. El uso de variables de referencia de tipo genérico es limitado en ABAP. Salvo por la sentencia ASSIGN, las variables de referencia de tipo genérico no puede anularse directamente en posiciones de operando. La sentencia WRITE ref->* posee una sintaxis incorrecta, por ejemplo, si la referencia de datos cuenta con el tipo TYPE REF TO DATA. Debido a estas restricciones, puede utilizar referencias de datos genéricas solo donde los Field Symbols genéricos no funcionan.
Utilizar casos para referencias de datos de tipo genérico Los casos de uso común para referencias con el tipo TYPE REF TO DATA son los que siguen: ●
En tablas internas
●
Durante la generación dinámica de objetos de datos utilizando la sentencia CREATE DATA.
Asignación de casting para referencias de datos
Figura 193: Asignación de casting para referencias de datos
Para direccionar el contenido de objetos de datos referenciados, utilice una referencia de datos de tipo completo. Los contenidos de la referencia de datos genéricas se copian a la referencia de datos de tipo completo. Puede anular la referencia de datos completos en cualquier elemento de operando. Sin embargo, para que esta técnica funcione, la segunda variable de referencia debe tener el mismo tipo que el objeto de dato referenciado.
© Copyright . Reservados todos los derechos.
483
Capítulo 11: Programación dinámica
Cuando asigna valores entre las dos variables de referencia con tipos diferentes, usted realiza una asignación de casting. Es similar a la asignación de casting entre referencias de objeto, sobre las que aprendió durante la programación orientada a objetos. De la misma manera que con las referencias de objeto, hay un up cast cuando la variable de destino posee una definición más general y un down cast cuando la variable de destino cuenta con un tipo más específico que el de la variable fuente. Por consiguiente, la asignación de una referencia de datos genérica a una referencia completa es un down cast. Mientras que los up cast al tipo TYPE REF TO DATA siempre funcionan, el down cast debe contar con el operador de casting ?= para tener una sintaxis adecuada. El sistema verifica la compatibilidad en el tiempo de ejecución en este caso.
Atención: Si el tipo de la nueva variable de referencia no coincide con el tipo exacto de objeto de dato referenciado, se produce un error de tiempo de ejecución. La clase CX_SY_MOVE_CAST_ERROR es una excepción.
Referencias de datos de tipo genérico anuladas
Figura 194: Anulación de referencias de datos de tipo genérico
La única sentencia ABAP en la cual puede anular una variable de referencia genérica es la sentencia ASSIGN. La sentencia ASSIGN asigna un Field Symbol (genérico) al objeto de datos al cual señala la variable de referencia genérica. Luego, puede direccionar y continuar procesando los contenidos del objeto referenciado utilizando este Field Symbol.
484
© Copyright . Reservados todos los derechos.
Lección: Uso de los tipos de datos genéricos
RESUMEN DE LA LECCIÓN Ahora podrá: ●
Explicar los tipos de datos genéricos de ABAP
●
Utilizar tipos de datos genéricos
●
Acceder a objetos de datos de manera dinámica
●
Utilizar referencias de datos de tipo genérico
© Copyright . Reservados todos los derechos.
485
Capítulo 11 Lección 2 Descripción de tipos de datos, objetos de datos y objetos en tiempo de ejecución
RESUMEN DE LA LECCIÓN En este módulo, se analiza la identificación de tipos en tiempo de ejecución, una técnica que le permite consultar información sobre tipos de datos y tipos de objetos en tiempo de ejecución. Esta técnica es esencial para utilizar los parámetros de tipo genérico, Field Symbols y referencias en programas dinámicos. Ejemplo empresarial Necesita desarrollar una aplicación flexible utilizando parámetros de tipo genéricos, Field Symbols y referencias. Por lo tanto, desea conocer las opciones proporcionadas por la RTTI para consultar información sobre el tipo real de objetos subyacentes en tiempo de ejecución. Por este motivo, se requieren los siguientes conocimientos: ●
●
Un resumen de cómo consultar las propiedades de los objetos de datos y los tipos de datos en tiempo de ejecución Un resumen de cómo consultar las propiedades de clases e instancias en tiempo de ejecución
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá:
486
●
Explicar el principio de RTTI
●
Describir tipos de datos y objetos de datos en tiempo de ejecución
●
Describir tipos de objetos y objetos en tiempo de ejecución
© Copyright . Reservados todos los derechos.
Lección: Descripción de tipos de datos, objetos de datos y objetos en tiempo de ejecución
Jerarquía de clase RTTI
Figura 195: Jerarquía de clase de las clases de descripción RTTI
A partir de SAP Web AS 6.10, los desarrolladores de ABAP utilizan un concepto basado en clases, RTTI, para determinar propiedades de tipo, como tipos de datos y tipos de objetos, en tiempo de ejecución. Consejo: Antes de RTTI, ABAP contenía solo las sentencias DESCRIBE FIELD y DESCRIBE TABLE. Sin embargo, estas sentencias se limitan a propiedades de objetos de datos y no determinan tantas propiedades como RTTI. RTTI consiste en una jerarquía de diez clases globales que utilizan los desarrolladores. La descripción de un tipo en tiempo de ejecución es una instancia de una de estas clases globales. La instancia Atributos graba las propiedades del tipo. Usted las consulta directamente o mediante métodos apropiados. En tiempo de ejecución, existe sólo un objeto de descripción para cada tipo. Todas las clases heredan propiedades de una clase superior compartida, de manera directa o indirecta, y todos sus nombres siguen el modelo CL_ABAP_xxxDESCR, donde xxx representa la categoría del tipo utilizado para describir la clase correspondiente. Necesita diferentes clases porque los atributos y los métodos de cada clase se especializan para describir una categoría específica de tipos. Por ejemplo, utilice la clase CL_ABAP_TABLEDESCR para describir tipos de tabla. Por lo tanto, la clase contiene atributos para la categoría de la tabla y la estructura de la clave de tabla, entre otros datos. Estos atributos son específicos de la clase CL_ABAP_TABLEDESCR. Ninguna otra clase RTTI los contiene. Clases de RTTI – Utilización Puede instanciar solo seis de las diez clases RTTI y utilizarlas para describir tipos específicos.
© Copyright . Reservados todos los derechos.
487
Capítulo 11: Programación dinámica
La siguiente tabla lista las clases RTTI que puede instanciar con su utilización: Clase RTTI
Utilización
CL_ABAP_ELEMDESCR
Para describir tipos de datos elementales
CL_ABAP_REFDESCR
Para describir tipos de referencias (=tipos de variables de referencias)
CL_ABAP_STRUCTDESCR
Para describir tipos de estructuras
CL_ABAP_TABLEDESCR
Para describir tipos de tablas
CL_ABAP_CLASSDESCR
Para describir clases (=tipos de objetos)
CL_ABAP_INTFESCR
Para describir interfaces
Todas las demás clases son abstractas, lo cual significa que no puede instanciarlas. Utilice esas clases para definir los atributos y los métodos que se utilizan en varias de las demás clases e implementarlos si es necesario. Por ejemplo, el atributo METHODS, que contiene una lista de métodos, no se define en la clase CL_ABAP_CLASSDESCR, sino en la clase CL_ABAP_OBJECTDESCR, ya que también se necesita en el mismo formulario de la clase CL_ABAP_INTFDESCR.
Figura 196: Clases RTTI que puede instanciar
488
© Copyright . Reservados todos los derechos.
Lección: Descripción de tipos de datos, objetos de datos y objetos en tiempo de ejecución
Instanciación de clase RTTI
Figura 197: RTTI: métodos y atributos de la clase raíz
No instancie las clases de descripción RTTI directamente con la sentencia CREATE OBJECT. Para recuperar una referencia a un objeto de descripción, llame el método estático DESCRIBE_BY_xxx de la clase CL_ABAP_TYPEDESCR. Los objetos de descripción se generan y los datos se completan y se devuelven utilizando un parámetro de retorno con el tipo genérico REF TO CL_ABAP_TYPEDESCR. Describir un tipo según su nombre
Figura 198: Descripción de un tipo según su nombre
© Copyright . Reservados todos los derechos.
489
Capítulo 11: Programación dinámica
Después de la llamada, debe asignar una subclase adecuada para acceder a los atributos y a los métodos específicos para el tipo correspondiente. Si no sabe qué clase RTTI se instanció, evalúe el atributo de instancia KIND público, cuyo contenido coincide con el valor de una de las seis constantes de la clase CL_ABAP_TYPEDESCR. Cada una de estas seis constantes corresponde a una de seis clases RTTI que el desarrollador puede instanciar. Referencia adecuada para un objeto de descripción de tipos
Figura 199: Casting de una referencia adecuada para un objeto de descripción de tipos
Consejo: Si sabe qué clase de descripción está instanciada, el down cast también puede llevarse a cabo directamente en la llamada del método funcional, por ejemplo, lo_class?= cl_abap_typedescr=>describe_by_... En este caso, puede interceptar el error de tiempo de ejecución CX_SY_MOVE_CAST_ERROR. Métodos para objetos de descripción Los siguientes métodos difieren con respecto a la información que se les proporciona en sus llamadas: ● DESCRIBE_BY_NAME Este método devuelve el objeto de descripción con el nombre de tipo que usted especifica y analiza tanto los tipos de datos como los tipos de objetos (clases e interfaces) que se definen de forma global en el Diccionario ABAP o Generador de clases, o de forma local en el programa. Debe introducir el nombre de tipo en mayúscula. Si el método no encuentra el tipo con el nombre especificado, emite una excepción convencional TYPE_NOT_FOUND. ●
490
DESCRIBE_BY_DATA
© Copyright . Reservados todos los derechos.
Lección: Descripción de tipos de datos, objetos de datos y objetos en tiempo de ejecución
Este método devuelve el objeto de descripción para el tipo de objeto de datos. Solo devuelve descripciones de tipos de datos y no considera si el objeto de datos se definió con un tipo explícito o un tipo vinculado. Si el objeto de datos especificado es un parámetro o un Field Symbol con un tipo genérico, el método no devuelve la descripción del tipo genérico. En cambio, devuelve el tipo del parámetro real o el objeto de datos actualmente asignado. ●
DESCRIBE_BY_DATA_REF Este método devuelve el objeto de descripción para el tipo de objeto de datos que señala a una referencia de datos. Solo devuelve descripciones de tipos de datos. Si la referencia de datos es de tipo genérico (TYPE REF TO DATA), puede utilizar este método para determinar el tipo dinámico del objeto referenciado.
Atención: Si la referencia no posee un valor válido en el tiempo de llamada, el método emite la excepción convencional REFERENCE_IS_INITIAL. ●
DESCRIBE_BY_OBJECT_REF Este método devuelve el objeto de descripción para el tipo de instancia que señala a una referencia de objetos. Solo devuelve descripciones de clases. Utilice este método para determinar el tipo dinámico de la instancia referenciada después de un up cast a una clase superior o a una interfaz implementada.
Atención: Si la referencia no posee un valor válido en el tiempo de llamada, el método emite la excepción convencional REFERENCE_IS_INITIAL.
© Copyright . Reservados todos los derechos.
491
Capítulo 11: Programación dinámica
Describir tipos según objetos de datos y referencias
Figura 200: Descripción de tipos según objetos de datos y referencias
En la figura se muestran ejemplos para utilizar estos métodos estáticos. Además de los métodos estáticos, utilice los métodos especiales para navegar desde un objeto de descripción hacia otros. Por ejemplo, desea navegar desde la descripción de un tipo de tabla hasta la descripción del tipo de línea correspondiente, o desea navegar desde un tipo de estructura hasta los objetos de descripción para los tipos de componente.
492
© Copyright . Reservados todos los derechos.
Lección: Descripción de tipos de datos, objetos de datos y objetos en tiempo de ejecución
Análisis de tipo de datos elemental
Figura 201: Análisis de un tipo de datos elemental
Los ejemplos de la aplicación demuestran cómo utilizar el RTTI para determinar las propiedades de diferentes tipos de datos. Si el sistema utiliza una subclase determinada, depende del tipo de dato. Una instancia de clase CL_ABAP_ELEMDESCR describe todas las propiedades de un tipo de datos elemental. Los atributos públicos correspondientes contienen las propiedades técnicas del tipo ABAP subyacente, la longitud y la cantidad de posiciones decimales. Para evaluar el atributo TYPE_KIND, compare sus contenidos con las constantes correspondientes de la clase CL_ABAP_TYPEDESCR, como debe hacer para evaluar el atributo KIND.
Nota: Los tres atributos se describen en la clase de raíz de RTTI, lo cual significa que se heredan por todas las clases de descripción. Sin embargo, en las otras clases, estos atributos son menos significativos. Las propiedades semánticas, en otras palabras, la información adicional del Diccionario ABAP, deben determinarse de manera explícita utilizando los métodos públicos. En la figura se muestra una llamada de método GET_DDIC_FIELD. Usted utiliza un parámetro opcional para determinar la información dependiente del idioma, como etiquetas de campo, en un idioma diferente del idioma actual de inicio de sesión.
© Copyright . Reservados todos los derechos.
493
Capítulo 11: Programación dinámica
Atención: Si el tipo actual no es un tipo del diccionario, el método emite una excepción convencional. Para evitar esto, utilice el método IS_DDIC_TYPE para verificar si la información del diccionario está disponible (consulte el ejemplo en la figura).
Análisis de tipo de referencia
Figura 202: Análisis del tipo de una variable de referencia
Cuando analiza un tipo de referencia (=tipo de variable de referencia), el atributo TYPE_KIND heredado le permite distinguir entre referencias de objeto y referencias de datos. Sin embargo, para determinar los detalles del tipo estático de variable de referencia, utilice el método de navegación GET_REFERENCED_TYPE. Este método devuelve una referencia a otro objeto de descripción. Este objeto de descripción puede ser una instancia de clase CL_ABAP_STRUCTDESCR, si la variable de referencia se creó con un tipo de estructura. Sin embargo, si crea la variable de referencia con referencia a una clase o una interfaz, GET_REFERENCED_TYPE devuelve instancias de las clases CL_ABAP_CLASSDESCR o CL_ABAP_INTFDESCR, respectivamente.
494
© Copyright . Reservados todos los derechos.
Lección: Descripción de tipos de datos, objetos de datos y objetos en tiempo de ejecución
Análisis de tipo de estructura
Figura 203: Navegación del tipo de estructura a los tipos de componentes
Para obtener acceso total a todas las propiedades de tipos de componentes, navegue a los objetos de descripción correspondientes. El método de navegación GET_COMPONENT_TYPE devuelve el objeto de descripción para el tipo de un componente específico, mientras que el método de navegación GET_COMPONENTS devuelve los objetos de descripción para todos los componentes.
Consejo: Dado que los tipos de componentes también pueden ser tipos de referencias, tipos de estructuras o tipos de tablas, defina los valores de retorno con el tipo REF TO CL_ABAP_DATADESCR. Probablemente necesite un down cast para una de las subclases en las variables de referencia, por ejemplo, para el tipo REF TO CL_ABAP_ELEMDESCR.
© Copyright . Reservados todos los derechos.
495
Capítulo 11: Programación dinámica
Análisis de tipo de tabla
Figura 204: Análisis de un tipo de tabla
Los atributos públicos de la clase CL_ABAP_TABLEDESCR incluyen los tipos de tabla, como estándar, clasificada, de claves de control, de índice, cualquiera, la singularidad de la clave y una lista de nombres de los componentes clave. Para determinar los detalles de un tipo de línea, navegue a un objeto de descripción para ese tipo de línea, el método de navegación GET_TABLE_LINE_TYPE. Consejo: El tipo de línea de un tipo de tabla puede tener cualquier tipo de datos. Por consiguiente, el parámetro de retorno se tipifica con REF TO CL_ABAP_DATADESCR y realiza un down cast a un tipo adecuado si es necesario.
496
© Copyright . Reservados todos los derechos.
Capítulo 11 Ejercicio 28 Proporcionar cabeceras de columna con la identificación de tipos en tiempo de ejecución
Ejemplo empresarial Debe desarrollar un programa sencillo que visualice los contenidos de cualquier tabla de base de datos. Para desarrollar el programa, debe averiguar las opciones disponibles en la programación dinámica. Ya desarrolló un método para enviar tablas internas con un tipo de línea plana a una lista. Debe utilizar las opciones de RTTI para desarrollar un método que genere cabeceras de columnas dinámicas para el programa. Utilice el RTTI para analizar un tipo de estructura y para determinar la información semántica para ese tipo de estructura desde el Dictionary ABAP. Utilice la información semántica del tipo de estructura para generar cabeceras de columna de manera dinámica. Tarea 1 Copie el modelo CL_BC402_DYT_RTTI_HEADERS y denomínelo ZCL_BC402_##_RTTI_HEADERS, donde ## representa su número de grupo. Familiarícese con la firma de clase. 1. Copie la clase global. 2. Analice la firma de clase. ¿Qué métodos se definen y para qué sirven? 3. ¿Qué parámetros y excepciones tienen estos métodos? ¿Cómo se tipifican los parámetros? ¿Qué situaciones de error corresponden a las excepciones?
Tarea 2 Implemente el método write_headers. Utilice las opciones RTTI para analizar el tipo de datos cuyo nombre se encuentra en el parámetro para import gv_tabname. 1. Llame un método estático adecuado de clase CL_ABAP_TYPEDESCR para analizar los tipos de datos según su nombre. 2. Cree una variable de referencia local (el nombre sugerido es lo_type) e introdúzcalo para que coincida con el parámetro de retorno del método. Especifique esta variable de referencia como un parámetro real en la llamada de método. 3. Controle cualquier excepción posible y emita la excepción TYPE_NOT_FOUND del método write_headers como reacción. 4. Utilice el atributo público KIND para determinar si la instancia de RTTI generada realmente describe un tipo de estructura. Si el tipo de datos no es un tipo de estructura, salga del método write_headers con la excepción NO_STRUCTURE.
© Copyright . Reservados todos los derechos.
497
Capítulo 11: Programación dinámica
5. Cree una variable de referencia local (el nombre sugerido es lo_struct) y asígnela a un tipo para que señale a instancias de la clase CL_ABAP_STRUCTDESCR. Programe un down cast para señalar esta referencia al objeto de descripción de tipos. Consejo: No intercepte posibles errores en tiempo de ejecución en este caso, porque el query del atributo KIND ya garantiza la compatibilidad.
Tarea 3 Determine una lista con información del diccionario para todos los componentes del tipo de estructura. Muestre la cabecera de informe para todos los componentes en la secuencia. Asegúrese de que la salida no supere la longitud de visualización del campo correspondiente. 1. Cree una tabla interna con el tipo ddfields (nombre sugerido: lt_fields). 2. Llame un método de clase adecuado CL_ABAP_STRUCTDESCR para generar una lista con información del diccionario para los componentes de la estructura. Para hacerlo, cree una tabla interna con el tipo ddfields como el parámetro real para el valor de retorno (el nombre sugerido es lt_fields). Si la llamada de método finaliza con excepciones, salga del método write_headers con una excepción adecuada. 3. Para programar un loop sobre la tabla interna, cree un Field Symbol (el nombre sugerido es ) que se tipifica con el tipo de línea de la tabla interna lt_fields. 4. Muestre la cabecera de informe (campo reptext) en cada ejecución de loop. Utilice la longitud de salida (campo outputlen) para el acceso de longitud para garantizar que las cabeceras tengan la longitud exacta que tendrán luego en la salida.
Tarea 4 Copie el programa BC402_DYS_GEN_TYPES o su propio programa, ZBC402_##_GEN_TYPES y denomínelo ZBC402_##_RTTI_HEADERS, donde ## es su número de grupo. Familiarícese con el programa y su funcionamiento. 1. Copie el programa y todos sus subcomponentes. 2. Active y realice un test del programa. Analice el código fuente.
Tarea 5 Inserte una llamada de método write_headers antes de la salida de datos. Transmita el nombre del tipo de línea de la tabla interna con los datos para su método. 1. Implemente una llamada de método write_headers antes de la llamada de método write_any_table. Transmita el objeto de datos que contenga el nombre de la tabla de base de datos (y, por lo tanto, el nombre del tipo de línea de la tabla interna). 2. Reaccione a las excepciones con mensajes de error adecuados de la clase de mensaje BC402. 3. Active y realice un test del programa.
498
© Copyright . Reservados todos los derechos.
Capítulo 11 Solución 28 Proporcionar cabeceras de columna con la identificación de tipos en tiempo de ejecución
Ejemplo empresarial Debe desarrollar un programa sencillo que visualice los contenidos de cualquier tabla de base de datos. Para desarrollar el programa, debe averiguar las opciones disponibles en la programación dinámica. Ya desarrolló un método para enviar tablas internas con un tipo de línea plana a una lista. Debe utilizar las opciones de RTTI para desarrollar un método que genere cabeceras de columnas dinámicas para el programa. Utilice el RTTI para analizar un tipo de estructura y para determinar la información semántica para ese tipo de estructura desde el Dictionary ABAP. Utilice la información semántica del tipo de estructura para generar cabeceras de columna de manera dinámica. Tarea 1 Copie el modelo CL_BC402_DYT_RTTI_HEADERS y denomínelo ZCL_BC402_##_RTTI_HEADERS, donde ## representa su número de grupo. Familiarícese con la firma de clase. 1. Copie la clase global. a) Realice este paso como siempre. 2. Analice la firma de clase. ¿Qué métodos se definen y para qué sirven? a) write_headers para mostrar una lista de cabeceras de columnas basadas en un tipo de estructura del Diccionario ABAP. 3. ¿Qué parámetros y excepciones tienen estos métodos? ¿Cómo se tipifican los parámetros? ¿Qué situaciones de error corresponden a las excepciones? a) Parámetro iv_tabname con el tipo genérico csequence y excepciones. Estas son las situaciones de error que corresponden a las excepciones: ●
TYPE_NOT_FOUND El tipo transmitido se desconoce.
●
NO_STRUCTURE El objeto no es un tipo de estructura.
●
NO_DDIC_TYPE El objeto no es un tipo en el Diccionario ABAP.
Tarea 2 Implemente el método write_headers. Utilice las opciones RTTI para analizar el tipo de datos cuyo nombre se encuentra en el parámetro para import gv_tabname.
© Copyright . Reservados todos los derechos.
499
Capítulo 11: Programación dinámica
1. Llame un método estático adecuado de clase CL_ABAP_TYPEDESCR para analizar los tipos de datos según su nombre. a) Consulte el extracto del código fuente de la solución modelo. 2. Cree una variable de referencia local (el nombre sugerido es lo_type) e introdúzcalo para que coincida con el parámetro de retorno del método. Especifique esta variable de referencia como un parámetro real en la llamada de método. a) Consulte el extracto del código fuente de la solución modelo. 3. Controle cualquier excepción posible y emita la excepción TYPE_NOT_FOUND del método write_headers como reacción. 4. Utilice el atributo público KIND para determinar si la instancia de RTTI generada realmente describe un tipo de estructura. Si el tipo de datos no es un tipo de estructura, salga del método write_headers con la excepción NO_STRUCTURE. a) Consulte el extracto del código fuente de la solución modelo. 5. Cree una variable de referencia local (el nombre sugerido es lo_struct) y asígnela a un tipo para que señale a instancias de la clase CL_ABAP_STRUCTDESCR. Programe un down cast para señalar esta referencia al objeto de descripción de tipos. Consejo: No intercepte posibles errores en tiempo de ejecución en este caso, porque el query del atributo KIND ya garantiza la compatibilidad. a) Consulte el extracto del código fuente de la solución modelo.
Tarea 3 Determine una lista con información del diccionario para todos los componentes del tipo de estructura. Muestre la cabecera de informe para todos los componentes en la secuencia. Asegúrese de que la salida no supere la longitud de visualización del campo correspondiente. 1. Cree una tabla interna con el tipo ddfields (nombre sugerido: lt_fields). a) Consulte el extracto del código fuente de la solución modelo. 2. Llame un método de clase adecuado CL_ABAP_STRUCTDESCR para generar una lista con información del diccionario para los componentes de la estructura. Para hacerlo, cree una tabla interna con el tipo ddfields como el parámetro real para el valor de retorno (el nombre sugerido es lt_fields). Si la llamada de método finaliza con excepciones, salga del método write_headers con una excepción adecuada. a) Consulte el extracto del código fuente de la solución modelo. 3. Para programar un loop sobre la tabla interna, cree un Field Symbol (el nombre sugerido es ) que se tipifica con el tipo de línea de la tabla interna lt_fields. a) Consulte el extracto del código fuente de la solución modelo. 4. Muestre la cabecera de informe (campo reptext) en cada ejecución de loop. Utilice la longitud de salida (campo outputlen) para el acceso de longitud para garantizar que las cabeceras tengan la longitud exacta que tendrán luego en la salida. a) Consulte el extracto del código fuente de la solución modelo.
500
© Copyright . Reservados todos los derechos.
Lección: Descripción de tipos de datos, objetos de datos y objetos en tiempo de ejecución
Tarea 4 Copie el programa BC402_DYS_GEN_TYPES o su propio programa, ZBC402_##_GEN_TYPES y denomínelo ZBC402_##_RTTI_HEADERS, donde ## es su número de grupo. Familiarícese con el programa y su funcionamiento. 1. Copie el programa y todos sus subcomponentes. a) Lleve a cabo este paso de la manera habitual. 2. Active y realice un test del programa. Analice el código fuente. a) Lleve a cabo este paso de la manera habitual.
Tarea 5 Inserte una llamada de método write_headers antes de la salida de datos. Transmita el nombre del tipo de línea de la tabla interna con los datos para su método. 1. Implemente una llamada de método write_headers antes de la llamada de método write_any_table. Transmita el objeto de datos que contenga el nombre de la tabla de base de datos (y, por lo tanto, el nombre del tipo de línea de la tabla interna). a) Consulte el extracto del código fuente de la solución modelo. 2. Reaccione a las excepciones con mensajes de error adecuados de la clase de mensaje BC402. a) Consulte el extracto del código fuente de la solución modelo. 3. Active y realice un test del programa. a) Realice este paso como siempre. Método write_headers (Class_CL_BC402_DYS_RTTI_HEADERS) METHOD write_headers. DATA: lo_type TYPE REF TO cl_abap_typedescr, lo_struct TYPE REF TO cl_abap_structdescr, lt_flist TYPE ddfields. FIELD-SYMBOLS: LIKE LINE OF lt_flist. CALL METHOD cl_abap_typedescr=>describe_by_name EXPORTING p_name = iv_tabname RECEIVING p_descr_ref = lo_type EXCEPTIONS type_not_found = 1. IF sy-subrc <> 0. RAISE type_not_found. ENDIF. IF lo_type->kind <> cl_abap_typedescr=>kind_struct.
© Copyright . Reservados todos los derechos.
501
Capítulo 11: Programación dinámica
RAISE no_structure. ENDIF. lo_struct ?= lo_type. CALL METHOD lo_struct->get_ddic_field_list RECEIVING p_field_list = lt_flist EXCEPTIONS not_found = 1 no_ddic_type = 2. CASE sy-subrc. WHEN 1. RAISE type_not_found. WHEN 2. RAISE no_ddic_type. ENDCASE. NEW-LINE. LOOP AT lt_flist ASSIGNING . WRITE -reptext(-outputlen) COLOR COL_HEADING. ENDLOOP. ULINE. ENDMETHOD. Programa ejecutable BC402_DYS_RTTI_HEADERS REPORT
bc402_dys_rtti_headers MESSAGE-ID bc402.
TYPE-POOLS: abap. DATA: gt_cust gt_conn DATA: gv_tabname
TYPE ty_customers, TYPE ty_connections. TYPE string.
FIELD-SYMBOLS: TYPE ANY TABLE. SELECTION-SCREEN COMMENT 1(80) text-sel. PARAMETERS: pa_xconn TYPE xfeld RADIOBUTTON GROUP tab DEFAULT 'X', pa_xcust TYPE xfeld RADIOBUTTON GROUP tab . PARAMETERS: pa_nol TYPE i DEFAULT '100'. START-OF-SELECTION. * specific part *----------------------------------------------------* CASE 'X'. WHEN pa_xconn.
502
© Copyright . Reservados todos los derechos.
Lección: Descripción de tipos de datos, objetos de datos y objetos en tiempo de ejecución
gv_tabname = 'SPFLI'. ASSIGN gt_conn TO . WHEN pa_xcust. gv_tabname = 'SCUSTOM'. ASSIGN gt_cust TO . ENDCASE. * dynamic part *------------------------------------------------------* TRY.
SELECT * FROM (gv_tabname) INTO TABLE UP TO pa_nol ROWS. CATCH cx_sy_dynamic_osql_error. MESSAGE e061. ENDTRY. CALL METHOD cl_bc402_dys_rtti_headers=>write_headers EXPORTING iv_tabname = gv_tabname EXCEPTIONS type_not_found = 1 no_structure = 2 no_ddic_type = 3. CASE sy-subrc. WHEN 1. MESSAGE e050 WITH gv_tabname. WHEN 2. MESSAGE e051 WITH gv_tabname. WHEN 3. MESSAGE e052 WITH gv_tabname. ENDCASE. cl_bc402_dys_gen_types=>write_any_table( ).
© Copyright . Reservados todos los derechos.
503
Capítulo 11: Programación dinámica
Análisis de tipo de objeto
Figura 205: Análisis de un tipo de objeto
RTTI le permite analizar los atributos de los objetos. Realice el análisis mediante las clases CL_ABAP_CLASSDESCR y CL_ABAP_INTFDESCR. La mayoría de los atributos y los métodos para estas dos clases se definen en la clase superior compartida (abstracta) CL_ABAP_OBJECTDESCR, porque se necesitan para analizar clases e interfaces.
Nota: En el ejemplo que se muestra en la figura, se analiza una clase. La mayor parte de la información también se aplica al análisis de interfaces. La clase CL_ABAP_CLASSDESCR contiene atributos públicos que listan los atributos, los métodos, los eventos, las interfaces y otros objetos de la clase que se describe. Las tablas internas en el sistema contienen estos atributos públicos. Algunos de estos atributos, como los METHODS, se definen como tablas internas anidadas, en las cuales, cada línea contiene una o más tablas internas. Por ejemplo, estas tablas internas anidadas contienen listas con parámetros y excepciones para el método correspondiente. Además de estos atributos heredados, la clase CL_ABAP_CLASSDESCR también proporciona atributos específicos, como el atributo CLASS_KIND, que utiliza para determinar si la clase se marcó como abstracta, final, y así sucesivamente.
504
© Copyright . Reservados todos los derechos.
Lección: Descripción de tipos de datos, objetos de datos y objetos en tiempo de ejecución
Nota: La clase CL_ABAP_INTFDESCR, en cambio, contiene un atributo INTF_KIND que le permite determinar si una interfaz está compuesta por múltiples interfaces. En la figura se muestra cómo se utiliza RTTI para determinar todos los parámetros del constructor para la clase CL_RENTAL. Después de que el sistema genera el objeto de descripción y ejecuta el down cast, lee la descripción del método constructor desde la lista de métodos (sentencia con READ TABLE). El sistema evalúa a continuación la lista de parámetros para este método constructor en un loop (LOOP en la tabla interna interior). Las clases de descripción para los tipos de objetos también proporcionan métodos de navegación para determinar los detalles de un tipo utilizado. Por ejemplo, el método GET_ATTRIBUTE_TYPE devuelve el objeto de descripción para el tipo de un atributo específico, mientras que GET_METHOD_PARAMETER_TYPE analiza el tipo de un parámetro de método específico, y así sucesivamente. El método GET_SUPER_CLASS_TYPE es específico de las clases. Devuelve el objeto de descripción para la clase superior directa, si existe.
© Copyright . Reservados todos los derechos.
505
Capítulo 11: Programación dinámica
RESUMEN DE LA LECCIÓN Ahora podrá:
506
●
Explicar el principio de RTTI
●
Describir tipos de datos y objetos de datos en tiempo de ejecución
●
Describir tipos de objetos y objetos en tiempo de ejecución
© Copyright . Reservados todos los derechos.
Capítulo 11 Lección 3 Creación de tipos de datos, objetos de datos y objetos en tiempo de ejecución
RESUMEN DE LA LECCIÓN En este módulo, se analiza el método para generar objetos, es decir, instancias de clases, en tiempo de ejecución a partir de la programación orientada a objetos. Analiza un método similar para generar objetos de datos como instancias de tipos de datos en tiempo de ejecución. Este módulo también analiza la creación de tipos en tiempo de ejecución (RTTC), una técnica que le permite definir los tipos de datos en tiempo de ejecución. Ejemplo empresarial Necesita desarrollar una aplicación flexible. Además de acceder a objetos de datos existentes de manera dinámica y de analizar los tipos de datos subyacentes, también desea aprender sobre las técnicas disponibles para generar objetos, objetos de datos y tipos de datos en tiempo de ejecución conforme a los requisitos del programa. Por este motivo, se requieren los siguientes conocimientos: ●
Un resumen de cómo generar objetos o instancias en tiempo de ejecución
●
Un resumen de cómo generar objetos de datos en tiempo de ejecución
●
Un resumen de cómo generar tipos de datos en tiempo de ejecución
OBJETIVOS DE LA LECCIÓN Después de completar esta lección, podrá: ●
Crear objetos (instancias) en tiempo de ejecución
●
Crear objetos de datos en tiempo de ejecución
●
Crear tipos de datos en tiempo de ejecución
© Copyright . Reservados todos los derechos.
507
Capítulo 11: Programación dinámica
Creación dinámica de objetos
Figura 206: Opciones para generar objetos en tiempo de ejecución
La sentencia CREATE OBJECT genera objetos o, más específicamente, instancias de clases en tiempo de ejecución. Defina el tipo de objeto; es decir, la clase que se instanciará de manera implícita a través del tipo estático de la variable de referencia utilizada. Como alternativa, utilice el suplemento TYPE para especificar la clase que se instanciará en la sentencia CREATE OBJECT. Las siguientes reglas se aplican al utilizar la adición TYPE de la sentencia CREATE OBJECT: ● Una clase, no una interfaz, debe aparecer después del suplemento TYPE. ●
●
Debe tener la posibilidad de instanciar la clase, lo cual significa que no puede marcarse como abstracta. El tipo estático de la variable de referencia debe ser compatible con la clase.
La última regla se aplica porque el sistema lleva a cabo un up cast implícito si es necesario cuando especifica el tipo de manera explícita. La variable de referencia es compatible con el objeto creado si cumple una de las siguientes condiciones: ● La variable de referencia se tipifica con la clase que se instanciará. ●
●
●
La variable de referencia se tipifica con una clase superior de la clase que se instanciará. La variable de referencia se tipifica con una interfaz que se implementa por la clase que se instanciará. La variable de referencia se tipifica con el tipo genérico REF TO OBJECT.
La sintaxis para especificar un tipo explícito puede incluir un objeto de datos entre paréntesis después de TYPE. Esta sintaxis admite la selección dinámica de la clase que se instanciará.
508
© Copyright . Reservados todos los derechos.
Lección: Creación de tipos de datos, objetos de datos y objetos en tiempo de ejecución
Consejo: Si hay clases disponibles para la selección que no se encuentran vinculadas por una clase superior compartida o la misma interfaz de implementación, tipifique la variable de referencia completamente de manera genérica con TYPE REF TO OBJECT.
Transferencia dinámica de parámetros
Figura 207: Transferencia dinámica de parámetros
Si todas las clases potenciales tienen la misma firma de constructor, proporcione datos de manera estática a los parámetros. Sin embargo, es probable que los parámetros y las excepciones de los constructores sean diferentes. En este caso, debe utilizar una transferencia de parámetros dinámica. Al igual que con las llamadas de método dinámicas, realice una transferencia de parámetros dinámica utilizando tablas internas después de los suplementos PARAMETER-TABLE y EXCEPTION-TABLE. Introduzca estas tablas y rellénelas como lo hace para las llamadas de métodos.
© Copyright . Reservados todos los derechos.
509
Capítulo 11: Programación dinámica
Creación dinámica de objeto de datos
Figura 208: Opciones para crear objetos de datos en tiempo de ejecución
También puede crear objetos de datos en tiempo de ejecución. La sentencia correspondiente, CREATE DATA, posee una definición similar a la de la sentencia CREATE OBJECT. La sentencia CREATE DATA crea un objeto de datos de manera dinámica, le asigna memoria y señala la variable de referencia de datos generales a ese objeto de datos en la memoria. No se le proporciona un nombre al objeto de datos; por ello, normalmente se denomina objeto de datos anónimo. Para direccionar el objeto de datos, anule las referencias de la variable de referencia en tiempo de ejecución.
Consejo: A diferencia de la sentencia estática DATA, el sistema no reserva la memoria para los objetos de datos hasta el tiempo de ejecución y no reserva la memoria cuando se carga el programa correspondiente. Al igual que con las instancias de clase, el recolector de basura libera la memoria nuevamente en cuanto el programa elimina la última referencia al objeto de datos. Utilice CREATE DATA para definir el tipo de objeto de datos de manera implícita utilizando el tipo de variable de referencia o de manera explícita utilizando el suplemento TYPE. Para utilizar un número de variantes con el que esté familiarizado, utilice el tipo explícito. Estas variantes pueden ser de sentencias DATA, como el uso de tipos integrados, la construcción implícita de tipos de tabla y la referencia a un objeto de datos existente con LIKE. Para definir el tipo de datos para los objetos de datos generados de manera dinámica, utilice los objetos de datos alfanuméricos entre paréntesis.
510
© Copyright . Reservados todos los derechos.
Lección: Creación de tipos de datos, objetos de datos y objetos en tiempo de ejecución
Nota: De manera alternativa, utilice el suplemento TYPE HANDLE para hacer referencia a un objeto de descripción de tipo a partir de RTTI.
Acceder a objetos de datos creados de manera dinámica
Figura 209: Acceder a objetos de datos creados de manera dinámica
Si el sistema determina el tipo de datos de manera dinámica, tipifique la variable de referencia de manera genérica con TYPE REF TO DATA. Este es el único tipo genérico que admite referencias de datos en este momento. Asigne un Field Symbol a las referencias a objetos de datos por los siguientes motivos: ●
Solo puede anular la referencia a los datos genéricos en la sentencia ASSIGN.
●
Puede utilizar Field Symbols tipificados de manera dinámica en cualquier lugar.
Consejo: Si el objeto de datos nuevo es una tabla interna y desea utilizarlo en las posiciones de operando correspondientes, el Field Symbol debe tener, al menos, el tipo ANY TABLE. Tabla interna generada de manera dinámica y SELECT dinámica
Figura 210: Ejemplo – Tabla interna generada de manera dinámica y SELECT dinámica
© Copyright . Reservados todos los derechos.
511
Capítulo 11: Programación dinámica
En la figura se muestra un ejemplo de acceso dinámico a la base de datos en el cual se genera un objeto de datos adecuado en tiempo de ejecución.
512
© Copyright . Reservados todos los derechos.
Capítulo 11 Ejercicio 29 Crear objetos de datos en tiempo de ejecución
Ejemplo empresarial Debe desarrollar un programa sencillo que visualice los contenidos de cualquier tabla de base de datos mediante las opciones disponibles en la programación dinámica. Genere y utilice objetos de datos en tiempo de ejecución, y utilice variables de referencia tipificados de manera genérica. Tarea 1 Copie el programa BC402_DYS_RTTI_HEADERS o su propio programa, ZBC402_##_RTTI_HEADERS y denomínelo ZBC402_##_CREATE_DATA, donde ## es su número de grupo. Familiarícese con el programa y su funcionamiento.
Consejo: Si no ha realizado el ejercicio en RTTI, simplemente copie el programa ZBC402_##_GEN_DATA. La visualización de las cabeceras de columna no es pertinente a este ejercicio. 1. Copie el programa y todos sus subcomponentes. 2. Active y realice un test del programa. Analice el código fuente. ¿Qué objetos de datos se completan durante el acceso a la base de datos? ¿Qué tipos poseen? ¿Se crearon de manera estática o dinámica?
Tarea 2 Reemplace las dos tablas internas definidas de manera estática con un objeto de datos que genere después de la estructura CASE (tabla estándar con clave estándar no única). Defina el tipo de objeto de datos de manera dinámica para garantizar que el tipo de línea coincida precisamente con la estructura de la tabla de la base de datos que desea leer. 1. Defina una referencia de datos de tipo genérico (el nombre sugerido es gr_data). 2. Utilice la referencia de datos gr_data para generar una tabla interna inmediatamente después de la sentencia ENDCASE. Acceda a los contenidos del objeto de datos gv_tabname para definir el tipo de línea de la tabla de manera dinámica. 3. Mueva una de las sentencias ASSIGN fuera de los bloques WHEN después de que se genere el objeto de datos y elimine la otra sentencia ASSIGN. Reemplace la tabla interna definida de manera estática con la tabla generada de manera dinámica.
© Copyright . Reservados todos los derechos.
513
Capítulo 11: Programación dinámica
Consejo: Anule la referencia de datos genérica.
4. ¿Por qué no puede continuar utilizando gr_data de manera directa? 5. Elimine las definiciones de las dos tablas internas estáticas o márquelas como comentarios. 6. Active y realice un test del programa.
Tarea 3 La parte estática del programa ahora solo contiene el llenado de objeto de datos gv_tabname con un literal adecuado para el nombre de la tabla de base de datos. Reemplace ambas casillas de verificación en la pantalla de selección con un parámetro para el nombre de cualquier tabla de base de datos. 1. Elimine los parámetros de las definiciones de ambas casillas de verificación o márquelas como comentarios. Copie la entrada de usuario del parámetro directamente al objeto de datos gv_tabname en lugar de evaluar las casillas de verificación en una estructura CASE. 2. Cree un nuevo parámetro (el nombre sugerido es pa_tab). Consejo: Si utiliza el tipo global dd02l-tabname, proporcione una función de ayuda para valores (F4) para los usuarios. 3. Elimine la estructura CASE o márquela como comentario. En la misma posición, programe una asignación de valor de pa_tab a gv_tabname. 4. Active y realice un test del programa.
514
© Copyright . Reservados todos los derechos.
Capítulo 11 Solución 29 Crear objetos de datos en tiempo de ejecución
Ejemplo empresarial Debe desarrollar un programa sencillo que visualice los contenidos de cualquier tabla de base de datos mediante las opciones disponibles en la programación dinámica. Genere y utilice objetos de datos en tiempo de ejecución, y utilice variables de referencia tipificados de manera genérica. Tarea 1 Copie el programa BC402_DYS_RTTI_HEADERS o su propio programa, ZBC402_##_RTTI_HEADERS y denomínelo ZBC402_##_CREATE_DATA, donde ## es su número de grupo. Familiarícese con el programa y su funcionamiento.
Consejo: Si no ha realizado el ejercicio en RTTI, simplemente copie el programa ZBC402_##_GEN_DATA. La visualización de las cabeceras de columna no es pertinente a este ejercicio. 1. Copie el programa y todos sus subcomponentes. a) Realice este paso como siempre. 2. Active y realice un test del programa. Analice el código fuente. ¿Qué objetos de datos se completan durante el acceso a la base de datos? ¿Qué tipos poseen? ¿Se crearon de manera estática o dinámica? a) Una de las dos tablas internas, gt_conn o gt_cust, se rellena dependiendo de la entrada de usuario. Mientras que el objeto de datos asignados a un Field Symbol (que, por lo tanto, se direcciona en la sentencia SELECT) se determina de manera dinámica, los objetos de datos en sí cuentan con definiciones estáticas (sentencia DATA).
Tarea 2 Reemplace las dos tablas internas definidas de manera estática con un objeto de datos que genere después de la estructura CASE (tabla estándar con clave estándar no única). Defina el tipo de objeto de datos de manera dinámica para garantizar que el tipo de línea coincida precisamente con la estructura de la tabla de la base de datos que desea leer. 1. Defina una referencia de datos de tipo genérico (el nombre sugerido es gr_data). a) Consulte el extracto del código fuente de la solución modelo.
© Copyright . Reservados todos los derechos.
515
Capítulo 11: Programación dinámica
2. Utilice la referencia de datos gr_data para generar una tabla interna inmediatamente después de la sentencia ENDCASE. Acceda a los contenidos del objeto de datos gv_tabname para definir el tipo de línea de la tabla de manera dinámica. a) Consulte el extracto del código fuente de la solución modelo. 3. Mueva una de las sentencias ASSIGN fuera de los bloques WHEN después de que se genere el objeto de datos y elimine la otra sentencia ASSIGN. Reemplace la tabla interna definida de manera estática con la tabla generada de manera dinámica. Consejo: Anule la referencia de datos genérica.
a) Consulte el extracto del código fuente de la solución modelo. 4. ¿Por qué no puede continuar utilizando gr_data de manera directa? a) Porque gr_data posee un tipo genérico y ABAP solo admite el acceso con referencia anulada a las referencias de datos de tipo genérico en las sentencias ASSIGN. 5. Elimine las definiciones de las dos tablas internas estáticas o márquelas como comentarios. a) Consulte el extracto del código fuente de la solución modelo. 6. Active y realice un test del programa. a) Realice este paso como siempre.
Tarea 3 La parte estática del programa ahora solo contiene el llenado de objeto de datos gv_tabname con un literal adecuado para el nombre de la tabla de base de datos. Reemplace ambas casillas de verificación en la pantalla de selección con un parámetro para el nombre de cualquier tabla de base de datos. 1. Elimine los parámetros de las definiciones de ambas casillas de verificación o márquelas como comentarios. Copie la entrada de usuario del parámetro directamente al objeto de datos gv_tabname en lugar de evaluar las casillas de verificación en una estructura CASE. a) Consulte el extracto del código fuente de la solución modelo. 2. Cree un nuevo parámetro (el nombre sugerido es pa_tab). Consejo: Si utiliza el tipo global dd02l-tabname, proporcione una función de ayuda para valores (F4) para los usuarios. a) Consulte el extracto del código fuente de la solución modelo. 3. Elimine la estructura CASE o márquela como comentario. En la misma posición, programe una asignación de valor de pa_tab a gv_tabname. a) Consulte el extracto del código fuente de la solución modelo. 4. Active y realice un test del programa.
516
© Copyright . Reservados todos los derechos.
Lección: Creación de tipos de datos, objetos de datos y objetos en tiempo de ejecución
a) Realice este paso como siempre. *&--------------------------------------* *& Report BC402_DYS_CREATE_DATA *& *&--------------------------------------* *& *& *&--------------------------------------* REPORT bc402_dys_create_data MESSAGE-ID bc402. *DATA: * gt_cust TYPE ty_customers, * gt_conn TYPE ty_connections. DATA: gr_data TYPE REF TO data. DATA: gv_tabname TYPE string. FIELD-SYMBOLS: TYPE ANY TABLE. SELECTION-SCREEN COMMENT 1(80) text-sel. *PARAMETERS: * pa_xconn TYPE xfeld RADIOBUTTON GROUP tab DEFAULT 'X', * pa_xcust TYPE xfeld RADIOBUTTON GROUP tab . PARAMETERS pa_tab TYPE dd02l-tabname DEFAULT 'SPFLI'. PARAMETERS: pa_nol TYPE i DEFAULT '100'. START-OF-SELECTION. * specific part *---------------------------------* * CASE 'X'. * WHEN pa_xconn. * * gv_tabname = 'SPFLI'. * ASSIGN gt_conn TO . * * WHEN pa_xcust. * * gv_tabname = 'SCUSTOM'. * ASSIGN gt_cust TO . * * ENDCASE. * dynamic part *---------------------------------* gv_tabname = pa_tab. CREATE DATA gr_data TYPE TABLE OF (gv_tabname). ASSIGN gr_data->* TO . TRY. SELECT * FROM (gv_tabname) INTO TABLE UP TO pa_nol ROWS. CATCH cx_sy_dynamic_osql_error. MESSAGE e061. ENDTRY.
© Copyright . Reservados todos los derechos.
517
Capítulo 11: Programación dinámica
CALL METHOD cl_bc402_dys_rtti_headers=>write_headers EXPORTING iv_tabname = gv_tabname EXCEPTIONS type_not_found = 1 no_structure = 2 no_ddic_type = 3. CASE sy-subrc. WHEN 1. MESSAGE e050 WITH gv_tabname. WHEN 2. MESSAGE e051 WITH gv_tabname. WHEN 3. MESSAGE e052 WITH gv_tabname. ENDCASE. cl_bc402_dys_gen_types=>write_any_table( ).
518
© Copyright . Reservados todos los derechos.
Lección: Creación de tipos de datos, objetos de datos y objetos en tiempo de ejecución
Creación de tipo en tiempo de ejecución (RTTC)
Figura 211: Métodos de creación de tipo dinámico de Run Time Type Services
RTTI le permite describir tipos de datos y tipos de objetos con instancias de las clases RTTI u objetos de descripción de tipos. El concepto RTTI se mejoró en SAP Web AS 6.40. Además de describir los tipos existentes, utilícelo para generar nuevos tipos. Este conjunto de funciones mejorado se denomina creación de tipos en tiempo de ejecución (RTTC). RTTC consta de una serie de métodos estáticos adicionales en las clases de descripción RTTI.
Consejo: Tenga en cuenta que la generación de tipos se limita a los tipos de datos. No puede generar clases o interfaces de manera dinámica. En la figura, las clases CL_ABAP_REFDESCR, CL_ABAP_STRUCTDESCR y CL_ABAP_TABLEDESCR se mejoraron con un método CREATE, mientras que la clase CL_ABAP_ELEMDESCR recibe un método GET adecuado para cada tipo ABAP elemental integrado, como GET_I, GET_F, GET_C, GET_STRING. Estos métodos devuelven punteros a una instancia de la clase correspondiente. A diferencia de los métodos DESCRIBE de la clase de raíz, los valores de atributo de esta instancia no provienen del análisis de un objeto de datos, una referencia o un tipo denominado. En lugar de ello, se transmiten al método RTTC de manera explícita. Las firmas de método se diseñaron en consecuencia. Mientras que el método GET_I no necesita otra entrada (tipo i completo), el método GET_P cuenta con dos parámetros para import definidos: uno de longitud y el otro de cantidad de posiciones decimales. El método CREATE para los tipos de referencia prevé el puntero para el objeto de descripción del tipo de referencia, mientras que el método CREATE para los tipos de estructura prevé una lista con los nombres y los tipos de los componentes. Cuando se generan los tipos de tabla, se prevé una referencia a un objeto RTTI que describe el tipo de línea (entre otras cosas).
© Copyright . Reservados todos los derechos.
519
Capítulo 11: Programación dinámica
Creación dinámica de tipo de tabla
Figura 212: RTTC – Creación de un tipo de tabla
En la figura se muestra cómo generar un tipo de tabla de manera dinámica con RTTC. Debe especificar solo el parámetro P_LINE_TYPE para el método CREATE. El parámetro es del tipo REF TO CL_ABAP_DATADESCR y necesita suministrarse con una referencia a cualquier objeto de descripción para un tipo de datos. En el ejemplo que se muestra en la figura, SPFLI se usa como el tipo de línea. El método DESCRIBE_BY_NAME devuelve el objeto de descripción que coincide. Los parámetros opcionales se utilizan para definir el tipo de tabla y la clave. Si no los especifica, el sistema utiliza una tabla estándar con una clave estándar no única.
520
© Copyright . Reservados todos los derechos.
Lección: Creación de tipos de datos, objetos de datos y objetos en tiempo de ejecución
Uso de un tipo de datos creado de manera dinámica
Figura 213: Generación de una tabla interna con un tipo creado dinámicamente
Para crear un objeto de datos de manera dinámica con este tipo específico, utilice el tipo generado de manera dinámica en la sentencia CREATE DATA. Utilice el suplemento HANDLE con la sentencia CREATE DATA para generar un objeto de datos cuyo tipo coincide con el objeto de descripción del tipo especificado. Especifique el HANDLE como una variable de referencia con el tipo estático CL_ABAP_DATADESCR o una de sus subclases. El sistema puede haber creado el objeto sobre la base de tipos de datos existentes utilizando métodos RTTI o definiendo dinámicamente un nuevo tipo de datos.
© Copyright . Reservados todos los derechos.
521
Capítulo 11: Programación dinámica
522
© Copyright . Reservados todos los derechos.
Capítulo 11 Ejercicio 30 Crear tipos de datos en tiempo de ejecución con la creación de tipos en tiempo de ejecución (RTTC)
Ejemplo empresarial Ha desarrollado un programa sencillo que visualiza los contenidos de cualquier tabla de base de datos. El programa ahora necesita permitir a los usuarios seleccionar las columnas específicas que desean leer y visualizar. Debe usar el módulo de funciones BC402_SELECT_COMPONENTS, que visualiza todos los componentes de un tipo de estructura global y permite a los usuarios seleccionar los componentes. Por ello, debe utilizar las opciones de creación de tipos en tiempo de ejecución (RTTC) para generar un tipo de tabla de manera dinámica. El tipo de tabla debería contener solo los componentes seleccionados por el usuario en sus líneas. Utilice el RTTC para generar tipos de estructura y tipos de tabla en tiempo de ejecución, y genere objetos de datos basados en tipos de datos dinámicos. Tarea 1 Visualice el módulo de funciones BC402_SELECT_COMPONENTS. Analice la interfaz y pruebe el ámbito funcional del módulo de funciones. 1. Visualice el módulo de funciones. Analice la interfaz. ¿Qué parámetros hay y cuáles son sus tipos? 2. ¿Qué excepciones puede emitir el módulo de funciones y cuál es el propósito de estas? 3. Realice un test del módulo de funciones.
Tarea 2 Copie el programa BC402_DYS_CREATE_DATA o su propio programa ZBC402_##_CREATE_DATA y denomínelo ZBC402_##_RTTC, donde ## representa su número de grupo. Familiarícese con el programa y su funcionamiento. Implemente una llamada del módulo de funciones antes de la generación dinámica de los objetos de datos. Transmita el nombre de la tabla que el usuario introdujo en la pantalla de selección para el parámetro para import. 1. Copie el programa y todos sus subcomponentes. 2. Llame el módulo de funciones antes de la sentencia CREATE DATA. Cree un objeto de datos tipificado correctamente para proporcionar datos al parámetro para export. Transmita los contenidos de gv_tabname al parámetro para import. Reaccione a las excepciones con mensajes de error adecuados de la clase de mensaje BC402.
© Copyright . Reservados todos los derechos.
523
Capítulo 11: Programación dinámica
Tarea 3 Copie el modelo CL_BC402_DYT_RTTC y denomínelo ZCL_BC402_##_RTTC, donde ## representa su número de grupo. Familiarícese con la firma del método create_table_type. 1. Copie la clase global. 2. Analice la firma de método create_table_type. ¿Qué parámetros se definen? ¿Cómo están tipificadas?
Tarea 4 Implemente el método create_table_type. Utilice las técnicas RTTI para analizar el tipo de datos cuyo nombre se encuentra en el parámetro para import. Utilice un método de navegación adecuado para calcular una lista con los nombres y los objetos de descripción tipo RTTI para todos los componentes de la estructura. 1. Llame un método de clase adecuado CL_ABAP_TYPEDESCR para generar un objeto de descripción de tipo para el tipo de datos. Cree una variable de referencia con un tipo adecuado para el valor de retorno (nombre sugerido: lo_struct). Consejo: Por motivos de simplicidad, asuma que el tipo de datos es un tipo de estructura en el Diccionario ABAP y realice un down cast directo para la variable de referencia correspondiente. 2. Llame al método get_components para la instancia RTTI. Cree un objeto de datos con un tipo adecuado para el valor de retorno (el nombre sugerido es lt_comps).
Tarea 5 Modifique la lista de componentes de manera que solo contenga los componentes detallados en el parámetro para it_comp_names. Según esta lista de componentes, cree un nuevo tipo de estructura y, a continuación, un nuevo tipo de tabla. 1. Implemente un loop a través de la lista de componentes lt_comps. 2. Verifique si el nombre del componente en cada línea se encuentra en el parámetro para import it_comp_names. Consejo: Utilice una sentencia como FIND ... IN TABLE o READ TABLE ... TRANSPORTING NO FIELDS. 3. Elimine la línea actual de lt_comps si el nombre de tabla correspondiente no se encuentra en el parámetro para import it_comp_names.
524
© Copyright . Reservados todos los derechos.
Lección: Creación de tipos de datos, objetos de datos y objetos en tiempo de ejecución
Consejo: Aquí, utilice la sintaxis abreviada para el acceso mediante índice en loops.
4. Para generar un objeto de descripción de tipo RTTI para un nuevo tipo de estructura, llame el método CREATE de la clase CL_ABAP_STRUCTDESCR. Transmita la lista de componentes reducida al método. Cree un objeto de datos con un tipo adecuado para el parámetro de retorno (nombre sugerido: lo_struct_new). 5. Para generar un objeto de descripción de tipo RTTI para un nuevo tipo de tabla, llame el método CREATE de la clase CL_ABAP_TABLEDESCR. Transmita la referencia al objeto RTTI para el nuevo tipo de estructura. Deje todos los parámetros opcionales configurados en sus valores propuestos. Transfiera el resultado de la llamada de método directamente al parámetro de retorno ro_table_def del método create_table_type.
Tarea 6 Regrese a su programa ejecutable ZBC402_##_RTTC. Llame el método create_table_type para generar un tipo de tabla conforme a los requisitos del usuario. Utilice un nuevo tipo de datos cuando genere el objeto de datos de manera dinámica. Modifique la sentencia SELECT de manera que solo lea los campos de la base de datos contenidos en el tipo de línea de la tabla interna.
Consejo: El método write_headers aún envía las cabeceras de todas las columnas de la tabla. Trabaje sin las cabeceras por completo o utilice el método write_headers_by_data de la clase CL_BC402_DYS_RTTI_HEADERS. Este método analiza el tipo de línea real de una tabla interna y muestra las cabeceras de columna que le corresponden. 1. Llame el método create_table_type en el programa directamente después de la llamada del módulo de funciones BC402_SELECT_COMPONENTS. Transmita el nombre de la tabla de base de datos y la lista de componentes que seleccionó el usuario al método create_table_type. 2. Modifique el tipo en la sentencia CREATE DATA. Utilice el suplemento TYPE HANDLE para utilizar el tipo de tabla recientemente generado. 3. Modifique la sentencia SELECT. Utilice la lista de nombres de componentes como una lista de campo dinámica. Consejo: De manera alternativa, utilice el suplemento INTO CORRESPONDING FIELDS OF TABLE. 4. Active y realice un test del programa.
© Copyright . Reservados todos los derechos.
525
Capítulo 11 Solución 30 Crear tipos de datos en tiempo de ejecución con la creación de tipos en tiempo de ejecución (RTTC)
Ejemplo empresarial Ha desarrollado un programa sencillo que visualiza los contenidos de cualquier tabla de base de datos. El programa ahora necesita permitir a los usuarios seleccionar las columnas específicas que desean leer y visualizar. Debe usar el módulo de funciones BC402_SELECT_COMPONENTS, que visualiza todos los componentes de un tipo de estructura global y permite a los usuarios seleccionar los componentes. Por ello, debe utilizar las opciones de creación de tipos en tiempo de ejecución (RTTC) para generar un tipo de tabla de manera dinámica. El tipo de tabla debería contener solo los componentes seleccionados por el usuario en sus líneas. Utilice el RTTC para generar tipos de estructura y tipos de tabla en tiempo de ejecución, y genere objetos de datos basados en tipos de datos dinámicos. Tarea 1 Visualice el módulo de funciones BC402_SELECT_COMPONENTS. Analice la interfaz y pruebe el ámbito funcional del módulo de funciones. 1. Visualice el módulo de funciones. Analice la interfaz. ¿Qué parámetros hay y cuáles son sus tipos? a) Hay un parámetro para import, iv_tabname, con el tipo csequence y un parámetro para export, et_comp_names, con el tipo string_table (tabla estándar con el tipo de línea string). 2. ¿Qué excepciones puede emitir el módulo de funciones y cuál es el propósito de estas? a) El módulo de funciones emite excepciones y se utilizan para los siguientes objetivos: ●
TYPE_NOT_FOUND El tipo transmitido se desconoce.
●
NO_STRUCTURE El tipo transmitido no es una estructura.
●
NO_DDIC_TYPE El tipo transmitido no es un tipo DDIC.
3. Realice un test del módulo de funciones. a) Realice este paso como siempre.
526
© Copyright . Reservados todos los derechos.
Lección: Creación de tipos de datos, objetos de datos y objetos en tiempo de ejecución
Tarea 2 Copie el programa BC402_DYS_CREATE_DATA o su propio programa ZBC402_##_CREATE_DATA y denomínelo ZBC402_##_RTTC, donde ## representa su número de grupo. Familiarícese con el programa y su funcionamiento. Implemente una llamada del módulo de funciones antes de la generación dinámica de los objetos de datos. Transmita el nombre de la tabla que el usuario introdujo en la pantalla de selección para el parámetro para import. 1. Copie el programa y todos sus subcomponentes. a) Realice este paso como siempre. 2. Llame el módulo de funciones antes de la sentencia CREATE DATA. Cree un objeto de datos tipificado correctamente para proporcionar datos al parámetro para export. Transmita los contenidos de gv_tabname al parámetro para import. Reaccione a las excepciones con mensajes de error adecuados de la clase de mensaje BC402. a) Consulte el extracto del código fuente de la solución modelo.
Tarea 3 Copie el modelo CL_BC402_DYT_RTTC y denomínelo ZCL_BC402_##_RTTC, donde ## representa su número de grupo. Familiarícese con la firma del método create_table_type. 1. Copie la clase global. a) Realice este paso como siempre. 2. Analice la firma de método create_table_type. ¿Qué parámetros se definen? ¿Cómo están tipificadas? a) El parámetro para import iv_tabname con el tipo genérico csequence, el parámetro para import it_comp_names con el tipo string_table y el parámetro de retorno ro_tabledescr, una referencia a la clase cl_abap_tabledescr.
Tarea 4 Implemente el método create_table_type. Utilice las técnicas RTTI para analizar el tipo de datos cuyo nombre se encuentra en el parámetro para import. Utilice un método de navegación adecuado para calcular una lista con los nombres y los objetos de descripción tipo RTTI para todos los componentes de la estructura. 1. Llame un método de clase adecuado CL_ABAP_TYPEDESCR para generar un objeto de descripción de tipo para el tipo de datos. Cree una variable de referencia con un tipo adecuado para el valor de retorno (nombre sugerido: lo_struct). Consejo: Por motivos de simplicidad, asuma que el tipo de datos es un tipo de estructura en el Diccionario ABAP y realice un down cast directo para la variable de referencia correspondiente. a) Consulte el extracto del código fuente de la solución modelo.
© Copyright . Reservados todos los derechos.
527
Capítulo 11: Programación dinámica
2. Llame al método get_components para la instancia RTTI. Cree un objeto de datos con un tipo adecuado para el valor de retorno (el nombre sugerido es lt_comps). a) Consulte el extracto del código fuente de la solución modelo.
Tarea 5 Modifique la lista de componentes de manera que solo contenga los componentes detallados en el parámetro para it_comp_names. Según esta lista de componentes, cree un nuevo tipo de estructura y, a continuación, un nuevo tipo de tabla. 1. Implemente un loop a través de la lista de componentes lt_comps. a) Consulte el extracto del código fuente de la solución modelo. 2. Verifique si el nombre del componente en cada línea se encuentra en el parámetro para import it_comp_names. Consejo: Utilice una sentencia como FIND ... IN TABLE o READ TABLE ... TRANSPORTING NO FIELDS. a) Consulte el extracto del código fuente de la solución modelo. 3. Elimine la línea actual de lt_comps si el nombre de tabla correspondiente no se encuentra en el parámetro para import it_comp_names. Consejo: Aquí, utilice la sintaxis abreviada para el acceso mediante índice en loops.
a) Consulte el extracto del código fuente de la solución modelo. 4. Para generar un objeto de descripción de tipo RTTI para un nuevo tipo de estructura, llame el método CREATE de la clase CL_ABAP_STRUCTDESCR. Transmita la lista de componentes reducida al método. Cree un objeto de datos con un tipo adecuado para el parámetro de retorno (nombre sugerido: lo_struct_new). a) Consulte el extracto del código fuente de la solución modelo. 5. Para generar un objeto de descripción de tipo RTTI para un nuevo tipo de tabla, llame el método CREATE de la clase CL_ABAP_TABLEDESCR. Transmita la referencia al objeto RTTI para el nuevo tipo de estructura. Deje todos los parámetros opcionales configurados en sus valores propuestos. Transfiera el resultado de la llamada de método directamente al parámetro de retorno ro_table_def del método create_table_type. a) Consulte el extracto del código fuente de la solución modelo.
Tarea 6 Regrese a su programa ejecutable ZBC402_##_RTTC. Llame el método create_table_type para generar un tipo de tabla conforme a los requisitos del usuario. Utilice un nuevo tipo de datos cuando genere el objeto de datos de manera dinámica.
528
© Copyright . Reservados todos los derechos.
Lección: Creación de tipos de datos, objetos de datos y objetos en tiempo de ejecución
Modifique la sentencia SELECT de manera que solo lea los campos de la base de datos contenidos en el tipo de línea de la tabla interna.
Consejo: El método write_headers aún envía las cabeceras de todas las columnas de la tabla. Trabaje sin las cabeceras por completo o utilice el método write_headers_by_data de la clase CL_BC402_DYS_RTTI_HEADERS. Este método analiza el tipo de línea real de una tabla interna y muestra las cabeceras de columna que le corresponden. 1. Llame el método create_table_type en el programa directamente después de la llamada del módulo de funciones BC402_SELECT_COMPONENTS. Transmita el nombre de la tabla de base de datos y la lista de componentes que seleccionó el usuario al método create_table_type. a) Consulte el extracto del código fuente de la solución modelo. 2. Modifique el tipo en la sentencia CREATE DATA. Utilice el suplemento TYPE HANDLE para utilizar el tipo de tabla recientemente generado. a) Consulte el extracto del código fuente de la solución modelo. 3. Modifique la sentencia SELECT. Utilice la lista de nombres de componentes como una lista de campo dinámica. Consejo: De manera alternativa, utilice el suplemento INTO CORRESPONDING FIELDS OF TABLE. 4. Active y realice un test del programa. a) Realice este paso como siempre. Método create_table_type (Clase CL_BC402_DYS_RTTC) METHOD create_table_type. DATA: lo_struct TYPE REF TO cl_abap_structdescr, lo_struct_new TYPE REF TO cl_abap_structdescr. DATA: lt_comps TYPE cl_abap_structdescr=>component_table. FIELD-SYMBOLS: LIKE LINE OF lt_comps. * get description of transparent table (=structure type) lo_struct ?= cl_abap_typedescr=>describe_by_name( iv_tabname ). * get list of components (including component types) lt_comps = lo_struct->get_components( ). LOOP AT lt_comps ASSIGNING .
© Copyright . Reservados todos los derechos.
529
Capítulo 11: Programación dinámica
FIND -name IN TABLE it_comp_names. IF sy-subrc <> 0. DELETE lt_comps. ENDIF. ENDLOOP. * alternatve solution with read table * remove all components but the requested ones * LOOP AT lt_comps ASSIGNING . * READ TABLE it_comp_names * TRANSPORTING NO FIELDS * WITH TABLE KEY table_line = -name. * IF sy-subrc <> 0. * DELETE lt_comps . * ENDIF. * * ENDLOOP. * create new structure type with the remaining components lo_struct_new = cl_abap_structdescr=>create( p_components = lt_comps ). * create table type with this new structure type as line type ro_tabledescr = cl_abap_tabledescr=>create( p_line_type = lo_struct_new ). ENDMETHOD. Programa ejecutable BC402_DYS_RTTC REPORT
bc402_dys_rttc MESSAGE-ID bc402.
DATA: gr_table
TYPE REF TO data.
DATA: gv_tabname TYPE string. DATA: gt_comp_names TYPE string_table, go_table TYPE REF TO cl_abap_tabledescr. FIELD-SYMBOLS: TYPE ANY TABLE. SELECTION-SCREEN COMMENT 1(80) text-sel. PARAMETERS pa_tab TYPE dd02l-tabname DEFAULT 'SPFLI'. PARAMETERS: pa_nol TYPE i DEFAULT '100'. START-OF-SELECTION. gv_tabname = pa_tab. CALL FUNCTION 'BC402_SELECT_COMPONENTS' EXPORTING iv_tabname = gv_tabname IMPORTING et_comp_names = gt_comp_names EXCEPTIONS type_not_found = 1
530
© Copyright . Reservados todos los derechos.
Lección: Creación de tipos de datos, objetos de datos y objetos en tiempo de ejecución
no_structure no_ddic_type
= 2 = 3.
CASE sy-subrc. WHEN 1. MESSAGE e050 WITH gv_tabname. WHEN 2. MESSAGE e051 WITH gv_tabname. WHEN 3. MESSAGE e052 WITH gv_tabname. ENDCASE. go_table = cl_bc402_dys_rttc=>create_table_type( iv_tabname = gv_tabname it_comp_names = gt_comp_names ). CREATE DATA gr_table TYPE HANDLE go_table. ASSIGN gr_table->* TO . TRY.
SELECT (gt_comp_names) FROM (gv_tabname) INTO TABLE UP TO pa_nol ROWS. CATCH cx_sy_dynamic_osql_error. MESSAGE e061. ENDTRY. CALL METHOD cl_bc402_dys_rtti_headers=>write_headers_by_data EXPORTING it_table = EXCEPTIONS no_structure = 1 no_ddic_type = 2 component_not_elem = 3. CASE sy-subrc. WHEN 1. MESSAGE e050 WITH gv_tabname. WHEN 2. MESSAGE e051 WITH gv_tabname. WHEN 3. MESSAGE e053 WITH gv_tabname. ENDCASE. cl_bc402_dys_gen_types=>write_any_table( ).
© Copyright . Reservados todos los derechos.
531
Capítulo 11: Programación dinámica
RESUMEN DE LA LECCIÓN Ahora podrá:
532
●
Crear objetos (instancias) en tiempo de ejecución
●
Crear objetos de datos en tiempo de ejecución
●
Crear tipos de datos en tiempo de ejecución
© Copyright . Reservados todos los derechos.
Capítulo 11 Evaluación de la formación
1. El INDEX TABLE es un tipo de datos genérico especial que solo es compatible con tablas internas. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
2. Los Field Symbols son punteros que asigna a objetos de datos de manera estática. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
3. Puede reemplazar los objetos de datos en posiciones de operando directamente por objetos de datos alfanuméricos en paréntesis mediante la sentencia ASSIGN para el objeto de datos al cual debe asignar el Field Symbol. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
4. Cuando asigna valores entre las dos variables de referencia con tipos diferentes, esto se denomina “asignación de casting”. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
533
Capítulo 11: Evaluación de la formación
5. ¿Cuál de las siguientes clases instancia y utiliza para describir tipos específicos? Seleccione las respuestas correctas. X
A CL_ABAP_ELEMDESCR
X
B CL_ABAP_INTFDESCR
X
C CL_ABAP_STRUCTDESCR
X
D CL_ABAP_RTTI
6. Las clases de descripción para los tipos de objetos proporcionan métodos de navegación para determinar los detalles de un tipo utilizado. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
7. Para generar objetos en tiempo de ejecución, el tipo estático de la variable de referencia debe ser compatible con la clase. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
8. Si utiliza objetos de datos alfanuméricos entre paréntesis, también puede definir el tipo de datos para los objetos de datos generados de manera dinámica. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
9. Con el suplemento HANDLE, la sentencia CREATE DATA crea un objeto de datos cuyo tipo de datos es descrito por un objeto de descripción RTTS. Indique si esta afirmación es verdadera o falsa.
534
X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
Capítulo 11 Respuestas a la Evaluación de la formación
1. El INDEX TABLE es un tipo de datos genérico especial que solo es compatible con tablas internas. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
2. Los Field Symbols son punteros que asigna a objetos de datos de manera estática. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
3. Puede reemplazar los objetos de datos en posiciones de operando directamente por objetos de datos alfanuméricos en paréntesis mediante la sentencia ASSIGN para el objeto de datos al cual debe asignar el Field Symbol. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
4. Cuando asigna valores entre las dos variables de referencia con tipos diferentes, esto se denomina “asignación de casting”. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.
535
Capítulo 11: Respuestas a la Evaluación de la formación
5. ¿Cuál de las siguientes clases instancia y utiliza para describir tipos específicos? Seleccione las respuestas correctas. X
A CL_ABAP_ELEMDESCR
X
B CL_ABAP_INTFDESCR
X
C CL_ABAP_STRUCTDESCR
X
D CL_ABAP_RTTI
6. Las clases de descripción para los tipos de objetos proporcionan métodos de navegación para determinar los detalles de un tipo utilizado. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
7. Para generar objetos en tiempo de ejecución, el tipo estático de la variable de referencia debe ser compatible con la clase. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
8. Si utiliza objetos de datos alfanuméricos entre paréntesis, también puede definir el tipo de datos para los objetos de datos generados de manera dinámica. Indique si esta afirmación es verdadera o falsa. X
Verdadero
X
Falso
9. Con el suplemento HANDLE, la sentencia CREATE DATA crea un objeto de datos cuyo tipo de datos es descrito por un objeto de descripción RTTS. Indique si esta afirmación es verdadera o falsa.
536
X
Verdadero
X
Falso
© Copyright . Reservados todos los derechos.