Documentos de Académico
Documentos de Profesional
Documentos de Cultura
STL,
Plantillas,
Excepciones,
Roles y Objetos.
por
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 3
AGRADECIMIENTOS
Este libro es el resultado de casi dos años de trabajo, en los cuales he añadido,
corregido, modificado y aun eliminado capítulos enteros. En tal período han cabi-
do artículos, conferencias, mesas redondas, intercambios de correo y cientos de
horas de lectura técnica; como también muchas personas que han influido directa
o indirectamente en el trabajo que el lector tiene ahora en sus manos. Los amigos
y colegas de APTO2 (Juan Manuel Cueva, César Pérez-Chirinos, Miguel Katrib,
Luis Joyanes, Pablo Peláez y otros muchos) han contribuido con sus inestimables
ideas y su espíritu crítico, en las diversas conferencias en que hemos coincidido
(así como en larguísimas conversaciones telefónicas), a refinar algunos de los
puntos expuestos en el texto. Ha resultado valiosísima también la colaboración de
muchos anónimos lectores (ya no tan anónimos) que mandaron correos con suge-
rencias y críticas. Antonio Vázquez corrigió el texto con una celeridad y diligencia
impresionantes, y José Bernabéu buscó un hueco entre viaje y viaje para leerlo:
mi gratitud para ambos. A Daniel Alonso le debo un mucho de amabilidad y ayu-
da. A María Teresa Gómez-Mascaraque, de Editorial Paraninfo, quisiera agrade-
cerle, por fin, su paciencia con un original que ha sufrido retraso tras retraso.
Mi familia merece una mención aparte: mis hijos, Ricardo y Andrea, se han acos-
tumbrado a que los besara entre párrafo y párrafo, y para mi esposa, Consol, es
como si me hubiera trasladado durante mucho tiempo a otro huso horario. Al me-
nos me ha librado de pasear al perro, Spock, durante algunos meses.
Espero, en definitiva, que el lector disfrute tanto leyendo este libro como yo disfru-
té escribiéndolo.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 4
ÍNDICE
i
AGRADECIMIENTOS................................................................................................................................................. 4
ÍNDICE............................................................................................................................................................................ 5
INTRODUCCIÓN.......................................................................................................................................................12
¿A QUIÉN VA DIRIGIDO ESTE LIBRO?.............................................................................................................12
SOBRE EL AUTOR.................................................................................................................................................13
UNA VISIÓN PANORÁMICA ....................................................................................................................................13
Capítulo 1 - Objetos: Hitos, Mitos y Ritos...................................................................................................13
Capítulo 2 - Contenedores en C++ .............................................................................................................14
Capítulo 3 - C++ STL: La Biblioteca Estándar de Plantillas en C++.................................................14
Capítulo 4 - Manejo de Excepciones en C++............................................................................................14
Capítulo 5 - Asignación en C++ ..................................................................................................................15
Capítulo 6 - Patrones de Diseño: La Calidad Sin Nombre .....................................................................15
Capítulo 7 - Roles y Objetos en C++...........................................................................................................15
Capítulo 8 - Bases de Datos Orientadas-a-Objetos...................................................................................16
Capítulo 9 - Consideraciones Prácticas.....................................................................................................16
Capítulo 10 - Gestión de Proyectos Orientados-a-Objetos.....................................................................16
Capítulo 11 - Modelos de Roles: El Método Ooram.................................................................................16
Capítulo 12 - Bibliografía Comentada .......................................................................................................17
GARANTÍA .............................................................................................................................................................17
OBJETOS: HITOS, MITOS Y RITOS ...................................................................................................................18
MITO 1: UN LENGUAJE ORIENTADO-A-OBJETOS “PURO” ES MEJOR QUE OTRO “HÍBRIDO”......................18
MITO 2: PARA APRENDER A USAR ADECUADAMENTE C++ HAY QUE EMPEZAR POR SMALLTALK. ......19
MITO 3: C++ ES MÁS FÁCIL DE ASIMILAR PARA LOS PROGRAMADORES DE C. ............................................19
MITO 4: LAS HERRAMIENTAS OOCASE INTEGRADAS GENERAN CÓDIGO ORIENTADO-A-OBJETOS
FIABLE. .....................................................................................................................................................................20
MITO 5: LA HERENCIA ES UNA CUALIDAD ESENCIAL DE LOS SISTEMAS ORIENTADOS-A-OBJETOS........20
MITO 6: LA HERENCIA ES UN MECANISMO INDISPENSABLE EN LOS LENGUAJES DE PROGRAMACIÓN
ORIENT ADOS-A-OBJETOS.......................................................................................................................................21
MITO 7: LA HERENCIA ÚNICAMENTE SE PUEDE APLICAR CUANDO SE DA UNA RELACIÓN “ES-UN”....21
MITO 8: EXISTEN DEMASIADAS METODOLOGÍAS DE ANÁLISIS Y DISEÑO ORIENTADAS-A-OBJETOS.....22
MITO 9: CADA EMPRESA DEBE ADAPTAR A SU MANERA LOS MÉTODOS EXISTENTES PARA
CONSTRUIRSE UNO “A MEDIDA”..........................................................................................................................22
MITO 10: LO PRIMERO QUE HAY QUE HACER ES CREAR UNA BIBLIOTECA DE CLASES REUTILIZABLES.23
CONTENEDORES Y PLANTILLAS.......................................................................................................................24
DISEÑO DE CONTENEDORES.............................................................................................................................25
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 5
LA OPCIÓN INGENUA: CUESTIÓN DE ÁMBITOS.........................................................................................26
LA TRAMPA DEL PREPROCESADOR..............................................................................................................27
CUANDO LA HERENCIA ES DISPUTADA ......................................................................................................30
HERENCIA MÚLTIPLE: ¿MÁS DE LO MISMO?..............................................................................................41
ITERADORES..........................................................................................................................................................42
LAS PLANTILLAS: CON HERENCIA, SIN ELLA O A SU PESAR................................................................43
C++ STL.......................................................................................................................................................................46
ESTRUCTURA DE LA BIBLIOTECA..................................................................................................................47
CONTENEDORES ...................................................................................................................................................48
ITERADORES..........................................................................................................................................................50
ALGORITMOS........................................................................................................................................................56
¿FUNCIONES-OBJETO U OBJETOS-FUNCIONES?.........................................................................................57
DE LOS PELIGROS DE LA EXTENSIBILIDAD.................................................................................................59
LEVES CRÍTICAS...................................................................................................................................................62
APRENDIZAJE Y DOCUMENTACIÓN..............................................................................................................63
REFERENCIAS DIRECTAS...................................................................................................................................64
MANEJO DE EXCEPCIONES EN C++...................................................................................................................65
LOS CÓDIGOS DE ERROR....................................................................................................................................65
CONCEPTOS BÁSICOS.........................................................................................................................................68
MANOS A LA OBRA ............................................................................................................................................70
CLASES DE EXCEPCIONES .................................................................................................................................73
JERARQUÍAS DE CLASES DE EXCEPCIONES ................................................................................................73
EL DESBOBINADO DE LA PILA.........................................................................................................................74
CONSISTENCIA DE ESTADOS...........................................................................................................................75
ADQUISICIÓN DE RECURSOS VÍA INICIALIZACIÓN..................................................................................76
ESPECIFICACIÓN DE INTERFACES ..................................................................................................................78
EL FINAL DE LA CUERDA ..................................................................................................................................79
VULNERACIÓN DE LA ESPECIFICACIÓN DE EXCEPCIONES ....................................................................80
CONCLUSIONES ....................................................................................................................................................81
REFERENCIAS DIRECTAS...................................................................................................................................81
ASIGNACIÓN EN C++..............................................................................................................................................83
CONCEPTOS BÁSICOS.........................................................................................................................................83
EL OPERADOR DE ASIGNACIÓN POR DEFECTO..........................................................................................84
LOS LÍMITES EXPLÍCITOS DE LA ASIGNACIÓN IMPLÍCITA....................................................................85
LA COPIA DE UN PUNTERO GENERA ... ¡OTRO PUNTERO! ......................................................................87
ASIGNACIÓN NO ES INICIALIZACIÓN...........................................................................................................87
EL OPERADOR POR DEFECTO RESULTA DEFECTUOSO............................................................................88
EL OPERADOR DE ASIGNACIÓN EXPLÍCITO................................................................................................89
DESIGNACIÓN NO ES ASIGNACIÓN................................................................................................................90
LO QUE LA ASIGNACIÓN PRODUCE...............................................................................................................91
CONVERSIÓN, CONSTRUCCIÓN Y ASIGNACIÓN.........................................................................................92
LA ASIGNACIÓN EN JERARQUÍAS DE HERENCIA......................................................................................93
ASIGNACIÓN NO ES TRANSMUTACIÓN.......................................................................................................93
RECURSIVIDAD EXPLÍCITA: CÉSAR O NADA..............................................................................................94
CUIDADO CON LA AUTO-ASIGNACIÓN .......................................................................................................95
IDENTIDAD, IGUALDAD Y ... ¿FRATERNIDAD? ..........................................................................................97
SOBRE LA ASIGNACIÓN BIDIRECCIONAL....................................................................................................98
POLIMORFISMO EN ASIGNACIÓN ................................................................................................................100
CUANDO LA ASIGNACIÓN ES INDESEABLE..............................................................................................101
LA ASIGNACIÓN CON CLASES BASE VIRTUALES ...................................................................................102
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 6
ALGUNOS CONFUSOS CONSEJOS..................................................................................................................103
REFERENCIAS DIRECTAS.................................................................................................................................103
PATRONES DE DISEÑO........................................................................................................................................105
LA CALIDAD SIN NOMBRE .............................................................................................................................105
PATRONES DE DISEÑO SOFTWARE .............................................................................................................106
CATÁLOGOS DE PATRONES ...........................................................................................................................108
¿PATRONES ORIENTADOS-A-OBJETOS?.....................................................................................................109
TELEPREDICADORES DE SOFTWARE ..........................................................................................................109
PATRONES ELECTRÓNICOS ............................................................................................................................110
ROLES Y OBJETOS EN C++ ................................................................................................................................113
CLASES DE ROLES..............................................................................................................................................114
UNA BUENA HERENCIA ¿LO ARREGLA TODO? ........................................................................................115
DINÁMICA DE CLASES.....................................................................................................................................116
LA HERENCIA INNECESARIA .........................................................................................................................117
DIVIDE Y HEREDARÁS......................................................................................................................................120
EL PATRON DE ROLES INTERCAMBIABLES...............................................................................................123
EL PATRON DE ESTADOS ................................................................................................................................124
EL PATRÓN PROXY DE SUBROGACIÓN.......................................................................................................125
CONVERSIONES E INDIRECCIÓN....................................................................................................................126
CONCURRENCIA Y SECUENCIACIÓN DE ROLES .......................................................................................129
EN LA ASOCIACIÓN ESTÁ LA FUERZA.......................................................................................................130
LA CITA DEL DESASOSIEGO ...........................................................................................................................135
REFERENCIAS DIRECTAS.................................................................................................................................135
BASES DE DATOS ORIENTADAS-A-OBJETOS ............................................................................................137
DEGRADADO DE BASES DE DATOS.............................................................................................................137
LOS DESEOS DEL PROGRAMADOR...............................................................................................................139
PERSISTENCIA, TRANSITORIEDAD Y MATRICES ....................................................................................140
ORTOGONALIDAD DE PERSISTENCIA Y TIPO...........................................................................................140
CRÍTICA DE LA RAZÓN PRÁCTICA ..............................................................................................................142
INTERNET: ¿CÓMO NO? ....................................................................................................................................142
CONSIDERACIONES PRÁCTICAS ....................................................................................................................144
PANORAMA PARA MATAR...........................................................................................................................145
REFLEXIONES REBAJADAS.............................................................................................................................146
Distribución Jerárquica Cósmica de Clases............................................................................................146
El Paradigma M2VC.....................................................................................................................................147
Arquitectura Gráfica MultiModal..............................................................................................................148
Gestión de Concurrencias............................................................................................................................151
Gestión de Objetos a través de Vistas........................................................................................................155
Incidencias de Usuarios...............................................................................................................................160
Actualización de Vistas ................................................................................................................................162
Seguridad del Sistema ..................................................................................................................................166
Gestión de Objetos mediante Colecciones................................................................................................171
Esquema de Consultas..................................................................................................................................172
Gestión de Dependencias entre Vistas.......................................................................................................178
GESTIÓN DE PROYECTOS ..................................................................................................................................181
EL SÍNDROME DE ESTOCOLMO.....................................................................................................................181
ANÁLISIS Y DISEÑO ORIENTADOS-A-OBJETOS.......................................................................................182
MÉTODOS COMERCIALES DE OOA/OOD....................................................................................................182
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 7
SOBRE LISTAS Y COMPARACIONES ............................................................................................................184
CÉSAR O NADA ..................................................................................................................................................185
LA SOLUCIÓN ECLÉCTICA...............................................................................................................................186
HERRAMIENTAS OOCASE...............................................................................................................................187
GESTIÓN DE PROYECTOS ORIENTADOS-A-OBJETOS..............................................................................187
SÍSIFO REDIVIVO.................................................................................................................................................188
MODELOS DE ROLES ...........................................................................................................................................189
ESCENARIOS Y APREHENSIONES ..................................................................................................................190
TRAS DIVIDIR HAY QUE MULTIPLICAR......................................................................................................192
EL LIBRO................................................................................................................................................................194
IDEAS PRINCIPALES ..........................................................................................................................................194
MODELADO DE ROLES .....................................................................................................................................195
SÍNTESIS DE MODELOS DE ROLES ................................................................................................................195
PUENTE A LA IMPLEMENTACIÓN................................................................................................................196
CREACIÓN DE COMPONENTES REUTILIZABLES ......................................................................................196
LEA, LECTOR: LEA..............................................................................................................................................197
REFERENCIAS DIRECTAS.................................................................................................................................197
BIBLIOGRAFÍA COMENTADA ...........................................................................................................................201
LIBROS BÁSICOS SOBRE C++..........................................................................................................................201
The C++ Workbook, por Richard S. Wiener & Lewis J. Pinson, 1990, Addison-Wesley, 0-201-
50930-X, 349 pág. .........................................................................................................................................201
A C++ Toolkit, por Jonathan S. Shapiro, 1990, Prentice Hall............................................................202
On to C++, por Patrick Henry Winston, 1994, Addison-Wesley, 0-201-58043-8.............................203
C++ Primer, 2 nd Edition, por Stanley B. Lippman, 1991, Addison-Wesley, 0-201-54848-8, 614 pág.
...........................................................................................................................................................................203
Mastering Object-Oriented Design in C++, por Cay S. Horstmann, 1995, John Wiley & Sons, 0-
471-59484-9. ..................................................................................................................................................204
Object-Oriented Design for C++, por Tsvi Bar-David, 1993, Prentice-Hall, 0-13-630260-2. .......204
The C++ Programming Language, 2 nd Edition, por Bjarne Stroustrup, 1991, Addison-Wesley, 0-
201-53992-6, 669 pág. .................................................................................................................................205
The Annotated C++ Reference Manual, por Margaret A. Ellis & Bjarne Stroustrup, 1990,
Addison-Wesley, 0-201-51459-1, 447 pág................................................................................................206
The Design and Evolution of C++, por Bjarne Stroustrup, 1994, Addison-Wesley, 0-201-54330-3.206
Algorithms in C++, por Robert Sedgewick, 1992, Addison-Wesley, 0-201-51059-6.......................207
LIBROS DE ESTILO EN C++...............................................................................................................................207
Effective C++: 50 Specific Ways to Improve Your Programs and Designs, por Scott Meyers, 1992,
Addison-Wesley, 0-201-56364-9.................................................................................................................207
C++ Programming Style, por Tom Cargill, 1992, Prentice Hall, 0-201-56365-7............................208
C++ Programming Guidelines, por Thomas Plum & Dan Saks, 1991, Plum Hall, 0-911537-10-4,
274 pág............................................................................................................................................................208
Taligent’s Guide To Designing Programs: Well-Mannered Object-Oriented Design in C++, por
Taligent Inc., 1994, Addison-Wesley, 0-201-40888-0.............................................................................209
LIBROS DE PROGRAMACIÓN MEDIA Y AVANZADA EN C++...............................................................210
C++ IOStreams Handbook, por Steve Teale, 1993, Addison-Wesley, 0-201-59641-5.....................210
Advanced C++ Programming Styles and Idioms, por James O. Coplien, 1992, Addison-Wesley, 0-
201-54855-0. ..................................................................................................................................................210
The Power of Frameworks for Windows and OS/2 Developers, por Taligent Inc., 1995, Addison-
Wesley, 0-201-48348-3. ................................................................................................................................211
Data Abstraction and Object-Oriented Programming in C++, por Keith E. Gorlen, Sanford M.
Orlow & Perry S. Plexico, 1990, John Wiley & Sons, 0-471-92346-X, 403 pág...............................212
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 8
C++ Strategies and Tactics, por Robert B. Murray, 1993, Addison-Wesley, 0-201-56382-7, 273
pág....................................................................................................................................................................213
Designing and Coding Reusable C++, por Martin D. Carroll y Margaret A. Ellis, 1995, Addison-
Wesley, 0-201-51284-X.................................................................................................................................213
Taming C++: Pattern Classes and Persistence for Large Projects, por Jiri Soukup, 1994, Addison-
Wesley, 0-201-52826-6. ................................................................................................................................214
LIBROS SOBRE SMALLTALK.................................................................................................................................214
Programación Orientada a Objetos: Aplicaciones con Smalltalk, Angel Morales & Francisco J.
Segovia, 1993, Paraninfo, 84-283-2019-5. ..............................................................................................215
Smalltalk Programming for Windows, Dan Shafer con Scott Herndon y Laurence Rozier, 1993,
Prisma Publishing, 1-55959-237-5............................................................................................................215
Object Oriented Programming, Peter Coad & Jill Nicola, 1993, Prentice-Hall, 0-13-032616-X,
con disquete del código C++ y Smalltalk................................................................................................215
Discovering Smalltalk, Wilf LaLonde, 1994, Benjamin Cummings, 0-8053-2720-7.........................216
Smalltalk -80: The Language, Adele Goldberg & David Robson, 1989, Addison-Wesley, 0-201-
13688-0............................................................................................................................................................216
Smalltalk -80: The Interactive Programming Environment, Adele Goldberg, 1984, Addison-Wesley,
0-201-11372-4................................................................................................................................................217
Inside Smalltalk I, Wilf LaLonde & John Pugh, 1990, Prentice-Hall, 0-13-468414-1. ...................217
Inside Smalltalk II, Wilf LaLonde & John Pugh, 1990, Prentice-Hall, 0-13-465964-3...................217
Smalltalk/V: Practice and Experience, Wilf LaLonde & John Pugh, 1994, Prentice-Hall, 0-13-
814039-1, con disquete. ...............................................................................................................................218
IBM Smalltalk: The Language, por David N. Smith, 1994, Addison-Wesley, 0-8053-0908-X........218
Smalltalk Best Practice Patterns - Volume 1: Coding, por Kent Beck................................................218
LIBROS SOBRE JAVA .........................................................................................................................................219
Hooked on Java: Creating Hot Web Sites with Java Applets, por Arthur van Hoff, Sami Shaio y
Orca Starbuck, 1995, Addison-Wesley, 0-201-48837-X, con CD-ROM. .............................................219
Mecklermedia’s Official Internet World 60 Minute Guide to Java, por Ed Tittel y Mark Gaither,
1995, IDG Books, 1-56884-711-4...............................................................................................................220
Java!, por Tim Ritchey, 1995, New Riders Publishing, 1-556205-533-X. ..........................................220
The Java Handbook: The Authoritative Guide to the Java Revolution, por Patrick Naughton,
1996, Osborne McGraw Hill, 0-07-882199-1. .........................................................................................220
The Java Primer Plus: Supercharging Web Applications with the Java Programming Language,
por Paul M. Týma, Gabriel Torok y Troy Downing, 1996, Wayte Group Press, 1-57169-062-X. ..221
LIBROS SOBRE SOFTWARE ORIENTADO-A-OBJETOS............................................................................221
Object-Oriented Software Construction, por Bertrand Meyer, 1988, Prentice Hall, 0-13-629031-
0,534 pág.........................................................................................................................................................221
A Book of Object-Oriented Knowledge, por Brian Henderson-Sellers, 1991, Prentice Hall, 0-13-
059445-8, 297 pág. .......................................................................................................................................222
Object-Oriented Methods, 2 nd Edition, por Ian M. Graham, 1994, Addison-Wesley, 0-201-59371-8,
473 pág............................................................................................................................................................223
Object-Oriented Programming, por Peter Coad y Jill Nicola, 1993, Prentice Hall-Yourdon Press,
0-13-032616-X, 582 págs. y disquete incluido........................................................................................223
LIBROS DE ANÁLISIS Y DISEÑO ORIENTADO-A-OBJETOS (OOA & OOD) ........................................224
Designing Object-Oriented Software, por Rebecca Wirfs-Brock, Brian Wilkerson & Lauren Wiener,
1990, Addison-Wesley, 0-13-629825-7, 368 pág.....................................................................................224
Using CRC Cards: An Informal Approach to Object-Oriented Development, por Nancy M.
Wilkinson, 1995, SIGS Books, 1-884842-07-0 (Prentice-Hall 0-13-374679-8), 226 págs.............225
Object-Oriented Modeling and Design, por James Rumbaugh, Michael Blaha, William Premerlani,
Frederick Eddy & William Lorensen, 1991, Prentice Hall, 0-13-629841-9, 528 pág. ....................226
Object-Oriented Analysis and Design with Applications, 2 nd Edition, por Grady Booch, 1994,
Benjamin/Cummings, 0-8053-5340-2, 589 pág. ......................................................................................227
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 9
Migrating to Object Technology, por Ian M. Graham, 1994, Addison-Wesley, 0-201-59389-0, 552
pág....................................................................................................................................................................228
Object-Oriented Analysis, 2nd Edition, por Peter Coad & Edward Yourdon, 1991, Yourdon
Press/Prentice Hall, 233 pág.......................................................................................................................228
Object-Oriented Design, por Peter Coad & Edward Yourdon, 1991, Prentice Hall, 0-13-630070-7.229
Object-Oriented Analysis: Modeling the World in Data, por Sally Shlaer & Stephen J. Mellor,
1988, Yourdon Press/Prentice Hall, 144 pág...........................................................................................229
Object Lifecycles: Modeling the World in States, por Sally Shlaer & Stephen J. Mellor, 1991,
Prentice Hall, 0-13-629940-7. ....................................................................................................................229
Object-Oriented Systems Analysis: A Model-Driven Approach, por David W. Embley, Barry D.
Kurtz & Scott N. Woodfield, 1992, Prentice Hall, 0-13-629973-3, 302 pág......................................230
Object-Oriented Software Engineering: A Use Case Driven Approach, por Ivar Jacobson, Magnus
Christerson, Patrik Jonsson y Gunnar Övergaard, 1992, Addison-Wesley, 0-201-54435-0, 524
págs. .................................................................................................................................................................230
Object Oriented Program Design with Examples in C++, por Mark Mullin, 1990, Addison-Wesley,
0-201-51722-1, 303 pág...............................................................................................................................231
A Complete Object-Oriented Design Example, por Joseph E. Richardson, Ronald C. Schultz &
Edward V. Berard, 1992, Berard Software Engineering Inc, 1-881974-01-4, 350 pág...................231
Working With Objects: The OOram Software Engineering Method, por Trygve Reenskaug con Per
Wold y Odd Arild Lehne, 1996, Manning Publications, 1 -884777-10-4 (Prentice Hall: 0-13-
452930-8)........................................................................................................................................................232
LIBROS SOBRE PATRONES DE DISEÑO .............................................................................................................232
Notes on the Synthesis of Design, de Christopher Alexander, 1964, Harvard University Press. ...232
A Pattern Language: Towns/Building/Construction, de Christopher Alexander, Sara Ishikawa,
Murray Silverstein, Max Jacobson, Ingrid Fiksdahl-King y Shlomo Angel, 1977, Oxford University
Press, 0-19-501919-9....................................................................................................................................232
The Oregon Experiment, de Christopher Alexander, 1978, Oxford University Press.......................233
The Timeless Way of Building, de Christopher Alexander, 1979, Oxford University Press.............233
The Production of Houses, de Christopher Alexander, 1985, Oxford University Press. ..................233
Advanced C++ Programming Styles and Idioms, por James O. Coplien, 1992, Addison-Wesley, 0-
201-54855-0. ..................................................................................................................................................233
Design Patterns: Elements of Reusable Object-Oriented Software, de Erich Gamma, Richard Helm,
Ralph Johnson y John Vlissides, 1995, Addison-Wesley, 0-201-63361-2. .........................................234
Design Patterns for Object-Oriented Software Development, de Wolfgang Pree, 1995, Addison
Wesley...............................................................................................................................................................234
Pattern Languages of Program Design, editado por James O. Coplien y Douglas C. Schmidt, 1995,
Addison-Wesley, 0-201-60734-4.................................................................................................................235
LIBROS SOBRE BASES DE OBJETOS......................................................................................................................235
Object-Oriented Concepts, Databases, and Applications, editado por Won Kim & Frederick H.
Lochovsky, 1989, Addison-Wesley, 0-201-14410-7. ...............................................................................235
Object-Orientation: Concepts, Languages, Databases, User Interfaces, Setrag Khoshafian &
Razmik Abnous, 1990, John Wiley & Sons, 0-471-51801-8..................................................................235
Object Data Management: Object-Oriented and Extended Relational Database systems, R.G.G.
Catell, 1991, Addison-Wesley, 0-201-53092-9. .......................................................................................236
Object-Oriented Databases, Setrag Khoshafian, 1993, John Wiley & Sons, 0-471-57056-7.........236
Sistemas de Bases de Datos Orientadas a Objetos: Conceptos y Arquitecturas, Elisa Bertino &
Lorenzo Martino, 1993 (traducción 1995), Addison-Wesley Iberoamericana, 0-201-65356-7. ...236
The Object Database Standard: ODMG-93, editado por R.G.G. Catell, 1994, Morgan Kaufmann
Publishers, 1-55860-302-6. .........................................................................................................................237
Object-Oriented Databases: Technology, Appllications and Products, Bindu R. Rao, 1994,
McGraw-Hill, 0-07-051279-5......................................................................................................................237
Object Databases: The Essentials, Mary E. S. Loomis, 1995, Addison-Wesley, 0-201-56341-X.....237
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 10
Modern Database Systems: The Object Model, Interoperability, and Beyond, editado por Won Kim,
1995, Addison-Wesley, 0-201-59098-0......................................................................................................237
LIBROS SOBRE INGENIERÍA DE PROCESOS.................................................................................................238
Reengineering the Corporation: A Manifesto for Business Revolution, por Michael Hammer &
James Champy, New York: HarperCollins Publishers, 1993, 0-88730-640-3...................................238
The Object Advantage: Business Process Reengineering with Object Technology, por Ivar
Jacobson, Maria Ericsson y Agneta Jacobson, ACM Press, 1994.......................................................238
Business Engineering with Object Oriented Technology, por David A. Taylor, John Wiley & Sons,
1995..................................................................................................................................................................238
LIBROS SOBRE GESTIÓN DE PROYECTOS...........................................................................................................239
Succeeding with Objects: Decision Frameworks for Project Management, por Adele Goldberg &
Kenneth S. Rubin, 1995, Addison-Wesley, 0-201-62878-3, 542 págs. ................................................239
Pitfalls of Object-Oriented Development, por Bruce F. Webster, 1995, M&T -Books, 1-55851-397-
3.........................................................................................................................................................................239
Object Lessons: Lessons Learned in Object-Oriented Development Projects, por Tom Love, 1993,
SIGS Books, 0-9627477-3-4 (Prentice-Hall 0-13-472432-1)...............................................................240
LIBROS CONTRA LA TONTERÍA ....................................................................................................................240
201 Principles of Software Development, por Alan M. Davis, 1995, McGraw-Hill, 0-07-015840-1.241
Software Requirements & Specifications: A Lexicon of Practice, Principles and Prejudices, por
Michael Jackson, 1995, Addison-Wesley, 0-201-87712-0.....................................................................241
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 11
INTRODUCCIÓN
ii
¿O tro libro sobre C++? Bueno, al menos no otro libro del tipo “Aprenda
C++ por ósmosis” o “¡Los secretos de C++ por fin revelados!”. La pre-
tensión de este texto es mucho más modesta: se trata de comunicar al
lector que también en C++ existen ciertas normas de estilo, y que tales normas se
desprenden tanto de la sintaxis del lenguaje como de prudentes decisiones de
diseño íntimamente relacionadas con la Tecnología de Objetos que anida tras el
lenguaje. La intención es, pues, colocar al lector en una posición más elevada a la
de la mera mecánica del lenguaje, donde el CO2 de la tontería quede bien abajo.
Podría decirse que al programador de C++, pero lo cierto es que la mayor parte
del material que en el mismo aparece ha sido impartida con éxito a postulantes a
la Tecnología de Objetos con muy distinto bagaje: desde programadores de RPG
hasta expertos en C++, pasando por analistas y diseñadores de todo tipo y con-
dición. Y es que un buen programador de C++ sobre todo lee y decide, lee y
estructura, lee y modifica, lee y vuelve a leer para, al final, codificar. En esa tónica,
el presente libro muestra arquitecturas, métodos, formas-de-hacer y técnicas de
codificación en C++ que el lector difícilmente encontrará reunidas en un solo libro.
Se explicitan, a la vez, errores frecuentes de uso del lenguaje y otros más sutiles
relacionados con decisiones de diseño que sobrepasan el ámbito de la
especificación sintáctica. Pero, con todo, no se trata de procurar recetas ni
brebajes milagrosos, sino más bien de argumentar, en continua evolución, las
posibles estrategias respecto de distintas características del lenguaje, así como
sus defectos, ventajas y carencias, para conducir de esta manera al lector hacia
soluciones razonadas de probada eficacia. Espero, pues, que el libro resulte tan
útil a los programadores de C++ como a los que quieren introducirse en el
proceloso mundo de la codificación en C++.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 12
SOBRE EL AUTOR
Ricardo Devis es, además de miembro del Comité ANSI X3J16 C++ para la
estandarización del lenguaje de programación C++, presidente nacional de
APTO2, la Asociación Española para la Promoción de las Tecnologías
Orientadas-a-Objetos; miembro con voto de ACM y ACM SigPlan; fellow de la
Institution of Analysts and Programmers (IAP); miembro con voto de IEEE e IEEE
Computer Society; miembro de The British Computer Society; miembro del Grupo
de Planificación de Métodos Orientados-a-Objetos de IEEE (Object-Oriented
Methods Planning Group), Objetos de Negocio, para la normalización y
estandarización de los métodos orientados-a-objetos; coordinador de INFOOP, la
conferencia española de OOP y C++; y miembro del IEEE CS&E Critics Circle.
Es editor del texto “INFOOP ‘93: I Congreso Español de Programación
Orientada-a-Objetos y C++” (Alicante, 1993, 84-604-6533-0), autor del libro
“Programación Orientada-a-Objetos en C++” (Editorial Paraninfo, Madrid, 1993,
320 páginas, 84-283-2056-X), y editor de “The Object Oriented Page (La Página
Orientada-a-Objetos)” en el World Wide Web para Tradewave’s Galaxy. Ricardo
Devis es el presidente y fundador de INFOPLUS, S.L., consultoría de Tecnología
de Objetos, C++ y Smalltalk, y ha estado trabajando en el área informática desde
1.982, y fuertemente focalizado en Tecnología de Objetos desde 1.987. Como
reconocida autoridad en Orientación-a-Objetos, ha formado a muchísimos
ingenieros de software en C++, Smalltalk y métodos de OORA/OOA/OOD, a la
vez que (co)dirigido multitud de proyectos orientados-a-objetos, principalmente
para grandes corporaciones y compañías institucionales.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 13
anima las oberturas de las obras musicales, cuyo antiguo objetivo era “tranquilizar
al ruidoso público y prepararlo para el comienzo de la representación”. Aparece
claro, con todo, que ésta no es la obertura de Tannhäuser, pero espero que surta
un parecido poderoso efecto.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 14
Capítulo 5 - Asignación en C++
¿Qué se esconde tras una aparentemente simple asignación en C++? En esen-
cia la voluntad de copiar un objeto en otro. Pero en C++ la complejidad se escon-
de en casi todos los recovecos del lenguaje, de forma que una simple expresión
de asignación puede generar gravísimos errores muy difíciles de depurar. Natu-
ralmente el remedio es el conocimiento exacto no sólo de la sintaxis del lenguaje,
sino también de la precisa actuación semántica que se agazapa tras aquélla.
Cuando yo planteo esto ante algún auditorio, suele preguntárseme: ¿no se puede
obviar toda esta complejidad? Mi respuesta suele ser: “Para permitirse ser es-
céptico hay que haber creído mucho antes”. Esto es, sólo simplifica quien com-
prende.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 15
Capítulo 8 - Bases de Datos Orientadas-a-Objetos
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 16
Ante tamaña impostura cabe señalar que realmente existen metodologías serias
y, de entre ellas, destaca por su originalidad, solidez y probada aplicación en la
construcción de grandes sistemas la representada por OOram y que se basa en
modelos de roles, la unidad natural de composición de sistemas software. En es-
te capítulo se dan algunas pistas y se exponen ciertas ideas que pretenden redi-
mir al lector de tanta comercialidad metódica.
“Si yo tuviera que vender mi gato (al menos a un informático) no diría que es
amable y autosuficiente y que se alimenta de ratones: más bien argüiría que
está orientado-a-objetos” (Roger King). ¡Oh, oh, hay que protegerse de la tonte-
ría! Lo que aparece en este capítulo es una cuidada y actualizada selección bi-
bliográfica (casi completamente en inglés) que abarca el grueso de las áreas de
la Tecnología de Objetos. He preferido comentar preferentemente los textos de
indiscutible calidad, pero también he incluido alguno sectorialmente interesante o
históricamente importante. Definitivamente se trata de ayudar al lector a evitar
tanto perder el tiempo como ser víctima de imposturas cometidas por autores
infames o simplemente inicuos.
GARANTÍA
Todos los errores que el lector encuentre en el presente texto son únicamente mí-
os, como lo son las carencias, deslices e inexactitudes que en el mismo se pue-
dan dar. Los comentarios, elogios, sugerencias y críticas son, cómo no, bienveni-
dos: el lector puede localizarme bien en INFOPLUS S.L., voz/fax (96) 5930017,
bien mediante correo electrónico en Internet (devis@ibm.net) o Compuser-
ve(100140.1435), mientras que la URL de mis páginas en el WWW es
“http://www.well.com/user/ritchie”.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 17
OBJETOS: HITOS, MITOS Y RITOS
1
N
o hay que subestimar la fuerza de la repetición y la estulticia de los medios
de comunicación: si una barbaridad se repite con insistencia en los luga-
res adecuados, en breve pasará a ser considerada como una realidad
incontestable. Les pondré un ejemplo: cuando se habla de objetos mucha gente
perpetra con demasiada facilidad vocablos como “paradigma”, “entorno/marco”
(por framework), etc. Pero, ¿cuál es su significado preciso? Humm, mejor no pre-
guntar. Pregunten sin miedo, empero, sobre la orientación a objetos y obtendrán:
tal, tal ... y “polimorfismo”. ¡Demonios! La traducción literal del griego, “muchas-
formas”, no genera excesivas luces, la verdad, así que la mayoría de los encues-
tados tiende a suplir sus carencias formales con su autoexaltado sentido común,
de forma que los resultados vienen a ser como la traducción al castellano de las
películas extranjeras: un dislate sin sentido. ¿Es polimórfico Felipe González?
¿Es polimórfica la plastilina? En fin, como el lector puede apreciar el panorama
es agotadoramente desolador. En lo que sigue intentaré reseñar algunas de las
supersticiones más extendidas, pero el tema en absoluto queda completamente
cubierto, así que a lo largo del libro irán apareciendo ideas parecidas que intenta-
ré sean oportunamente desenmascaradas.
Esto es lo mismo que decir que un veneno puro es más beneficioso para el cuer-
po que otro convenientemente rebajado. Cualquier mente no enferma entiende
que la idoneidad de un lenguaje, en cualquier ámbito, se basa en las facilidades
que provee para acometer las tareas a que se destina. Parece, además, pruden-
te suponer que, como bien afirma Stroustrup, “un lenguaje de propósito general ha
de soportar más de un estilo (paradigma) de programación”. Oh, naturalmente
esto no es sólo una defensa de C++ frente a Smalltalk (que lo es, por cierto), sino
una llamada al sentido común: si preguntamos a diez dentistas cuáles son los pi-
lares de la orientación-a-objetos, al menos nueve de ellos responderán “encapsu-
lación, herencia y polimorfismo”, para después añadir “y no provoca caries”. Ah,
pero esto no es cierto. La verdad es que todavía no hay consenso respecto de las
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 18
características esenciales de la orientación-a-objetos. Y no digamos de otras ca-
racterísticas: En los lenguajes orientados-a-objetos ¿todo son objetos? ¿Las cla-
ses han de ser por fuerza objetos? ¿Son los sistemas orientados-a-objetos en
realidad sistemas de objetos, para los objetos y con los objetos? ¿La herencia
múltiple es una bendición o más bien un artefacto del infierno que requiere vender
primero el alma para ser manejado con acierto? ¿El chequeo estático de tipos es
una herejía? Vaya, demasiadas incertidumbres. Así que si Smalltalk o Eiffel son
químicamente puros, C++ podría ser físicamente híbrido. Bah, ¡tonterías!
Este lugar común casa perfectamente con aquel otro que afirma “Para estudiar
C++ hay que empezar estudiando C”. En general habría que decir, con Stroustrup,
que “si vas a usar C++, estudia C++”. Desmond D’Souza acertadamente expone
que el hecho que la enseñanza de C++ no sea trivial en absoluto implica que C++
sea difícil de aprender (o al menos un cierto subconjunto de uso del lenguaje): otra
cuestión es que lo parezca, y esto se debe más a lo que se adivina no saber que
a lo que en realidad se ha aprendido (C++ es un lenguaje ciertamente prolijo). En
general el segmento de C++ que intersecta con C no posee el mismo comporta-
miento en ambos lenguajes: esto es, C enseña a codificar estructuras de código
preparadas para utilizar los recursos del lenguaje, bien distintos a los de C++; y a
la inversa. Así una buena parte de las técnicas que se enseñan en excelentes tex-
tos de C resultan inservibles o inadecuadas en C, mientras que el uso de ciertas
características del subconjunto C de C++ no es en absoluto trasladable al puro C.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 19
Resulta, pues, que en la práctica los programadores que arrostran un cierto estilo
C tienden a observar un lapso de tiempo más prolongado para el aprendizaje de
C++ que los que, sin bagaje previo de C, empiezan por C++.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 20
nos aspectos de simplificación del diseño, para terminar con cuestiones de reuti-
lización: todo un completo panorama que parece trocar a la herencia en piedra
angular. Nada más lejos de lo deseable, empero: ¿por qué distinguir la herencia,
como relación entre clases, de las relaciones de agregación, composición o uso
que también se dan en tales sistemas? ¿Por qué la herencia suele aplicarse a
clases y no a objetos/instancias? Pues porque es una componenda esencialmen-
te estática que procura una estructura lógica recorrible sobre la que basar bien la
un esquema de reutilización bien la resolución de operadores (por métodos) en
tiempo de ejecución. Pero componenda no es panacea, así que nos quedaremos
con que la herencia es una cualidad accesoria de los sistemas orientados-a-
objetos.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 21
facilidad que la finalidad de las actividades de desarrollo es la construcción de
sistemas software, y no la aplicación de métodos o técnicas en sí.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 22
ciara: sobre gustos no hay nada escrito. ¡Mentira! Hay muchísimo escrito, pero
seguramente usted no lo ha leído, cabría contestar. La solución, a mi entender, no
pasa por el refrito de métodos, ni tampoco por la solución que proponen los auto-
denominados métodos de segunda generación, abanderados por Fusion, de Co-
leman y otros, y que se basa en la utilización de un método cualquiera (OMT, Ja-
cobson, Wirfs-Brock, etc.) como información de entrada para un marco formal que
regule y distribuya adecuadamente los resultados. El modelado genérico de sis-
temas de información habría más bien de pasar, según mi opinión, por lo que se
conocen como “marcos referenciales metodológicos”: esto es, un adecuado con-
junto de herramientas metodológicas y de métodos que conforman un arsenal de
vistas aplicables de forma segmentada y no necesariamente completa sobre el
dominio de los problemas a modelar. ¿Existen tales marcos? Por supuesto, pero
esto es otra historia.
MITO 10: LO PRIMERO QUE HAY QUE HACER ES CREAR UNA BIBLIOTE-
CA DE CLASES REUTILIZABLES.
Esta frase se oye mucho en cursillos y se lee por doquier en las revistas del ramo.
La cuestión es: ¿cómo puede crearse de la nada una clase reutilizable? Esto es,
¿puede reutilizarse una clase que todavía no ha sido utilizada? ¡Naturalmente que
no! Primero hay que generar a la vez política y ambiente de reutilización en la em-
presa, de forma que cuando se creen clases con un diseño prudente tales clases
sean utilizadas por el equipo humano y la información que se desprenda de tal
uso pueda revertir en la mejora de tales clases, que volverán a ser utilizadas de
nuevo en un ciclo involutivo. Se entiende por reutilización no el uso (una clase
“Ventana” se usará por varias aplicaciones, pero tal no es reuso), sino los usos
distintos en distintos contextos. Por supuesto que el (re)uso se da tanto a nivel de
aplicativos como de las propias bibliotecas de clases, pero aquí, como ya se ex-
presó anteriormente, la herencia juega un papel usualmente desdichado: si nos
dedicamos a insertar las clases a reutilizar en jerarquías no-triviales de herencia,
cuando queremos hacer uso de una determinada clase arrastraremos con ellas
buena parte del arbol de derivación, con lo que el nivel de aprovechamiento, si
posible, dejará mucho que desear.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 23
CONTENEDORES Y PLANTILLAS
2
D
esafortunadamente el término "contenedor" no existe -si no es un armazón
metálico- como sustantivo en castellano, pero para eso está la informática:
para alterar los nervios de los puristas y modificar, de facto, para bien o
mejor para mal, el lenguaje. Así diremos, parafraseando a la Real Academia, que
un objeto “contenedor” (o de tipo contenedor) es “el que lleva o encierra objetos
dentro de sí”. De la misma manera afirmaremos que una clase “contenedora” es
una clase cuyas instancias pueden contener otras instancias. Obviaremos, pues,
expresamente, el exacto vocablo “continente”, cuya acepción como “cosa que
contiene en sí a otra” es en realidad lo que necesitamos, pues aquí la ortodoxia
del lenguaje deberá ceder frente a la costumbre establecida: la práctica totalidad
de los asistentes a cursos prefiere el neologismo, pues “continente” ofrece unas
connotaciones de “uso restrictivo de la continencia” no deseadas. Pero, ¿qué in-
terés tienen estas baratijas pseudo-lingüísticas? Pues resulta que, como el pers-
picaz lector ya habrá adivinado, continuamente estamos usando clases y objetos
contenedores; de hecho existen muchos libros que, de forma mayormente lasti-
mosa, dedican casi todo su espacio a la ejemplificación de los mismos: pilas,
bolsas, conjuntos, vectores, matrices, listas, listas enlazadas, colas, etc. Su utili-
zación es tan frecuente que la circunstancia de que, hasta hace poco, C++ no in-
cluyera clases contenedoras como parte del lenguaje indudablemente ha perjudi-
cado la extensión de su adopción. Piénsese, por ejemplo, que el esperanto es un
lenguaje bienintencionado (y recordemos aquí a Valle-Inclán, buen ilustrador de la
materia con que está empedrado el infierno) dotado de una sintaxis y pronuncia-
ción racionales que en teoría facilitarían su urgente adopción universal. Sin em-
bargo algo falla, pues es evidente que estas líneas no están en esperanto 1. Pa-
semos a otro escenario: si yo me siento bien con RPG, me he acostumbrado a él,
le he cogido cariño con el tiempo y no creo en la muerte asistida, ¿por qué demo-
nios he de cambiar a un lenguaje pretendidamente mejor, como anuncian pueda
ser C++? Y lo mismo puedo pensar si estoy cuidando de Cobol, Visual Basic, C,
Pascal, etc.: ¿No es demasiado presumida la asunción de que si no cambio es
debido a un cúmulo de incapacidades? Bueno, un lenguaje se usa en la práctica,
1
En Español (castellano <sic>) en el original.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 24
independientemente de los bienintencionados motivos que lo amparen, en tanto
que proporciona facilidades para el tipo de programación para el que se preten-
de utilizar como herramienta. En este sentido cabe destacar que C++ es -en la
actualidad- un lenguaje de extensa sintaxis y gran prolijidad semántica (sólo hay
que contar que el borrador del estándar del lenguaje consta de aproximadamente
700 páginas en formato A-4, y en él "sólo" se describe el lenguaje C++), y su con-
cepción y desarrollo se han ligado, sobre casi todo lo demás, a su practicidad
como herramienta de programación, de tal forma que si realmente se necesitaba
una facilidad ésta se añadía al acervo del lenguaje. Pero, ¿proporciona C++, por
ejemplo, las facilidades sobre contenedores que necesitamos? Pues bien, sí. Re-
sulta que ANSI X3J16 ha incorporado recientemente como parte del lenguaje una
biblioteca de plantillas de contenedores2 (STL, The Standard Template Library:
La Biblioteca Estándar de Plantillas), que en el capítulo siguiente diseccio-
naremos pedagógicamente. Pero yendo más allá descubriríamos, en palabras de
Stroustrup, que la génesis de las plantillas se basa "en el deseo de expresar la
parametrización de clases contenedoras"3, situando de esta manera en un lugar
privilegiado, por su importancia, al diseño y uso de tales contenedores. En reali-
dad C++ se convierte, así, en uno de los lenguajes mejor preparados para la ges-
tión de contenedores. Y aunque esto pueda tildarse de opinión subjetiva, a lo que
sigue me remito, pues la intención primera de este capítulo es, además de pon-
derar la importancia de los contenedores, llegar a explicitar los mecanismos, sin-
taxis, sutilezas y carencias que animan el soporte conceptual en que se apoyan
las plantillas (templates) en C++. Pero el tema es largo, muy largo, así que ¡al gra-
no!.
DISEÑO DE CONTENEDORES
Aparte de lo anteriormente expresado, los contenedores son vitales para los pro-
gramadores por una razón adicional: virtualmente todas las actuales bases de
objetos (OODBSs: Object-Oriented Database Systems) gestionan buena parte de
los accesos a objetos mediante estas estructuras. Pero a esto atenderemos más
adelante. Por ahora simplemente consideraremos las distintas estrategias que,
de forma inexorable, nos conducirán al empleo de plantillas en C++. En principio
para el diseño de contenedores en C++ podemos tener en cuenta, básicamente,
cuatro enfoques distintos: lo obvio, el preprocesado, la herencia y las plantillas.
Pero vayamos paso a paso.
2
En verdad la adición de características en C++ es tan importante, en comparación con lo mos-
trado por la mayoría de compiladores comercializados en la actualidad, que realmente sorprende.
Algún colega ha llegado a decir que C++ ha dejado de ser un lenguaje para transformarse en un
entorno. Bueno, es una idea.
3
Bjarne Stroustrup, The Design and Evolution of C++, 1994, Addison-Wesley, Página 337.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 25
LA OPCIÓN INGENUA: CUESTIÓN DE ÁMBITOS
Una primera solución elemental consiste en usar un pequeño truco para sustituir
en cada ocasión únicamente el tipo de objetos a usar por el contenedor, sin tener
que modificar la definición de éste. De esta manera, al definir la siguiente clase
en un fichero denominado "coleccio.h":
class Coleccion {
public:
bool inserta( TIPO );
Coleccion& operator|=( TIPO );
// etc., etc.
};
Si por otra parte queremos -puro capricho- una colección de decimales, podría-
mos codificar, en un ámbito diferente, así:
Lo que en ambos casos hemos hecho es, en primer lugar, asignar una sustitución
del identificador TIPO con sentido para el lenguaje, para después, usando del
preprocesador, incluir el código de definición de la clase colección (mediante la
directiva "#include"). Seguidamente se define una variable (objeto) del tipo Co-
leccion (que en realidad, en ese momento, no es una clase colección genérica,
sino que es ya, de hecho, una colección de enteros en el primer caso y otra de
doubles en el segundo). Por último se llama a una función miembro de la clase
con el argumento adecuado en cada caso. ¡Ea, parece que esto funciona!, podría
aquí exclamar el incauto lector. Pero no, desafortunadamente ¡esto no funciona!
En primer lugar la clase Coleccion depende, para su compilación, de una defini-
ción exterior a la misma, de forma que se genera una necesidad de secuenciali-
dad bien difícil de documentar. Por otro lado resulta que si compilamos las líneas:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 26
Coleccion unaColeccionDeDecimales;
double unDecimal = 1.23456
unaColeccionDeDecimales.inserta( unDecimal );
#ifndef coleccio_h
#define coleccio_h
// definición de clase
#endif /* coleccio_h */
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 27
// como yuxtaposición de dos identificadores dados.
4
#define concatenar(a,b) a##b
// seguidamente se codifica la macroinstrucción que
// generará un nombre específico para cada colección.
#define Coleccion(tipo) concatenar(tipo,Coleccion)
// y aquí viene la definición "genérica" de nuestra
// clase contenedora.
#define declara(Coleccion,tipo) \
class Coleccion(tipo) { \
public: \
Coleccion(tipo)(); \
Coleccion(tipo)(const Coleccion(tipo)&); \
bool inserta(tipo); \
// etc., etc. \
};
#include <ppcollec.h>
declara(Coleccion,int)
Coleccion(int) miColeccionDeEnteros;
class intColeccion {
public:
intColeccion();
intColeccion(const intColeccion&);
bool inserta(int);
// etc., etc.
5
};
intColeccion miColeccionDeEnteros;
declara(Coleccion,double)
4
Este código para concatenar identificadores no es, como resulta fácil suponer, portable entre
sistemas, de tal manera que también se usan lindezas como las siguientes:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 28
Coleccion(double) miColeccionDeDoubles;
miColeccionDeDoubles.inserta( 1.1135917 );
declara(Coleccion,char*)
intentaría generar el código de una clase con un identificador tal que así:
char*Coleccion
pero lo que aquí estamos haciendo es ... suplir el trabajo que usualmente el len-
guaje hace por nosotros, reconociendo a la vez la incapacidad del preprocesador
respecto de los tipos y su alejamiento del lenguaje. Una de las mejores caracterís-
ticas de C++ es su fuerte chequeo de tipos que, en el caso de las macrosustitu-
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 29
ciones, se pierde como se perdió Cuba: de forma irremediable. Húyase, pues,
del preprocesador siempre que sea posible ("Me gustaría ver abolido el Cpp"6,
Stroustrup dixit). Pero, entonces, ¿qué hacer respecto de los contenedores gené-
ricos? Bueno, la mayoría de bibliotecas de C++ se basan en un uso más o menos
intensivo de la herencia mediante la derivación de clases. ¿Qué tal si aplicamos
la derivación y los mecanismos de conversión, implícitos o no, de C++ para pro-
curar la genericidad deseada? Al grano.
class Coleccion {
public:
bool inserta( Objeto* );
// etc., etc.
};
Coleccion miBiblioteca;
Libro* miPreferido = new Libro( "The Devil's Dictionary" );
miBiblioteca.inserta( miPreferido );
6
Cpp es el acrónimo de "C Preprocessor" -o sea, "Preprocesador de C"-, lo que indica suficiente-
mente su carácter básico de herencia de C adquirida por C++. Como en las malas herencia de la
vida jurídica real, no hay más remedio que resignarse: se trata de una deuda.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 30
forma en un puntero a Objeto, y todo funciona como en los cuentos de Perrault.
Bien, sigamos. Pero antes una consideración adicional: ¿y si deseáramos man-
tener una colección de bibliotecas -o sea, una colección de colecciones? Pues no
tendríamos más que volver a aplicar el esquema derivativo. Esto es, necesitaría-
mos que la misma clase Coleccion derivara también, directa o indirectamente, de
la clase Objeto:
Coleccion misBibliotecas;
Coleccion* miBibliotecaErotica = new Coleccion;
misBibliotecas.inserta( miBibliotecaErotica );
Por otro lado ahora podemos mantener perfectamente en el mismo ámbito varias
colecciones conteniendo tipos distintos, pues en realidad se tratará de objetos
del mismo tipo: una colección de enteros es exactamente del mismo tipo que otra
de caracteres (ambas son instanciaciones de la clase Coleccion). Resulta así que
todas nuestras clases derivarán de Objeto: o sea todas las instancias que mane-
jemos serán Objetos (no olvidemos que la derivación pública en C++ representa
relaciones "ES-UN"). Y aquí nos enfrentamos con el primer problema. ¿Qué pasa
si codificamos lo siguiente?
Coleccion misEnteros;
int* pEntero = 7;
misEnteros.inserta( pEntero );
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 31
bien encapsulamos tales tipos en sendas clases derivadas, éstas sí, de la clase
Objeto, de la forma:
¿Cuál es la mejor opción? Bueno, piénsese que codificar una clase simuladora
de un tipo predefinido no es un ejercicio trivial, y habría que hacerlo para cada uno
de los tipos definidos en el sistema: float, long, char, etc. En contrapartida, si nos
hacemos con el conjunto de tales clases en el futuro podremos utilizarlos sin codi-
ficación adicional en cualquiera de los contenedores que manejen Objetos, pero a
costa de obligar al programador a no usar los tipos predefinidos, de tal manera
que se influye en el posible código ya existente cuando se intentan usar estos
contenedores, so pena de usar una mixtura de operadores de conversión y de
sobrecarga, algo que casi nunca funciona totalmente de la forma deseada. La
opción de la sobrecarga de las funciones miembros es, por otro lado, menos in-
trusiva, pero obliga a la codificación repetitiva de las funciones en cada nueva
clase contenedora, de forma que cada nueva función miembro que se adicione y
contenga punteros a Objeto en su signatura deberá ser replicada para cada uno
de los tipos predefinidos. Si suponemos una jerarquía estable de contenedores
esta sería la opción menos desventajosa: de hecho es la elegida por la mayoría
de bibliotecas comerciales.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 32
cualquier caso, la biblioteca comercial no está preparada para conjuntarse con la
nuestra. Y además habría que modificar el código de la biblioteca comercial: algo
calificado como anatema, pues habría que repetir tales modificaciones (y volver a
comprobar su repercusión) en cada versión de la misma. Y, con todo, suponemos
que disponemos del código fuente de la biblioteca para poder modificar las cla-
ses, algo que no siempre ocurre.
ColeccionOrdenada miBolsa;
Persona analista( "Ricardo Lara" );
ElementoQuimico analito( "Sodio", "Na" );
miBolsa.inserta( analito );
miBolsa.inserta( analista );
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 33
El lector pensará que si el último elemento es una Persona la línea funcionará per-
fectamente. Pues no. Resulta que la función miembro "ultimo()" devuelve un punte-
ro a Objeto (en realidad un puntero a la porción de Objeto contenida en el objeto
accedido), y sobre este puntero se aplica la función "edad()", pero la clase Objeto
no tiene definida tal función, por lo que el compilador arrojará un lógico error. Ne-
cesitamos, pues, un cast que troque el puntero a Objeto en un puntero a nuestra
clase deseada (esta es, Persona), y explicitaré la sintaxis con profusión de parén-
tesis:
En este caso Persona derivaría "virtualmente" de Objeto, y entonces ... ¡la línea
con el cast originaría un error en compilación!, pues resulta que el lenguaje no
permite un "downcasting" de una clase base virtual a una clase derivada de ésta
(y el lector que dude de esta afirmación debería urgentemente consultar el ARM).
La biblioteca NIH (cuya referencia encontrará más adelante el lector) dispone, sin
embargo, de una triquiñuela para salvar esta imposibilidad, facilitando un conjunto
de funciones estáticas con identificador "castdown(...)" que, mediante macrosubs-
tituciones del preprocesador, se generan automáticamente para cada clase del
sistema. Pero, como ya sabe el lector, las soluciones del cpp no nos gustan, así
que ... ¡al saco!
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 34
que el cast aparece inevitable 7. Para poder aplicar una cierta validación de tipos
necesitaríamos un contenedor como el siguiente:
Lo que ocurre es que de esta manera ... ¡perdemos por completo la genericidad
objeto de las presentes disquisiciones! Podríamos, por otra parte, intentar la si-
guiente desgraciada triquiñuela, usando del mecanismo de identificación de tipos
en tiempo de ejecución (el esquema se ha simplificado de forma grosera para
evitar perdernos en profundidades que ahora mismo resultan un poco lejanas,
sobre todo teniendo en cuenta que la clase "typeid" está pendiente todavía de
definición en el estándar del lenguaje 8):
#include <typeinfo.h>
7
A no ser que creemos lo que se denomina una "Flat Base Class", o sea, una clase base dotada
de un abrumador número de funciones virtuales puras, comprehensivas de toda la posible fun-
cionalidad de sus clases derivadas, presentes y futuras. Esto suele dar lugar, en jerarquías poco
meditadas, a verdaderos pastiches formales.
8
El ejemplo siguiente se basa en lo que se denomina RTTI (Run-Time Type Identification:
Identificación de Tipos en Tiempo de Ejecución), y a pesar de la actual indefinición del estándar,
ya se pueden encontrar implementaciones concretas en compiladores, como por ejemplo en
Borland C++ 4.XX.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 35
}
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 36
Bueno, lo estamos pintando muy negro, pero la verdad es que los problemas del
enfoque derivativo no acaban aquí: pasemos a un nuevo capítulo de molestias.
void afiliate()
{
Coleccion partidoPolitico;
partidoPolitico.inserta(new Persona("Juan Nadie"));
// aquí, por terminar el ámbito de la función
// se destruye el objeto partidoPolitico
}
Vemos que se destruye el contenedor, pero ¿qué pasa con el objeto Persona que
hemos insertado? Pues que, al serle asignada memoria del almacenamiento li-
bre, queda sin destruir ocupando memoria útil del sistema, y además sin posibili-
dad evidente de ser accedido. Estamos suponiendo, naturalmente, que el conte-
nedor no suprime al destruirse los objetos que contiene, porque si así fuera nos
veríamos abocados a errores aún más peligrosos:
void afiliateYMuere()
{
Persona* incauto = new Persona( "Pepe Pérez" );
Coleccion* partidoMinimalista = new Coleccion;
partidoMinimalista->inserta( incauto );
Coleccion* partidoNeologista = new Coleccion;
partidoNeologista->inserta( incauto );
// se ejecuta aquí algún proceso irregular
// y se disuelve el partido Neologista
// y con éste se "disuelven" también todos
// sus afiliados, incluido nuestro "incauto"
delete partidoNeologista;
// seguidamente la caida del partido Neologista
// arrastra a la disolución al partido Minimalista
// (temas de empatía política, ya saben)
delete partidoMinimalista; // ¡el desastre!
}
9
CRUD es el acrónimo de "Create, Read, Update & Delete" (Crear, Leer, Actualizar y Borrar) y se
refiere a las operaciones más usuales que pueden aplicarse a objetos.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 37
¿Cuál es el problema aquí? Pues que al destruirse el partido Minimalista intenta
destruir a todos sus miembros, pero resulta que el objeto al que apunta el identifi-
cador "incauto" ya ha sido destruido anteriormente, por lo que el resultado de
aplicar el operador "delete" a tal puntero es impredecible. Naturalmente obten-
dríamos el mismo desastroso resultado si destruyéramos "a mano" los objetos
contenidos. Esta es, de hecho, la poderosa razón por la que los contenedores de
la mayoría de bibliotecas comerciales no destruyen a sus objetos contenidos
cuando se destruyen ellos mismos. Otra solución muy socorrida es proveer a la
clase Objeto de las siguientes funciones:
class Objeto {
public:
// copia superficial o referencial de objetos
virtual Objeto* shallowCopy();
// copia profunda o estructural de objetos
Objeto* deepCopy();
// convierte una deepCopy en una shallowCopy
virtual void deepenShallowCopy();
// etc., etc., como siempre
};
Pero los peligros de los punteros no acaban aquí. Consideren, si no, el siguiente
código:
Coleccion partidoContrapopular;
void afiliateYVeras()
{
Persona personaDePaso( "Eutimio" );
// atención: seguidamente se inserta en la colección
// un puntero a un objeto de ámbito local.
partidoContrapopular.inserta( &personaDePaso );
// aquí se acaba el ámbito de la función y se
// destruye el objeto automático "personaDePaso"
}
Nos encontramos con una colección que contiene, como en el caso anterior, un
puntero a un objeto que ya no existe. Cualquier operación sobre la colección que
afecte a tal puntero originará ... cualquier cosa, usualmente muy desagradable.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 38
Vemos, pues, que se dan muchos problemas pero, demonios, no todo es tan ma-
lo en el esquema de diseño de contenedores por derivación. Después de todo es
un enfoque que funciona en Smalltalk <sic> y en las jerarquías de clases C++
consideradas como un "idioma" o "patrón" (pattern) Smalltalk, casi todas ellas
descendientes de la biblioteca NIH de Keith Gorlen et al.10, aunque en ésta el me-
canismo de identificación de tipos recae, de una forma muy propia de Smalltalk,
en una clase denominada Class. Además estas jerarquías cósmicas (pues así se
denominan las jerarquías de clases que tienen una única clase base) son muy
prácticas cuando se trata de obtener una adecuada granulación de objetos en
base a sus relaciones de herencia. Vamos a intentar explicarlo con un ejemplo:
supongamos la siguiente jerarquía (que respeta escrupulosamente la directriz ES-
UN, aunque de estas cuitas ya hablaremos más adelante):
Objeto
Bien
BienMueble
Prenda
Pulsera
class Objeto {
public:
Objeto() { extent.inserta( this ); }
~Objeto() { extent.extrae( this ); }
private:
static Coleccion extent;
// etc., etc.
};
10
La biblioteca NIH es, para gozo del lector, de dominio público y puede encontrarse en la may-
oría de servicios on-line: Internet, BIX, Compuserve, etc. Aunque yo, personalmente, no prescin-
diría del libro en que se explicitan las decisiones de diseño de tal biblioteca, un clásico ya de la
programación en C++: Data Abstraction and Object-Oriented Programming in C++, Gorlen, Orlow
& Plexico, 1990, John Wiley & Sons, 0-471-92346-X.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 39
// aquí se repite el mismo esquema para todas las
// clases de la jerarquía, hasta llegar a la terminal
De esta manera cada vez que creemos un nuevo objeto de alguna de estas cla-
ses automáticamente se insertará en la colección estática (única para todos los
objetos de la clase) correspondiente a su tipo (con el nombre "CLASE::extent" y
accesible a través de las correspondientes funciones miembros públicas estáti-
cas, que aquí se han obviado). Así, por ejemplo, la línea
delete miPulseraDeCompromiso;
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 40
al entrar en acción los destructores de las clases bases (en orden inverso al de
construcción, como el voraz lector ya sabe), se extraerá tal objeto de cada una de
las colecciones. Un corolario lógico es que la colección estática de la clase Obje-
to contendrá en cada momento todas las instancias de clases disponibles en
nuestra aplicación. De cualquier forma, y como ya se ha dicho, este es un esque-
ma particularmente poco eficiente, así que sólo se usará cuando el polimorfismo
que proporciona sea real y positivamente necesario (lástima que no existan toda-
vía mecanismos ni métricas orientadas-a-objetos maduras que permitan calibrar
tal necesidad).
class Cliente {
// descripción de clase
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 41
ción de un nuevo identificador, de forma que no se mantiene la integridad referen-
cial, que debería aquí ser expresamente codificada (o sea: ¡problemas!).
Claro que algo se puede arreglar -nunca se arregla todo, como el desencantado
lector ya puede intuir- a costa de complicar un tanto -o mejor un mucho- el esque-
ma de derivación y de relaciones entre clases. Se trata, en esencia, de aplicar a
nuestros contenedores un patrón conocido como de clases "Sobre/Carta" monta-
do sobre un mecanismo virtual que permita la inserción y extracción de objetos en
contenedores sin tener que realizar "casts" expresos. Este patrón está suficien-
temente explicitado en el libro de Coplien11, y junto con el patrón o idioma de
"Ejemplares" proporciona soporte para una parametrización en tiempo de ejecu-
ción de nuestros contenedores. Pero quizás este modelado sobrepase el tono
resueltamente elemental del presente capítulo. Además, ¿qué demonios son "pa-
trones"? En pocas palabras: se trata de construcciones idiomáticas con persona-
lidad y estructuración propias, que conllevan particulares formas de codificar y
modelar los problemas12. Pero esto, aparte de resultar muy extenso, en realidad
es relativamente nuevo (de hecho existe en Internet un grupo de discusión de
patrones via correo electrónico al que se puede apuntar cualquier interesado), así
que volvamos a nuestras cuitas anteriores: ¿puede solucionar la conjunción de
herencia múltiple y el uso de patrones nuestros problemas de parametrización de
contenedores? Sí en buena medida, pero básicamente a costa de la eficiencia y
del chequeo estático de tipos, aparte de que se genera la necesidad de mantener
un esquema derivativo no trivial en el que hay que insertar cada nueva clase (esto
es, se hace necesario un "administrador" de la parametrización). Pero la cosa no
acaba aquí.
ITERADORES
class Iterador {
public:
Iterador( Coleccion* coleccion ) :
11
Advanced C++ Programming Styles and Idioms, James O. Coplien, 1992, Addison-Wesley, 0-
201-54855-0.
12
El lector inquieto puede leer el excelente texto “Design Patterns: Elements of Reusable Object-
Oriented Software”, de Gamma, Helm, Johnson & Vlissides, 1994, Addison-Wesley, 0-201-63361-
2.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 42
contenedor( coleccion );
void rebobina();
Objeto* operator();
Objeto* operator++();
private:
Coleccion* contenedor;
Objeto* objetoSeleccionado;
// etc., etc.
};
¿Qué es una plantilla? En primer lugar la traducción, desafortunada o no, del tér-
mino "template", actualmente parte del lenguaje C++. Otros autores prefieren "ge-
nérico", pero personalmente pienso que esto constituye un sobreabuso del voca-
blo (adjetivo, al fin y al cabo). Se trata, en definitiva, de un concepto asociado al
de "parametrización de tipos", de manera que se usarán "plantillas" para imple-
mentar en C++ estructuras de datos (objetos contenedores, de forma más explíci-
ta) y algoritmos independientes en buena medida (aunque no absolutamente) de
los tipos de objetos sobre los que operan o se aplican.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 43
En resumen, y dado que en este capítulo no examinaremos la sintaxis de las plan-
tillas, ahora podríamos codificar una colección genérica de la siguiente forma:
donde "T" ha de ser sustituido por el tipo de objeto (clase o predefinido) que de-
seamos manejar en nuestra colección (y obviaremos momentáneamente el espi-
noso asunto de los punteros y los objetos en plantillas). Pero esta sustitución se
produce mediante la "instanciación" de la plantilla en una línea como la siguiente:
funciona sin cast alguno, pues la función miembro devuelve directamente un pun-
tero a Politico (en este caso), y no un puntero a una clase base (cual era el caso
con Objeto en el enfoque anterior) que necesitaría de un "downcast" para poder
acceder a una función miembro de la clase adecuada.
Bien: hemos visto, aun muy brevemente, que el enfoque de plantillas soluciona los
problemas planteados. ¿Cuál es el siguiente paso? Parece que habría que usar
la sintaxis de plantillas para codificar las clases contenedoras que necesitemos.
Pero, ¿es lógico que cada programador haya de enfrentarse individualmente al
no-trivial problema de codificar los mismos contenedores? O sea, ¿hay que in-
ventar la rueda cada vez? ¡Naturalmente que no! El lector puede estar seguro que
existen multitud de bibliotecas comerciales con particulares implementaciones de
contenedores mediante plantillas (Rogue Wave, Borland, etc.). Pero, ¿cuál elegir?
¡Ninguna de ellas! Resulta que, como ya se anunció al principio de este capítulo,
C++ ya posee su propia biblioteca estándar de plantillas (STL), desarrollada por
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 44
Alex Stepanov en los laboratorios HP y puesta por Hewlett Packard en el dominio
público, liberando todas las licencias a ella afectas. Cualquier interesado puede
acceder al código fuente completo de la STL via ftp anónimo o vía e-mail, aunque
el fichero también puede encontrarse en distintos servicios electrónicos, como
por ejemplo en el forum de Microsoft España en Compuserve. La STL supone un
trabajo de desarrollo de unos diez años, y el código C++ es de una calidad que
impresiona, con dos particularidades notables: en absoluto se usa de la herencia
en esta biblioteca y el tratamiento algorítmico recuerda las mejores bibliotecas
fortran. Pero el uso de la STL y su integración en los esquemas de programación
en C++ es asunto prolijo que necesita de un capítulo exclusivo: el siguiente.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 45
C++ STL
3
L
a STL, acrónimo de Standard Template Library (Biblioteca Estándar de
Plantillas), es, según Stroustrup, “un entorno-marco, formado por contene-
dores, iteradores y algoritmos, que resulta grande, sistemático, limpio,
formalmente completo, comprehensible, elegante y eficiente”. Y además codifi-
cado en C++. Tantos elogios los recibe una biblioteca-marco de clases derivada
de los trabajos de Dave Musser y Alex Stepanov en Hewlett Packard, cuyo propó-
sito primero fue la producción de una estructura de código que permitiera la crea-
ción, en su seno, de algoritmos reutilizables. Tras un proceso iterativo de acopla-
miento a Scheme, Ada y finalmente C++, en Noviembre de 1.993 el propio Ste-
panov junto con Meng Lee presentaron al Comité de Estandarización ANSI/ISO
X3J16 la biblioteca, que fue aceptada como parte de la Biblioteca Estándar de
C++ en julio de 1.994 e incorporada al borrador del estándar del lenguaje.
Bien, bien: parece que la STL es fabulosa, pero, tras esta exposición histórica,
¿para qué demonios sirve? Durante mucho tiempo se ha achacado a C++ la ca-
rencia de estructuras de datos con funcionalidad suficiente para procurar las ba-
ses de una deseada genericidad en la codificación. Y la STL proporciona justa-
mente eso: un conjunto de estructuras de datos y de algoritmos que operan sobre
aquéllas. Pero sobre todo procura, según Koenig, “un entorno conceptual que fa-
cilita a los usuarios la adición de sus propios algoritmos y estructuras de datos”
de una forma ciertamente genérica: los nuevos algoritmos funcionarán con todas
las estructuras de datos (contenedores) existentes, a la vez que sobre las nuevas
estructuras de datos se podrán aplicar todos los algoritmos existentes. La STL
viene, pues, a cubrir un hueco mal tapado hasta ahora por macros y clases no-
estandarizadas, propias o de bibliotecas comerciales, usualmente poco efecti-
vas, con un uso inadecuado de la herencia, con escaso o nulo chequeo de tipos,
tan sustancial a C++.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 46
llan), sino más bien comprehensivo e iniciático. No se detallará, tampoco, la sin-
taxis y uso de las plantillas en C++. En definitiva mi intención es transmitir al lector
el “espíritu” de la STL y la animosidad suficiente para que pueda usarla con efec-
tividad, esperando, entre otras cosas, no vuelva a usar otra clase “vector” que la
provista por esta biblioteca13. A ello.
ESTRUCTURA DE LA BIBLIOTECA
Esto es, el núcleo de la STL son los algoritmos, que utilizan iteradores para acce-
der a contenedores. Como bien explican Stepanov y Lee, si quisiéramos codificar
‘c’ contenedores para ‘t’ tipos de datos accesibles mediante ‘a’ algoritmos, debe-
ríamos contemplar ‘c*t*a’ combinaciones. Debido a la parametrización de tipos
que procuran las plantillas, la STL sólo necesitaría ‘c*a’ combinaciones, que fi-
nalmente se reducen a ‘a+c’ por la reutilización de los algoritmos en diferentes
contenedores.
Adicionalmente los componentes de la STL son al menos tan eficientes como los
codificados a-mano (debido al uso del “inlining” y el prácticamente nulo uso de la
derivación); proveen un fuerte chequeo de tipos (mediante el uso de plantillas);
sus iteradores son generalizaciones de los punteros (pudiendo usarse donde ta-
les aparecen, singularmente en los arrays de C); y permiten el uso, sobre todo en
13
Mucha gente piensa, como Prémontal, que las bibliotecas son como las farmacias: muchos
venenos y pocos remedios. Así que prefieren las soluciones caseras a-mano. El mercado mismo
evidencia su error.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 47
algoritmos, de funciones encapsuladas en objetos (también como el uso de las
típicas funciones C/C++).
CONTENEDORES
que a su vez encierran las siguientes colecciones concretas, todas ellas codifica-
das en C++ mediante plantillas y con las subdisiviones que se indican:
ADAPTADORES
stack pila, en la que el primer elemento en entrar es el último en salir.
queue cola, en la que el primer elemento en entrar es el primero en salir.
priority_queue cola que mantiene sus elementos en orden.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 48
Descripción Prototipo de las funciones miembros T
Constructor list() D
Constructor Copia list( const list<T>& lista ) C
Destructor ~list() D
Tamaño máximo size_type max_size() const T
Tamaño size_type size() const T
Intercambio void swap( list<T>& lista ) A
Asignación list<T>& operator=( const list<T>& lista ) A
Igualdad bool operator==( const list<T>& lista ) const C
Comparación orden bool operator<( const list<T>& lista ) const C
STL provee otras funciones de comparación (C) que se derivan (en sentido figu-
rado) de los operadores == y <, a saber: <=, >=, > y !=. En realidad STL provee
tales operadores adicionales para cualquier objeto, supuesta la existencia de los
dos primeros.
Los adaptadores son, en esencia, plantillas que procuran un interfaz especial pa-
ra los otros tipos de contenedores. Así cualquier contenedor que soporte las ope-
raciones de push_back y pop_back (como vector, list y queue) puede ser usado para
instanciar “stack”. Si se añade la operación front , entonces se podrá instanciar una
“priority_queue”. Por fin “queue” podrá instanciarse con contenedores que soporten
front , back, push_back y pop_front . Como el lector fácilmente habrá adivinado, los
adaptadores “adaptan” o “adecúan” un determinado contenedor para que adopte
un nuevo comportamiento, restringiendo ciertas características y cambiando
otras.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 49
“Bien, bien -exclamará el impaciente lector- Todo esto está muy bien, pero yo ya
uso los contenedores de la biblioteca de clases X (o de una propia) que me van
estupendamente”. ¡Estupendo! Pero el énfasis de la STL no está en los contene-
dores, sino en los algoritmos (que veremos poco después). De cualquier manera
la genericidad que otorgan las plantillas es difícilmente superable por una biblio-
teca comercial, y la efectividad de los contenedores de la STL es, por otro lado,
virtualmente inmejorable. Pero de poco sirve una mera estructura sin las
herramientas que permitan accederla, revisar y modificar tanto su propia
configuración como los ítems que contenga. Y aquí aparecen los iteradores.
ITERADORES
Según Andrew Koenig, “un iterador es algo que permite un conjunto de operacio-
nes en una estructura de datos sin decir nada sobre la naturaleza de tal estructu-
ra”. Esta definición resulta especialmente relevante dentro del entorno que pro-
porciona la STL pues ésta, centrada en los algoritmos, se encuentra con la dificul-
tad de aplicar éstos directamente en los contenedores o estructuras genéricas de
datos: algunos algoritmos funcionan con ciertas estructuras; otros no. Con la in-
troducción de los iteradores se genera un nuevo nivel de indirección que permite,
en su calidad de mediador, el perfecto entendimiento entre contenedores y algo-
ritmos. Los iteradores, así, saben poco de algoritmos o de contenedores, de for-
ma que son grandemente independientes de ambos. De esta manera los algorit-
mos se expresarán en términos de iteradores, de manera que las estructuras de
datos accedidas, en otro nivel, por los iteradores, serán independientes de los
primeros. De hecho esto es precisamente lo que diferencia a la STL de otras bi-
bliotecas de clases.
• InputIterator (iterador de entrada/lectura): lee un solo ítem cada vez, en una úni-
ca dirección, y su desreferenciación (*iterator) sólo podrá ser usada a la dere-
cha de una asignación: esto es, la desreferenciación devuelve un elemento
constante. Un puntero de C operando sobre un array predefinido es un iterador
de lectura (veremos que también es de escritura, pero las dos condiciones in-
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 50
cluyen la establecida). Así, por ejemplo, si consideramos el algoritmo
“max_element ”, con signatura:
template<class InputIterator>
InputIterator max_element(
// iterador en el primer ítem del rango elegido
InputIterator primero_,
// iterador tras el último ítem del rango elegido
InputIterator ultimo_ )
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 51
OutputIterator primero_, // apunta al primer ítem del
rango
Size n_, // limita el rango: primero_ + n_
const T& valor_ ) // valor de relleno
vector<int> quiniela( 15 );
fill_n( quiniela.begin(), quiniela.size(), 1 );
// el iterador de escritura que devuelve la función “begin()”
// se utiliza para escribir el valor ‘1’ en el ítem apuntado,
// y quiniela queda como { 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 }
y cuyo sentido es intercambiar los elementos apuntados por los iteradores (ca-
da iterador lee el ítem al que apunta, pero también lo escribe):
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 52
y cuyo propósito es la copia de los elementos comprendidos en el rango [prime-
ro_, ultimo) en otro rango cuyo final está indicado por el iterador ‘resultado_’ (que
apunta a la posición tras el último elemento del rango). O sea, para copiar se
da la posición final del destino (como si se copiara “hacia atrás”), copiando
mediante el ‘operator= ’. Lo que se devuelve es otro iterador del mismo tipo que
‘resultado_’ pero apuntando al primer elemento del nuevo rango:
vector<Politico> listaPartidoD;
vector<Politico> listaPartidoI;
// se rellenan ambas listas
copy_backward( ++listaPartidoD.begin(),
--listaPartidoD.end(),
--listaPartidoI.end() );
// ahora ambas listas son iguales menos el
// primer y último elemento: la sin par realidad.
template<class RandomAccessIterator>
void partial_sort (
RandomAccessIterator primero_,
RandomAccessIterator medio_,
RandomAccessIterator final_ )
int array[ 7 ] = { 6, 4, 2, 1, 5, 3, 7 };
partial_sort( array, array + 4, array + 7 );
// resultado: { 1, 2, 3, 4, 7, 5, 6 }
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 53
Iteradores Todos Input Output Bidirectional Random Access
Operaciones ++i *i (const) *i --i i += n
permitidas i++ i == j i=j i-- i -= n
i != j i+n
i-n
i[ n ]
input
forward bidirectional random access
output
de forma que donde se espera un cierto iterador, puede aplicarse cualquier itera-
dor a su derecha. Y, claro, aquí el lector podría exclamar: “¡Una jerarquía de
herencia de iteradores!”. Pues no, irredento lector: nada de jerarquías: aunque
parezca lo contrario, la clase del iterador bidirectional no “deriva” de la clase del
iterador forward, como no lo hacen tampoco las demás. Andrew Koenig acerta-
damente afirma que habría que pensar en las relaciones entre iteradores como
“herencia conceptual”, pues un iterador es una familia de tipos relacionados en
razón de formas que no son directamente expresables en C++.
Además de los iteradores expuestos, la STL provee otros igualmente útiles: is-
tream_iterator y ostream_iterator (que operan como cin y cout respecto de streams
C++ de entrada y salida, respectivamente), reverse_bidirectional_iterator y rever-
se_iterator (que iteran hacia atrás), insert_iterator (inserta en la posición a que apun-
ta), back_insert_iterator y front_insert_iterator (sólo insertan al final y al principio de un
contenedor, respectivamente), etc.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 54
donde se explicita algo evidente: únicamente las “Colecciones de Primera Clase”
(esto es, contenedores secuenciales y asociativos) pueden ser accedidas por
iteradores. La ligazón entre contenedores, iteradores y algoritmos se produce así:
la descripción de los contenedores incluye la categoría de los tipos de iteradores
que proveen, mientras que los algoritmos genéricos incluyen (en su prototipo) la
categoría de iteradores con que trabajan. Así, para evitarle al usuario la consulta o
aprendizaje de tablas como la anterior, cada contenedor define una serie ade-
cuada de typedefs, de forma que la notación contenedor<class T>::iterator enmascara
los tipos:
list<Politico> cuadrilla;
// aquí se rellena la lista, y seguidamente
// se define un iterador del tipo adecuado
// (que en este caso será bidireccional)
list<Politico>::const_iterator i = cuadrilla.begin();
// y ahora se utiliza el iterador
for ( i; i != cuadrilla.end(); i++ )
// supondremos que la clase Politico sobrecarga
// el operador de inserción (y esto no parece des-
// cabellado, pues los políticos lo sobrecargan todo).
cout << *i << “\n”; //imprime la lista
// Y ahora al revés
list<Politico>::const_reverse_iterator ri;
// y en lo siguiente aparecen dos nuevas funciones marcadas
// por una r (reverse) inicial: rbegin() devuelve un iterador
// posicionado en el ultimo ítem, mientras que rend() devuelve
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 55
// un iterador posicionado inmediatamente antes del primer ítem.
// Su uso es evidente para iteradores que operan al revés.
for ( ri = cuadrilla.rbegin(); ri != cuadrilla.rend(); ri++ )
cout << *i << “\n”;
dejando que los typedefs hagan el trabajo de elección del iterador correcto por no-
sotros. ¿No es sencillamente fantástico?
ALGORITMOS
Algoritmo Descripción
for_each aplica una función a cada uno de los objetos en un rango dado
find localiza un ítem en una secuencia
adjacent_find localiza la secuencia consecutiva en un rango dado
find_if halla el elemento que satisface un predicado en un rango dado
count cuenta las ocurrencias de un valor en un rango determinado
count_if cuenta los elementos que satisfacen un predicado en un rango dado
search encuentra una secuencia contenida en otra
binary_search localiza un elemento perteneciente a una secuencia ordenada
fill rellena un determinado rango con un valor
fill_n rellena los n primeros elementos con un valor dado
min devuelve el minimo de dos elementos
min_element devuelve el minimo elemento dentro de un rango
max devuelve el maximo de dos elementos
max_element devuelve el máximo elemento dentro de un rango
sort ordena los elementos en un rango dado
partial_sort ordena los elementos de un rango hasta el término n-simo
set_difference genera un conjunto con la diferencia de las colecciones A y B (A-B)
set_intersection genera un conjunto con los elementos comunes a dos secuencias
set_union genera un conjunto con los elementos pertenecientes a AUB
merge integra dos listas ordenadas en una única lista ordenada
+++ +++
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 56
Pero veamos un ejemplo de un algoritmo eminentemente práctico: “for_each”, que
con signatura
vector<Politico> listaNegra;
void detecta( const Politico& politico ) {
if ( politico.piensa() )
listNegra.pushBack( politico );
}
list<Politico> lista;
// se rellena convenientemente la lista
for_each( ++lista.begin(), lista.end(), detecta );
¿FUNCIONES-OBJETO U OBJETOS-FUNCIONES?
Muchos de los algoritmos usan de funciones que son aplicadas a los elementos
de los contenedores por medio de iteradores. Tales funciones pueden ser bien
punteros a funciones normales de C/C++ o una generalización de éstas: funcio-
nes encapsuladas en objetos. Los objetos-funciones son instancias de clases con
un comportamiento definido por sus funciones miembros públicas, pero cuya sin-
taxis simula la de las funciones C mediante la sobrecarga del operador (); pero
además los objetos-funciones incorporan datos miembros y operan como el resto
de los objetos: se crean, se modifican y se destruyen. En general los objetos-
funciones, o simplemente funciones respecto de la STL, pueden dividirse en una-
rios o binarios, dependiendo si toman uno o dos argumentos, pero también, en
función de su propósito, en
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 57
Funciones Genera- sin funcionalidad predefinida, se aplican sobre elementos de contenedo-
les res
Pero veamos un ejemplo de cada uno, empezando por los predicados. Si consi-
deramos el algoritmo “find_if” con prototipo:
que devuelve un iterador apuntando al primer elemento del contenedor que cum-
ple el predicado (esto es, la función de tipo Predicate aplicada a ese elemento
devuelve “true”):
template<class T>
const T& min( const T& a_, const T& b_, Compare comparador_ );
Por último examinemos las funciones generales, para lo que trataremos con el
algoritmo “count_if” con prototipo:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 58
template<class InputIterator, class Predicate, class Size>
void count_if (
InputIterator primero_,
InputIterator ultimo_,
Predicate predicado_,
Size& n_ );
template<class T>
struct logical_not : unary_function<T, bool> {
// ...
bool operator()( const T& x_ ) const {
return !x_;
}
};
vector numeros[ 8 ] = { 0, 1, 0, 0, 1, 1, 1, 1 };
int n = 0;
count_if( numeros, numeros + 2, logical_not<int>(), n );
cout << n; // imprime ‘2’
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 59
Size& n_ // el contador a incrementar por cada ocurren-
cia
}
O sea, este algoritmo recorre una coleccion o contenedor desde el primer ele-
mento hasta pasado el último, y compara cada ítem encontrado con “value” apli-
cando el operador ==. Si la comparación devuelve “true” entonces se sumará uno
a “n”. Pero el lector, siempre atento, notará que el algoritmo no inicializa “n” a cero,
y ni siquiera devuelve el número de ocurrencias, que parece lo más intuitivo, sino
“void”. Pero tal es natural, pues la reusabilidad de un algoritmo se sustenta en no
fijar presunciones que lesionen su genericidad: de esta manera podemos pasar
por referencia a “count()” una variable con un valor anterior para que sea modifica-
da con las ocurrencias buscadas (caso que se da, por ejemplo, en la concatena-
ción de dos o más búsquedas sobre la misma o distinta colección). Se deja, así,
al usuario de la STL que especifique expresamente su intención:
vector<Politico> listaMunicipal;
vector<Politico> listaAutonomica;
// seguidamente se “llenan” los vectores con criterios
// que escapan a los propositos de este capítulo y por
// lo común a la lógica y la prudencia.
Politico discolo;
// se inicializa debidamente del objeto díscolo (o sea,
// se ponen algunas ideas en él).
int contador; // ¡oops! No se ha inicializado.
// seguidamente querremos contar cuántos políticos
// díscolos hay en una determinada lista.
count( listaMunicipal.begin(),
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 60
// seguidamente se cambia de vector (¡Horror!)
listaAutonomica.end(),
discolo,
contador ); // error: sin inicializar
// ¿El resultado? ¡Impredecible!
Visto lo anterior parece que para la mayoría de los casos un algoritmo como el
siguiente sería mucho más legible y seguro:
a lo que se podría llegar derivando de la clase “vector” en la STL una nueva clase
que incorporara como función miembro una función “count()” que, a su vez, usara
del algoritmo “count()”. Algo así como:
De esta manera las listas anteriores deberían ser instanciadas como objetos de
nuestro vector personalizado:
vectorEspecial<Politico> listaMunicipal;
vectorEspecial<Politico> listaAutonomica;
• Para cada algoritmo deberá añadirse una función miembro a nuestra clase.
Así, y aparte de la duplicación de clases que la derivación supone (para cada
clase en la STL habrá de crearse una nueva clase derivada con funciones
miembros reflejando cada algoritmo), dada la naturaleza de la STL, que invita a
añadir nuevos algoritmos, el interfaz de las clases derivadas debería ser cam-
biado con relativa frecuencia.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 61
• La facilidad por derivación enfatiza el uso de clases “no-normalizadas”, de ma-
nera que el código generado no se acoje a normas de estandarización y por
tanto plantea problemas para su extensión y acoplamiento a distintos entornos.
LEVES CRÍTICAS
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 62
APRENDIZAJE Y DOCUMENTACIÓN
14
¡Ah, lo siento! Para mí es “el Web” y no “la Web”. Y es que pese a la traducción de “Telaraña a
lo ancho del mundo” (que a mí me resuena a un cierto Capitán Tan), los barbarismos “WWW”,
“World-Wide Web”, “Web” ó “W3” me resultan terminantemente masculinos. Claro que una solu-
ción “políticamente correcta” sería la de “el/la Web”, tan común hoy en día en los textos nortea-
mericanos. Pero, vaya, tras leer la versión “políticamente correcta” de “Los Tres Cerditos” creo
que me batiría en duelo por reivindicar el sano derecho a la incorrectitud individual.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 63
(Stl<ToolKit>), con soporte para la mayoría de los compiladores C++ actuales,
aunque Rogue Wave ha anunciado también la inclusión de la STL en su conocida
biblioteca de clases Tools.h++. Restringiéndonos a los dos primeras, ambas con
buenos manuales y varios añadidos, yo recomendaría la segunda: STL<ToolKit>,
que provee un manual de 421 páginas perfectamente pedagógico, con más de
250 ejemplos de uso y una distribución de la información sencillamente perfecta
(tanto es así que parece que en breve se publicará el manual como libro en Pren-
tice Hall). Además ObjectSpace, accesible en el Web por http://www.objectspace.com
provee extensiones “multi-thread”, multitud de “algoritmos de ayuda” y soporte
para asignadores dinámicos de memoria.
REFERENCIAS DIRECTAS
• Cargill, T. STL Caveats, C++ REPORT, 7(6), julio-agosto 1995.
• Barreiro, J.-Fraley R. & Musser D.R. Hash Tables for the Standard Template
Library, X3J16/94-0218, WG21/N0605, enero 95.
• Koenig, A. The ideas behind STL, X3J16/94-0134, WG21/N0521, 1994.
• Musser D.R. The Standard Template Library Home Page, WWW 26/07/95.
• ObjectSpace Inc. STL<ToolKit> User Guide, mayo 1995.
• Stepanov, A. & Lee, M. The Standard Template Library, X3J16/94-0140,
WG21/N0527, julio 1994.
• Stroustrup, B. Making a vector fit for a standard, C++ REPORT, 6(8), octubre
1994.
• Vilot, M. An Introduction to the Standard Template Library, C++ REPORT,
6(8), octubre 1994.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 64
MANEJO DE EXCEPCIONES EN C++
4
xcepciones? ¿Es que no basta con las reglas15? ¡Oh, difícilmente las
¿E construcciones humanas pueden tratar con la inflexible y perfecta exacti-
tud reglada! Ya decía Goethe que “apenas hablamos, empezamos ya a
equivocarnos”. Y si la vida está repleta de errores, equívocos e imponderables,
imagínense el software, pobre y desdibujado reflejo de aquélla. Así que para ma-
nejarnos con cierta soltura debemos reglar también lo que no cabe en la propia
norma, estableciendo ciertas estructuras de control que nos permitan, cuando
menos, construir una somera malla en que las excepciones queden atrapadas: lo
excepcional se convierte así en previsible, en alguna medida. Esta es la ventaja,
claro. Pero desafortunadamente el diseño e implementación de un sistema de
captación y manejo de excepciones posee también sus reglas, sutilezas y des-
ventajas. Si encima añadimos a éstas la prolijidad y los problemas usualmente
achacados al lenguaje C++, bueno, el asunto adquiere tintes inopinadamente ma-
lignos. Pero quizá el tratamiento de excepciones constituya una excepción res-
pecto del comportamiento usual de C++: la sintaxis es relativamente sencilla, pero
su aplicación en sistemas software reales requiere de una estrategia previa cui-
dadosamente medida (y más vale que el lector me crea a pies juntillas). Entre
ambos extremos se sitúan, empero, los aspectos semánticos de uso de las ca-
racterísticas del lenguaje asociadas al manejo de excepciones y que son de los
que este capítulo se ocupará.
15
Quien piense que el proverbio latino Exceptio probat regulam significa “la excepción confirma la
regla” debería repasar su latín.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 65
{
if plantilla.incluye( empleado )
return -21545; //absurdo código de error
else {
plantilla.adiciona( empleado );
return 1;
}
}
Politico& PartidoPolitico::politicoHonrado()
{
// devuelve un político honrado del partido
// El problema es que si tal político no existe
// ¿qué se devuelve?
}
Una posible solución pasaría por reconvertir la función en otra que devuelva un
codigo de error:
de tal manera que el código cliente deberá siempre comprobar el valor de retorno
antes de operar con el posible Politico encontrado, pues si realmente no se en-
cuentra (el caso más frecuente) tal puntero apuntará ... ¿a qué?. Humm, esta solu-
ción, aparte de no ser especialmente elegante y resultar intrusiva 16, ni siquiera
puede aplicarse en todas las situaciones: pensemos, por ejemplo, en los cons-
tructores, que no pueden devolver código alguno.
16
Cuando se quiere recomponer artificialmente código muerto, el producto final tiene bastantes
posibilidades de acabar como el monstruo de Victor Frankentein: bien en la hoguera bien como
leitmotiv de películas absolutamente infames.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 66
D situaciones
La devolución de códigos de error por funciones no puede aplicarse en muchas
y, por tanto, no debe constituirse en estrategia genérica de manejo de
excepciones.
class Persona {
long dni;
public:
Persona::Persona(
if ( unDNI < 0 ) {
dni = 0;
return;
}
// código consructor persona
}
int comprueba() {
return dni;
}
// sigue resto descripción de clase
};
Pero esto arrostra nuevos problemas: ahora obligaremos bien a los clientes de la
clase a validar cada objeto antes de usarlo:
if ( fulano.comprueba() )
cout << fulano;
D
Los objetos “zombis” generan una ingente cantidad de código cliente de compro-
bación y bifurcación usualmente dependiente de unas especificaciones volátiles.
La aplicación indiscriminada de este enfoque ocasiona sistemas software de du-
dosa mantenibilidad.
¿Adivina ahora el lector por qué las estrategias usuales de error suelen resultar
tan artificiosas, frágiles y díficiles de mantener? Basta con echarle un vistazo a los
manuales corporativos de referencia de códigos de error: una barbaridad tal que
al final proporciona ciertos gusto y adicción malsanos17. Naturalmente no se afir-
17
Des Esseintes, el sofisticado protagonista del “À rebours” de Huysmans, gustaba de coleccio-
nar orquideas naturales que parecieran absolutamente artificiales: las corporaciones intentan
alcanzar el aberrante nivel opuesto asimilando a cada error un código que resulte humanamente
intuitivo (¡Diantre! ¡La psicología industrial se ha desquiciado!).
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 67
ma aquí que los códigos de error resulten dañinos per se, pues de alguna manera
(con algún código) ha de comunicarse la parte que genera un error con la parte
que la maneja. Pero el cómo es fundamental.
CONCEPTOS BÁSICOS
Como solución a estas cuitas, lo que C++ provee son tres nuevas construcciones
explicitadas en tres nuevas palabras reservadas:
Ü el bloque try, que indica las secciones de código que son sensitivas
respecto de las excepciones.
try {
// una porción de código cualquiera
}
18
Como señala Stroustrup, “raise” o “signal” hubieran sido palabras más apropiadas, pero éstas
ya existían en la biblioteca estándar de C.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 68
catch ( int entero ) { // inmediatamente después del bloque try
cout << “Código de error: ” << entero;
}
catch ( Persona ) {
// en este “catch” sólo importa el tipo de error
// y no el objeto concreto lanzado por “throw”
relanzaProcesoDePersona();
}
catch ( Racional& racional ) {
racional += 1;
cout << racional;
}
catch ( const char* mensaje ) {
VentanaDeMensaje( mensaje );
}
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 69
la expresión throw inicializaría un objeto temporal del tipo estático del operando
(éste es, “Mensaje”), y tal objeto se usaría a su vez para inicializar, de la misma
manera que un argumento en la llamada a una función, la variable establecida
como operando del catch adecuado. Vamos, que el mecanismo semeja el de una
expresión return. En tal sentido debe tenerse en cuenta que el paso por valor sig-
nifica el uso del constructor de copia, y que a pesar que la memoria para el objeto
temporal se asigna de una forma dependiente de la implementación, el destructor
del objeto deberá ser finalmente usado, de manera que tal funcionalidad mínima
tendrá que ser prevista en la clase.
C cer
Los objetos que se utilicen como operandos de expresiones throw deben pertene-
a clases en que el constructor de copia y el destructor sean accesibles (estén
declarados en la sección pública).
Cuando se “entra” en un manejador catch que toma como operando un objeto (no
una referencia a un objeto) de una clase dada, se produce una copia del objeto
lanzado por la expresión throw correspondiente, que se destruye cuando se sale
del ámbito del manejador. Si el catch espera un objeto no-constante, los posibles
cambios realizados en la copia del objeto dentro del manejador serán locales a
dicha copia y, por tanto, se perderán a la salida del catch.
MANOS A LA OBRA
class MensajeDeSocorro {
public:
MensajeDeSocorro( char* cadena );
char* cadena() const;
// resto descripción clase
};
void Programador::codifica()
{
desactivaSalvaPantallas();
escribe();
escribe();
escribe();
modifica();
piensa();
throw MensajeDeSocorro( “¿Qué había que hacer?” );
// (1)
}
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 70
void Analista::analiza()
{
try { // (2)
desactivaSalvaPantallas();
escribe();
escribe();
escribe();
discute();
piensa();
programador->codifica();
throw “¿Qué había que hacer?”; // (3)
}
catch ( char* ) { // (4)
VentanaModalDeAviso( “Cambiar de analista” );
}
}
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 71
ámbito en que se llama a la función “Programador::codifica()”, dentro de la función
“Programador::analiza()”, que sí está incluida en un bloque try (línea 2). Seguida-
mente miramos si el bloque try tiene uno o más bloques catch asociados. Y así
es: en la línea 4 se da un catch que admite objetos del tipo “char*”. Pero el objeto
que se lanzó en el throw era de tipo “MensajeDeSocorro”, por lo que este catch no
es de aplicación. Así que se busca un nuevo bloque try exterior, que se encuentra
en la línea 5 y que tiene asociados dos bloques catch en las líneas 6 y 7. En se-
guida se comienza la comparación del tipo lanzado con el que espera cada uno
de los bloques catch, examinados en estricto orden de aparición. Así tenemos
que el primero (línea 6) admite cualquier tipo de argumento (...), por lo que casa
perfectamente con el tipo “MensajeDeSocorro” que se lanzó en el throw inicial.
Pasa inmediatamente a ejecutarse el catch(...), y en ese mismo momento la ex-
cepción se entiende manejada (exactamente así, querido lector). Lo que sigue es
una instrucción “throw” sin más que, simplemente, relanza la misma excepción
que había captado, significada en el mismo objeto de tipo “MensajeDeSocorro”: o
sea, es como si se repitiera la línea 1, pero en esta nueva posición:
G
Una expresión throw sin operando relanza la excepción que en ese momento se
estaba manejando sin copiarla. Si no se está manejando ninguna excepción se
genera una llamada a “terminate()”.
Claro que ahora el lector despistado podría pensar: “Bueno, perfecto. El segundo
catch de la línea 7, que espera un objeto de tipo “MensajeDeSocorro” manejará
perfectamente la excepción relanzada”. ¡En absoluto! Hay que pensar que las
conjunciones “try-catch” se asemejan sobremanera en su comportamiento a las
conjunciones “switch-case” (suponiendo un break al final de cada case): para ca-
da try se ejecuta, a lo sumo, solo uno de los catch asociados. Es fácil ver, así, que
como el catch de la línea 6 capta cualquier excepción de cualquier tipo, el catch
de la línea 7 no será alcanzado por ninguna excepción en ningún caso, y de hecho
un buen compilador emitiría el siguiente error (sí caro lector: error, no aviso):
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 72
caso para llamar a una función miembro, “cadena()”, que devuelve la cadena de
caracteres de su representación interna (ésta es, “¿Qué había que hacer?”). Re-
capacite el lector que este último catch (línea 9) admite un objeto (no una referen-
cia) de forma que, como ya se notó en el parágrafo anterior, si se produjera algún
cambio en el mismo, éste se perdería al salir del ámbito del manejador. Hay que
fomentar aquí, también, las mismas consideraciones de eficiencia que aconsejan
el uso de referencias a objetos como argumentos de funciones.
Incidentalmente el lector habrá también notado que la línea 3, en que está codifi-
cado directamente el lanzamiento de una excepción asociada a la función “Analis-
ta::analiza()”, nunca será alcanzada, pues la excepción lanzada con anterioridad
por la función “Programador::codifica()” modifica el flujo secuencial del programa,
como es fácil suponer y más adelante veremos. De esta manera el software imita
al mundo real: el error del programador impide que el del analista resulte visible.
CLASES DE EXCEPCIONES
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 73
class ErrorBaseDeDatos : public Error { /*...*/ };
class ErrorDeActualizacion : public ErrorBaseDeDatos { /*...*/ };
void actualizaClientes() {
throw ErrorDeActualizacion(); // (10)
}
try { // (11)
actualizaClientes();
}
catch ( ErrorDeActualizacion ) { /*...*/ } // (12)
catch ( Error ) { /*...*/ } // (13)
catch ( ErrorBaseDeDatos ) { /*...*/ } // (14)
void actualizaClientes() {
throw ErrorBaseDeDatos();
}
C ensiempre
Si en un conjunto de bloques catch tras un bloque try se manejan tipos de datos
jerarquía, los bloques catch con argumento de clases derivadas deberán
anteceder a los catch que manejen excepciones de sus clases base
respectivas..
EL DESBOBINADO19 DE LA PILA
Cuando se lanza una excepción el programa “salta” hacia un nivel superior donde
el error podrá ser procesado20 o, lo que es lo mismo, se transfiere el control de la
19
Bueno, “desbobinado” no existe en castellano, pero rebobinado, el vocablo más ajustado, re-
presenta la acción de “desbobinar” para bobinar en otro carrete (un tipo de pila, al fin y al cabo).
Por si el lector abriga alguna duda, “desempilar” o “desapilar” tampoco existen.
20
¿No les viene a la cabeza una poca piadosa semblanza con la actitud de algunos ante la su-
puesta vida eterna? ¡Yerra, yerra y sufre, que de todo se ocupará un nivel superior! Ah, pero, ¿y
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 74
ejecución del programa al primer bloque try que lo encierre. Normalmente los ob-
jetos en la pila (stack) se destruyen cuando finaliza el ámbito en que fueron decla-
rados, pero al realizar el “salto” quedarían objetos abandonados entre el
lanzamiento y el manejador. Para evitar esto se invocan los destructores de todos
los objetos automáticos construidos hasta que se encuentra el bloque try, y este
proceso de denomina “desbobinado de la pila” (stack unwinding). Pero
pongamos las cosas más difíciles: imaginemos que se genera una excepción en
el bloque de inicialización de un constructor, de tal forma que algunos de los
objetos que debería inicializar quedan sin construir. El desbobinado de la pila, a
resultas de tal excepción, llamará solamente a los destructores de los objetos
totalmente construidos.
CONSISTENCIA DE ESTADOS
Stroustrup relata con detalle las dudas que surgieron en el proceso de diseño del
mecanismo de manejo de excepciones en C++ respecto de sí debía ser continua-
tivo o conclusivo: o sea, si tal mecanismo debía constituirse en una bifucarción
que, tras ser tratada, pudiera devolver el flujo del programa a donde se lanzó la
excepción o bien debería adoptarse el actual enfoque. La decisión final es ac-
tualmente evidente. Las razones fueron, en esencia, que el mecanismo continuati-
vo representaba graves complejidades como estrategia y, sin embargo, resultaba
fácilmente codificable tomando como base el enfoque conclusivo.
Es relativamente usual, por ejemplo, que una función miembro necesite completar
una serie de acciones para mantener la consistencia del estado interno del objeto
a que se aplica. Echemos, si no, un vistazo a la siguiente función:
void PoliticoHonrado::adjudicaContrato(
vivir? Esta es, naturalmente, una de las razones por las que el hombre mata a Dios (pero su
sombra es larga, que decía Nietzsche).
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 75
Adjudicatario& X, long soborno )
{
recibeDinero( soborno );
try {
cometeTurbiosManejos();
}
catch(...) {
devuelveDinero( X, soborno );
throw; // relanza la excepción
}
emiteDictamenFavorable();
}
Claro que aquí el lector descontento podría exclamar: “Oh, esto es demasiado
prolijo. Si tengo que codificar de esta manera todas mis funciones el código final
crecerá una barbaridad. Y eso sin hablar de los errores tipográficos que acechan
en cada línea”. Bueno, en primer lugar he de reconocer que el lector se expresa
muy bien, para después proclamar que, como ya anuncié, el manejo de excepcio-
nes en C++ no es tarea simple.
void Politico::cobra()
{
HombreDePaja* testaferro = new HombreDePaja();
// Aquí se suceden distintas llamadas
// a funciones y métodos (a cuál peor)
delete testaferro; // se eliminan las pruebas
}
class PunteroAHombreDePaja {
public:
PunteroAHombreDePaja() : testaferro( new HombreDePaja; ) {}
~PunteroAHombreDePaja() { delete testaferro; }
HombreDePaja* testaferro; // ¡anatema!
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 76
void Politico::cobra()
{
PunteroAHombreDePaja testaferro;
// Transacciones financieras varias
}
void Politico::cobra()
{
New< HombreDePaja > testaferro;
// ahora puede usarse testaferro como un puntero
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 77
// a un HombreDePaja, merced al operator*.
firma( testaferro );
}
Otra solución, a falta de un buen recolector de basura para C++, sería usar de
Punteros Inteligentes (Smart Pointers) para gestionar el manejo de excepciones.
Pero esto se sale del ámbito de lo aquí pretendido, así que el lector interesado
puede echarle un vistazo al interesante artículo de Steve Churchill.
ESPECIFICACIÓN DE INTERFACES
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 78
Bueno, esto resulta perfecto: ahora cada uno sabrá a qué atenerse cuando mane-
ja funciones ajenas, dotando a su código si es necesario de los manejadores
adecuados (y antes de los bloques try) para controlar las posibles excepciones.
¿Perfecto? Humm, seguro que el lector ha notado un cierto retintín en la repetición
del adverbio “legalmente”. ¿Qué significa aquí está apreciación jurídica? Pues
exactamente lo siguiente: si una función con una especificación de excepciones
de ciertos tipos lanza una excepción no contemplada en la lista, entonces el sis-
tema llamará automáticamente a la función “unexpected()”, que por defecto llama-
rá a “terminate()”, que por defecto, a su vez, llamará a “abort()”, y el programa
acabará abruptamente. ¡Vaya! ¡Funciones nuevas! Echémosles un vistazo.
EL FINAL DE LA CUERDA
N
No se debe lanzar una excepción desde el interior del cuerpo de un destructor,
pues si su lanzamiento se produce durante un desbobinado de la pila se ignorará
el mecanismo de manejo de errores y se llamará indefectiblemente a “termina-
te()”.
que admite un puntero no nulo a una función (que necesariamente debe terminar
sin devolver el control al usuario) y retorna el anterior manejador.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 79
VULNERACIÓN DE LA ESPECIFICACIÓN DE EXCEPCIONES
Si una función con una especificación de excepciones asociada lanza una excep-
ción no contemplada en tal lista, se producirá una llamada a la función “void unex-
pected()”, que a su vez llamará a su manejador asociado de tipo
que por defecto llamará a la función “terminate()”. Tal manejador puede cambiar-
se, empero,mediante la función
¡Demonios! ¡Otra nueva palabra! Bueno, sufrido lector, no me negará que esta
situación excepcional lo disculpa casi todo: “bad_exception” es el nombre de una
clase derivada públicamente de “exception”, perteneciente a la biblioteca están-
dar del lenguaje, y cuya razón de ser es precisamente evitar el problema sugerido
por Taligent y que se refiere al peligro de usar funciones con especificación de
excepciones en un código robusto: cuando se lanza una excepción no prevista,
directa o indirectamente, la acción por defecto es terminar el programa. Y, claro,
esto resulta inaceptable. Debe procurarse algún mecanismo que permita obviar
conscientemente este problema sin eliminar las útiles especificaciones de inter-
faz. La solución la proporciona la clase “bad_exception”. Pero veámoslo en deta-
lle.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 80
búsqueda de un nuevo manejador en el ámbito de la llamada a la función con la
especificación referida.
CONCLUSIONES
Como bien afirma Hortsmann, “Las excepciones deberán reservarse para cir-
cunstancias inesperadas en el flujo normal de una computación y cuya ocurrencia
crea una situación que no puede ser resuelta en su actual ámbito”. De hecho él
mismo establece unas cuantas indicaciones de uso de excepciones:
• Captar únicamente aquellos errores que se puedan manejar.
• Las excepciones deben usarse en circunstancias excepcionales.
• No apoyarse en excepciones si se puedes validar el código.
• No lanzar una excepción si se puede continuar.
• Permitir a los usuarios de bibliotecas decidir cómo desean que los errores sean manejados.
• Usar excepciones cuando se den fallos en constructores.
• No pierdas recursos durante el procesado de excepciones
David Reed, por su parte, expone un plan metódico para incorporar las excepcio-
nes a un código ya existente:
• Implementar manejadores especiales para las funciones “terminate()” y “unexpected()”.
• Añadir bloques try/catch que cubran las excepciones pre-existentes.
• Diseñar y utilizar clases de excepciones.
• Añadir especificaciones de excepciones a las funciones.
• Localizar y reparar pérdidas de recursos.
& encasC++
Lea, lector, lea. Porque cualquier intento de aplicar el manejo de excepciones
sin conocer exactamente los recursos del lenguaje y las característi-
del compilador troca imposible la definición de una estrategia exitosa que
M estructure las excepciones en una arquitectura eficaz, efectiva y fácilmente
mantenible. Lo contrario es, sin duda, una bomba de relojería gobernada por un
reloj estropeado.
REFERENCIAS DIRECTAS
• Working Paper for Draft Proposed International Standard for Information Sys-
tems - Programming Language C++, Documento X3J16/95-0185-
WG21/N0785, 26 de septiembre 1995.
• Exception Handling: Supporting the Runtime Mechanism, Josée Lajoie, SIGS
Publications, C++ Report, marzo-abril 1994.
• Using C++ Exceptions, David Reed, SIGS Publications, C++ Report, marzo-
abril 1994.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 81
• Excepctions: Pragmatic issues with a new language feature, David R. Reed,
SIGS Publications, C++ Report, octubre 1993.
• Designing and Coding Reusable C++, Martin D. Carroll & Margaret A. Ellis,
1995, Addison-Wesley, 0-201-51284-X.
• The Design and Evolution of C++, Bjarne Stroustrup, 1994, Addison-Wesley,
0-201-54330-3.
• Mastering Object-Oriented Design in C++, Cay S. Horstmann,1995, John Wi-
ley & Sons, 0-471-59484-9.
• C++ Strategies and Tactics, Robert B. Murray, 1993, Addison-Wesley, 0-201-
56382-7.
• Exception Recovery with Smart Pointers, Steve Churchill, SIGS Publications,
C++ Report, enero 1994.
• Taligent’s Guide to Designing Programs: Well-Mannered Object-Oriented
Design in C++, Taligent Inc, 1994, Addison-Wesley, 0-201-40888-0.
• Designing with Exceptions, Grady Booch y Michael Vilot, SIGS Publications,
C++ Report, Mayo 1994.
• Designing with Exceptions, Grady Booch y Michael Vilot, SIGS Publications,
C++ Report, julio-agosto 1994.
• C++ Primer, 2nd Edition, Stanley B. Lippman,1991, Addison-Wesley, 0-201-
54848-8.
• The C++ Programming Language, 2nd Edition, Bjarne Stroustrup, 1991, Ad-
dison-Wesley, 0-201-53992-6.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 82
ASIGNACIÓN EN C++
5
L
a asignación en C++ no es, como no lo son otras muchísimas características
del lenguaje, asunto baladí. C++ es sorprendentemente copioso en sutilezas
sintácticas, lo que plantea dos cuestiones: la seguridad de las herramientas
generadoras de código y la eficacia de los cursos-relámpago de C++ avanzado
(se han llegado a publicitar risibles reclamos de la guisa “Programación Avanza-
da Orientada-a-Objetos en C++, Visual Basic y Clipper en 15 días”). C++ es ex-
tenso, prolijo, complejo y, afortunadamente, imperfecto en su sentido más prácti-
co: amigo de lo bueno, como podría haber dicho Voltaire. Lo que sigue es, pues,
una concentración de técnicas, sintácticas y de construcción de programas, que
pretende mostrar al programador novel -y aun intermedio- en C++ las soluciones
a distintos problemas bien conocidos, como fuego en carne, por los expertos21.
CONCEPTOS BÁSICOS
Como bien sintetiza Winston, “El operador de asignacion se utiliza para cambiar
el valor de una variable” y en C++ viene representado por los símbolos:
21
Al decir de Oscar Wilde, “la experiencia es el nombre que cada uno da a sus propios errores”,
mientras que para Auguez es “la suma de nuestros desengaños”. Un experto es, por tanto, una
persona que, a más de equivocarse muchísimo, sufre abundantes rechazos y desencantos. La
línea entre un experto y un psicótico resulta, así, sorprendentemente frágil.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 83
garantizará la declaración y, en su caso, definición de un operador de asignación
implícito para las clases en que expresamente tal no se codifique, y que en esen-
cia consistirá en la copia miembro a miembro, secuencial y recursiva, de los
miembros no-estáticos y de las correspondientes porciones de las clases base
de la dada. De esta manera tenemos que (suponiendo que un político es un obje-
to con una cierta oscura funcionalidad) la siguiente línea:
unPolitico = otroPolitico;
equivale a
unPolitico.operator=( otroPolitico );
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 84
y cuya implementación realiza una copia bit-a-bit del objeto otroPolitico en el obje-
to unPolitico. De hecho, y según el borrador del estándar C++ (en adelante WP22:
working paper), “un operador de asignación por copia, operator=, es una función
miembro no-estática de la clase X con exactamente un parámetro de tipo X& ó
const X&”. El prototipo de operador por defecto, generado por el compilador, que
hemos visto antes, cambiaría empero su parámetro a constante
únicamente si, y sólo si, todos los miembros de la clase Politico y sus posibles
clases base directas (muy variadas, atendiendo al sorprendente resultado) pose-
yeran operadores de asignación con argumento constante.
El esquema de copia por defecto es, en definitiva, el siguiente: para cada dato
miembro no-estático de la clase se busca, recursivamente, si el tipo o clase a que
tal miembro pertenece posee operador de asignación, de forma que si existe se
usa para copiarlo y si no se genera una copia bit-a-bit.
class Politico {
const long ambicion; //una constante política
Persona& padrino; // imposible empezar sin él
// sigue descripción de clase
};
El compilador no podrá generar el operador implícito para tal clase, pues, co-
mo el leído lector conoce, los datos miembros de tipo referencia y constantes
tienen que ser inicializados y asignados a la vez: esto es, no pueden ser prime-
22
El nombre completo es “Working Paper for Draft Proposed International Standard for Informa-
tion Sytems -- Programming Language C++”, y su última versión ha sido sometida a revisión pú-
blica, con petición de comentarios, en los países cuyo capítulo nacional de estandardización así
lo ha requerido (no España, naturalmente).
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 85
ro inicializados para luego asignarles un valor. Precisamente por esto tales
miembros han de ser construidos forzosamente en la lista de inicialización de
todos los constructores, y no tienen cabida en una mera copia por asignación,
que es la que proporciona el operador implícito. El compilador originará, pues,
sendos errores (parece, así, que la ambición, por ser constante, y el padrino,
por constituirse en referencia, impiden, o cuando menos dificultan, la sustitu-
ción de los políticos).
class PartidoPolitico {
Politico Presidente; // sin operador implícito o explícito
// y un largo etcétera
};
class Politico {
private:
Politico& operator=( const Politico& );
// sigue descripción de clase
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 86
no podrá generar, en cualquier caso de los expuestos, su propio operador de
asignación por defecto. Así, cuando el compilador se encuentre con la primera
expresión de asignación exclamará algo así como:
error EDC3209: class "X" does not have a copy assignment operator
class Politico {
String* nombre;
String alias;
};
otroPolitico = unPolitico;
ASIGNACIÓN NO ES INICIALIZACIÓN
El siguiente código:
Politico unPolitico;
Politico otroPolitico = unPolitico;
unPolitico = otroPolitico;
equivale a:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 87
ción) muta los valores en objetos ya creados. Por eso en la línea en que aparece
el símbolo “=” y donde se crea el objeto otroPolitico interviene el constructor (de-
nominado constructor de copia) en lugar del operador de asignación.
class Politico {
public:
Politico( int numero = 0 ) : numeroDeLista( numero ){
cout << “Se crea el nuevo ideario ”
<< numeroDeLista << “\n”;
ideario = new String;
}
~Politico() {
cout << “Se destruye el ideario “
<< numeroDeLista << “\n”;
delete ideario;
}
private:
int numeroDeLista;
String* ideario;
// resto definición de clase
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 88
¿Qué ha ocurrido? Vemos que, en primer lugar, la copia implícitamente definida
origina que se copie en el objeto receptor ... el puntero a la cadena (como vimos
en el parágrafo anterior) y no la cadena en sí (para lo que habría que reservar es-
pacio y luego copiar los caracteres haciendo uso, por ejemplo, de strcpy(...) su-
poniendo que la representación interna de String sea un puntero a char y que
además sea accesible), de forma que tenemos dos objetos apuntando a la mis-
ma cadena de caracteres, siendo así que si uno de ellos cambiara la cadena ésta
cambiaría en ambos. Esta situación, en que ambos comparten exactamente la
misma cadena, causa que al operar el destructor de uno de ellos eliminando tal
cadena, el otro se quede conteniendo un puntero ... ¿a qué? ¡A basura! De esta
manera, cuando se aplica el destructor sobre el segundo objeto, el resultado es ...
el desastre. Naturalmente, y sin necesidad de aplicar el segundo destructor, el
segundo objeto está en estado inestable, y cualquier operación con él puede pro-
curar resultados indeseables. Incidentalmente cabe notar, también, que el ideario
primero queda libre ocupando memoria y ... ¡sin que nadie lo destruya!, gastando
así los preciados recursos del sistema. Por fin, y esto lo dejo en ejercicio al inteli-
gente lector, siempre desconfiado de las apariencias, ¿qué ocurriría si cambiá-
ramos el orden de destrucción de los objetos?
Realmente esto no funciona, así que, como afirman Meyers, Cargill y otros mu-
chos, siempre se definirá un operador de asignación para clases que usen de
memoria dinámica. Stroustrup propone una asimilación, a este respecto, entre
constructor de copia, destructor y operador de asignación, que Horstman formula
como regla de esta interesante forma: “Cualquier clase con un destructor no-
trivial necesita un operador de asignación definido-por-el usuario que realice
las copias de manera adecuada”, queriendo indicar que si el destructor tiene tra-
bajo que realizar, probablemente el operador de copia/asignación tenga pareci-
das tareas, lo que descalificaría al operador por defecto.
En primer lugar hay que insistir en que, como ya hemos visto, el operador = debe
ser una función miembro (regla que se extiende a los tres operadores (), [] y ->),
de manera que su declaración como función global (o amiga, un caso especial de
aquélla), como por ejemplo
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 89
originaría un error en compilación. El operador ha de ser también forzosamente
no-estático (no hay que olvidar que su funcionalidad se refiere a las instancias de
la clase).
a = b = c = d = e;
( a = ( b = ( c = ( d = e ) ) ) );
DESIGNACIÓN NO ES ASIGNACIÓN
class Politico {
public:
// operador ortodoxo explícito
Politico& operator=( const Politico& );
// sobrecarga (en el argumento, no en el tipo de retorno)
void operator=( Politico& );
// operador no-ortodoxo
Politico operator=( Politico* );
// etc., etc.
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 90
Ahora bien, ¿es semánticamente aceptable que un operador de copia/asignación
devuelva un tipo distinto de Politico&? ¿Es razonable que se devuelva ‘void’ (aun-
que alguno pueda alegar que un político nunca devuelve nada)? ¿Qué tipo debe,
en definitiva, devolver el operador de asignación/copia?
if ( unPolitico == otroPolitico ) {
// sigue ...
int uno = 1;
int dos = 2;
int tres = 3;
cout << ( uno = dos = tres ) << dos << tres; // imprime ‘333’
cout << ( ( uno = dos ) = tres ) << dos << tres; // imprime
‘323’
cout << ( uno = dos = uno ) << dos << tres; // imprime
‘113’
cout << ( ( uno = dos ) = uno ) << dos << tres; // imprime
‘223’
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 91
que el resultado de una asignación puede ser, a su vez, asignado, así que el ope-
rador predefinido devuelve una referencia no constante. Pero en el ejemplo adver-
timos, también, los un tanto inesperados resultados de aplicar la asociatividad de
izquierda a derecha en la última línea. Debemos considerar, pues, a la hora de
codificar nuestra función de asignación si vamos a permitir tal comportamiento. Si
no deseamos que el resultado de una asignación pueda ser usado a la izquierda
de una asignación (como lvalue), que suele ser lo más prudente, debemos proto-
tipar así nuestro operador:
¿Se debe limitar, con todo, el prototipo del operador de asignación explícito a las
sobrecargas con un argumento Politico& y const Politico&? Diríase que no. Exa-
minemos el siguiente código:
class Politico {
public:
Politico( char* promesas = 0 );
const Politico& operator=( const Politico& );
// ...
};
Politico puedoPrometerYPrometo;
puedoPrometerYPrometo = “Jamás dimitiré”;
evitando así la puesta en marcha del esquema de conversiones del lenguaje. Na-
turalmente la regla se puede generalizar de la siguiente forma: Se replicará la
sobrecarga de parametros unitarios de los constructores respecto del operador
de asignación.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 92
LA ASIGNACIÓN EN JERARQUÍAS DE HERENCIA
ASIGNACIÓN NO ES TRANSMUTACIÓN
Persona persona;
Politico politico;
politico = persona;
class Persona {
public:
virtual void disculpa() {
cout << “Lo siento\n”;
}
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 93
class Politico : public Persona {
public:
void disculpa() {
cout << “Estaba así cuando llegué\n”;
}
};
Persona persona;
Politico politico;
// llama a Persona::operator=( const Persona& )
// pues se produce conversión implícita del tipo
// Politico a su clase base pública Persona
persona = politico;
// pero veremos que no se observa cambio alguno:
persona.disculpa(); // “Lo siento”
politico.disculpa(); // “Estaba así cuando llegué”
// lo que sigue es un error, porque intenta acceder
// con un objeto de tipo Persona a la función de
// asignación implícita, que tiene un prototipo
// Politico& Politico::operator=( const Politico& )
politico = persona;
// lo que sigue, sin embargo, sí funciona, porque
// se asigna una persona a la porción de Persona
// que existe en un Politico (al menos en teoría).
// Así que en realidad se aplica la llamada:
// ((Persona&)politico).Persona::operator(persona);
( Persona& )politico = persona;
// pero, como se ve, el político no cambia:
politico.disculpa(); // “Estaba así cuando llegué”
struct Persona {
Persona& operator=( const Persona& );
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 94
struct Politico : public Persona {
Politico& operator=( const Politico& politico ) {
// llama al operador de la clase base
Persona:operator=( politico );
// y seguidamente copia los datos miembros
}
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 95
nombre = ‘\0’;
}
char* nombre
};
¿Qué ocurre en la peligrosa última línea? Pues que se ejecuta el código conteni-
do en el cuerpo de la función de copia/asignación, y en ésta lo primero es des-
asignar la memoria dinámica del dato miembro “nombre” en el objeto *politico,
para después asignar memoria suficiente (midiendo a partir del dato miembro
“nombre” de *persona) para seguidamente copiar la cadena de caracteres. ¿El
problema? Que al eliminar la cadena de caracteres del objeto *politico ... ¡se está
eliminando la cadena “nombre” del objeto *persona!, por lo que las subsiguientes
operaciones de medición y copia originan ... ¡el desastre! Pues claro -exclamará
el atento lector-: ¡los dos punteros apuntan al mismo objeto y -de nuevo claro- esto
no funciona! ¡Hay que cambiar el orden de las sentencias y modificar ligeramente
el código para solucionar este pequeño problema! (dejemos que el hirsuto lector
tome las riendas y veamos dónde nos lleva). “Basta con copiar la cadena del ob-
jeto a la derecha de la asignación (*persona en nuestro caso) a una cadena tem-
poral en calidad de variable local, a la que habrá que asignar memoria dinámica
suficiente midiendo la longitud de la cadena a copiar, para después poder elimi-
nar esta cadena sin problemas y luego -aquí el lector empieza a mostrar signos
de preocupación-, bueno luego habría que ver si hay más punteros o, mejor, co-
piar todo el objeto en un objeto temporal del mismo tipo, para así poder restituir
las variables y...” (en este momento el lector, totalmente avergonzado, reconoce
que su estrategia en absoluto funciona, y proyecta serios planes de enmienda).
En fin, retomemos el capítulo: si el problema sólo se produce en caso de auto-
asignación (directa o indirecta, por medio de lo que se denomina autoexplicativa
y bárbaramente “aliasing”), chequeemos esta circunstancia para adoptar diferen-
cialmente la estrategia adecuada, que evidentemente es ... ¡no copiar nada! Es
natural que si lo que se pretende es copiar dos objetos exactamente -bueno, in-
mediatamente matizaremos este adverbio- iguales, el mejor trabajo es no realizar
trabajo alguno, con lo que la copia quedará hecha. Nuestro operador quedaría de
la siguiente guisa:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 96
¡Ah, esto parece perfecto! Pero las apariencias no son más que eso: pura vani-
dad. Si atendemos a la línea de chequeo vemos que se comparan los objetos a
ambos lados del operador de asignación (objetos, no punteros), y además
haciendo uso de un operador de comparación que ha de suponerse definido para
la clase Politico. Atendamos a los hechos.
¿Cuál es el criterio que nos permitirá comparar dos objetos respecto de la auto-
asignación, como hemos hecho en el parágrafo anterior? ¿La igualdad o la iden-
tidad? Parece claro que, en general, la igualdad no, pues ésta se basa en la
exacta similitud de los valores de dos objetos, de forma que, por ejemplo, dos
objetos de una clase con un único atributo de nombre serían iguales si sus nom-
bres coincidieran. La identidad, sin embargo, se refiere al hecho diferencial del
objeto: yo soy yo, independientemente de los valores que asuma mi representa-
ción interna. Claro que en la práctica las cosas no son tan sencillas. ¿Serían por
ejemplo idénticas dos personas con el mismo NIF? Esto es, ¿sería adecuada la
siguiente función?
if ( this == &politico )
return *this;
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 97
no tiene por qué necesariamente funcionar. El modelo de objetos propuesto por el
OMG (Object Management Group) en CORBA (Common Object Request Broker
Architecture) propone unos identificadores de objetos (denominados “objrefs”)
que no tienen por qué ser únicos para un sólo objeto en tanto cada uno de estos
puede existir en distintos contextos no solapados. De cualquier manera el enfo-
que habitual en bases de objetos es la asignación automática y opaca por el sis-
tema de un OID (Object Identifier) a cada objeto. Pero estamos entrando en un
tema que examinaremos con más detenimiento -¿cómo no?- en el capítulo dedi-
cado a Bases de Objetos o Bases de Datos Orientadas-a-Objetos. A fin de cuen-
tas este enfoque de “luego veremos” es parte sustancial de la Orientación-a-
Objetos: involución permanente y citas circulares.
Hasta ahora hemos visto cómo una referencia o puntero de una clase derivada de
una dada se convierte convenientemente en un puntero o referencia a la clase
base para encajar con su operador de asignación, implícito o no. Pero seamos
exigentes: si tenemos
struct Persona {
const Persona& operator=( const Persona& );
};
Persona persona;
Politico politico;
y quisiéramos codificar
politico = persona;
o, en general, deseáramos una jerarquía de clases en que los valores de los obje-
tos pudieran ser asignados con independencia de las clases involucradas (siem-
pre en la misma jerarquía derivativa), necesitaríamos añadir, en el presente caso,
una nueva función a la clase Politico:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 98
ción pública). Pero esto significa que ahora tendremos en nuestra clase Politico
dos funciones, una con argumento “const Persona&” y otra con argumento “const
Politico&”, de parejo contenido (relacionadas cuando menos por una inclusión no-
estricta). Y si la jerarquía es una larga cadena de derivación tendremos que cada
clase constará de un operador de asignación más que la anterior, y que la adición
de una clase en medio de tal jerarquía obligaría a añadir una nueva sobrecarga
del operador de asignación en las clases derivadas de la insertada. Bueno, es un
panorama ciertamente poco elegante y difícil de explicitar en una jerarquía de uso
comercial. ¿No habría una forma de usar tan sólo un operador que reuniera la fun-
cionalidad de los otros con argumentos de clases bases? En realidad el compor-
tamiento de tales funciones resulta seguir el siguiente esquema:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 99
samente al operador de la clase base directa. ¿Es, pues, una buena solución?
¡Ea! Seguro que el inteligente lector ya supone, a estas alturas, que con el opera-
dor de asignación en C++ no hay solución única. Podríamos decir que el opera-
dor de asignación implícito proporciona lo que se denomina una “copia superfi-
cial” (shallow copy), mientras que nuestra recursividad manual procura la llamada
“copia profunda” (deep copy). La copia superficial presenta escasos problemas
conceptuales, mientras que la copia profunda, bueno, por citar sólo un problema:
¿qué ocurre cuando se dan referencias circulares en la recursividad hacia atrás
planteada? ¿Qué ocurre, por otro lado, con el operador de comparación para el
chequeo de la autoasignación? ¿No debería tal operador codificarse de la misma
manera que el de asignación montando casts dinámicos? ¡Seguro que sí! Diga-
mos que el aumento de complejidad supone un parejo aumento de la capacita-
ción del programador respecto del lenguaje. Así que, como dicen en Tráfico, “si
no está realmente seguro, no adelante”, so pena de encontrarse con demasiados
problemas y otras tantas peligrosas implicaciones. Y si no veamos qué ocurre
cuando el problema se hace virtual (¡Problemas virtuales! Gracián caeríase muer-
to ya).
POLIMORFISMO EN ASIGNACIÓN
Como quiera que un operador de asignación es una función miembro de una cla-
se (se trate de un operador de copia/asignación o de un operador de asignación
cualquiera), en tal calidad puede ser perfectamente declarado como virtual. La
única salvedad a considerar aquí es que el operador de copia/asignación de la
clase derivada no se constituye en destinatario del mecanismo virtual respecto
del operador de copia/asignación en la clase base, lo cual es ciertamente lógico,
merced a la diferencia del tipo del argumento y al especial mecanismo implícito
del operador. Examinemos, así, el siguiente código:
struct Persona {
virtual int operator=( char* );
virtual Persona& operator=( const Persona& );
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 100
*persona = otroPolitico;
// llamada a Politico::operator=( const Politico& )
unPolitico = otroPolitico;
pudiendo pasar como un argumento una referencia a una Persona o una referen-
cia a una clase derivada de ésta.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 101
ficación de acceso al operador que se resuelve en tiempo de ejecución depende
de la cualificación de acceso de la clase a que pertenece el puntero o la referen-
cia desde la que se accede a la función. Esto es, si tenemos:
struct Persona {
virtual Persona& operator=( const Persona& );
};
class Animal{};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 102
class Persona : virtual public Animal {};
class X : virtual public Animal {};
class Politico : public Persona, public X {};
Pues que, de acuerdo con el WP, queda sin especificar si la porción de la clase
base virtual Animal se asignará una o dos veces mediante el operador de co-
pia/asignación definido implícitamente en la clase Politico. El comportamiento
quedará, en cada caso, determinado por el compilador concreto utilizado, con lo
que viene a colación el consejo de Cargill: “No trates de aprender la semántica de
la herencia múltiple de tu propio compilador”. Naturalmente tal inespecificidad
puede ser salvada -¿cómo no?- codificando expresamente todos los operadores
de asignación y procurando manejar las asignaciones de todas las porciones, tal
y como muestra el mismo Cargill. De cualquier forma en el ARM se reconoce que
llegar a un estado de consistencia en jerarquías virtuales con operadores de asig-
nación es francamente difícil.
REFERENCIAS DIRECTAS
• Working Paper for Draft Proposed International Standard for Information Sys-
tems -- Programming Language C++, ANSI X3J16, 28-abril-1995.
• The C++ Programming Language, 2nd Edition, Bjarne Stroustrup, 1991, Ad-
dison-Wesley, 0-201-53992-6.
• Mastering Object-Oriented Design in C++, Cay S. Horstmann, 1995, Wiley, 0-
471-59484-9.
• On To C++, Patrick Henry Winston, 1994, Addison-Wesley, 0-201-58043-8.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 103
• C++ Programming Guidelines, Thomas Plum & Dan Saks, 1991, Plum Hall, 0-
911-537-10-4.
• C++ Strategies and Tactics, Robert B. Murray, 1993, Addison-Wesley, 0-201-
56382-7.
• Class Construction in C and C++, Roger Sessions, 1992, Prentice Hall, 0-13-
630104-5.
• Effective C++: 50 Specific Ways to Improve Your Programs and Designs,
Scott Meyers, 1992, Addison-Wesley, 0-201-56364-9.
• Advanced C++: Programming Styles and Idioms, James O. Coplien, 1992,
Addison-Wesley, 0-201-54855-0.
• The Design and Evolution of C++, Bjarne Stroustrup, 1994, Addison-Wesley,
0-201-54330-3.
• Taligent’s Guide to Designing Programs: Well-Mannered Object-Oriented
Design in C++, Taligent, 1994, Taligent Press, 0-201-40888-0.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 104
PATRONES DE DISEÑO
6
E
n el capítulo “Gestión de Proyectos Orientados-a-Objetos” se expone de
forma breve el panorama aparentemente confuso y un tanto desolador en el
que parece estár sumido el Diseño Orientado-a-Objetos (OOD), necesita-
do de soluciones formales claras, sectorialmente completas, efectivas, compren-
sibles y aplicables en la gestión diaria de proyectos software. Se trata, en definiti-
va, de aplicar la modularidad propugnada para la Programación Orientada-a-
Objetos (básicamente según los criterios y principios que expone Bertrand Meyer
en “Object-Oriented Software Construction”) a las áreas del Análisis y Diseño
Orientados-a-Objetos. Y es en este contexto donde aparecen, como sacados de
un cuento de Perrault, los patrones de diseño (inevitable traducción, quizás des-
afortunada, de Design Patterns: DPs). Basados en la obra del arquitecto y mate-
mático estadounidense Christopher Alexander, los patrones, cual solución balsá-
mica, pretenden encerrar la esencia cualitativa de distintas soluciones sectoriales
software y generar componentes de diseño universalmente reutilizables. Bien: el
propósito es encomiable, y merece la pena examinarlo en algún detalle.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 105
ma, y da a esta parte la elusiva calificación de “la calidad que no se puede nom-
brar”.
Alexander sostiene que existe un “algo innombrable” que no puede ser modelado
únicamente por medio de un conjunto arbitrario de requerimientos. Esto es, que
los sistemas poseen una esencia cualitativa que les otorga verdadera identidad y
equilibra sus fuerzas internas. Y si bien tal calidad no tiene nombre, sí pueden ad-
jetivarse los sistemas que la poseen: vivos, completos, libres, exactos, desperso-
nalizados y eternos. Bien, esto puede sonar un tanto místico, pero así suena
Alexander todo el tiempo. Pongamos un ejemplo arquitectónico práctico: si nos
fijamos en las construcciones de una determinada zona rural observaremos que
todas ellas poseen apariencias parejas (tejados de pizarra con gran pendiente,
etc.), pese a que los requerimientos personales por fuerza han debido ser distin-
tos. De alguna manera la esencia del diseño se ha copiado de una construcción a
otra, y a esta esencia se plegan de forma natural los diversos requerimientos. Di-
ríase aquí que existe un “patrón” que soluciona de forma simple y efectiva los pro-
blemas de construcción en tal zona. Este patrón, no obstante, para ser considera-
do como tal, y siempre según Alexander, debe encerrar la capacidad de conectar
con la cualidad buscada.
Tal y como Alexander expone, “cada patrón describe un problema que ocurre una
y otra vez en nuestro entorno, para describir después el núcleo de la solución a
ese problema, de tal manera que esa solución pueda ser usada más de un millón
de veces sin hacerlo siquiera dos veces de la misma forma”. Pero pasemos ya al
área software: un patrón de diseño23 es, pues, una solución a un problema en
un determinado contexto. Tal solución es, empero, a la vez parte del “qué” y del
“cómo” del sistema completo a construir: esto es, la pieza que conforma el patrón
software es como la pieza del patrón de sastre que se utiliza para confeccionar
vestidos y trajes, pues tal pieza, aparte de contener las especificaciones de corte
y confección del producto final, representa a la vez, en apariencia, una parte de tal
producto textil. Pero vayamos a un ejemplo práctico.
23
También denominado “patrón software” o “patrón generativo”.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 106
necesita una solución matizadamente distinta en cada contexto en el que se plan-
tea: así, por ejemplo, no resulta igual iterar por una colección que por un objeto
compuesto por capas envolventes, como tampoco es exactamente igual un reco-
rrido que la conjunción concurrente de varios iteradores sobre la misma colec-
ción, ni resultan iguales los iteradores concretos que aquellos otros polimórficos,
aunque, de alguna manera, la esencia de la iteración es la misma para todos los
problemas de ese tipo. Aquí tenemos, por tanto, un “patrón”, conocido como “Ite-
rador” o “Cursor”, cuya descripción podría darse de acuerdo con el siguiente es-
quema (extraído del libro del GOF):
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 107
Si accedemos a un catálogo que contenga este patrón (“iterador”), encontrare-
mos que se refiere al acceso secuencial a objetos sin entrar en su representación
interna: esto es, sin directamente cambiarlos. Porque resulta que si lo que que-
remos es actuar de alguna manera sobre los objetos a recorrer, entonces debe-
remos usar de otro patrón: el conocido como “visitador”. Vemos, pues, que ya
existe una granulación diferencial de patrones que pretende encapsular la expe-
riencia adquirida en muchos proyectos software de forma límpida y reutilizable. Y
es que, como el lector fácilmente comprenderá, lo difícil de los patrones es preci-
samente descubrirlos, pulirlos y formalizarlos, porque la realidad, como una al-
fombra, necesita ser extendida y desenrollada para que se puedan apreciar sus
“patrones”, pues si no éstos aparecen desfigurados y confusos24.
CATÁLOGOS DE PATRONES
24
¡Vaya, esto suena profundo!, pero debo reconocer que el mérito, en traducción libre, es de
Themistocles.
25
En realidad se necesitó algo más que dos patrones (como, por ejemplo, un subsistema gestor
de implementaciones), pero esa es otra historia (nadie ha dicho que los patrones sean autosufi-
cientes para completar sistemas software).
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 108
parecida manera, pues se trataba de problemas que ya se habían abordado ante-
riormente. Pero, claro, lo que se pretende con un catálogo de patrones no es
favorecer al diseñador experto (que quizás no necesite en absoluto de los
patrones, aunque el estudio de la formalización del conocimiento es siempre
recomendable), sino más bien ayudar al diseñador inexperto a adquirir con cierta
rapidez las habilidades de aquél, como también comunicar al posible cliente, si
es el caso, las decisiones de diseño de forma clara y autosuficiente. Se trata, en
definitiva, de un medio para comunicar la experiencia de forma efectiva,
reduciendo (o aplastando, aplanando o suavizando) lo que sorprendentemente se
conoce como “curva de aprendizaje” del diseño.
¿PATRONES ORIENTADOS-A-OBJETOS?
TELEPREDICADORES DE SOFTWARE
26
Es como si desearan una suerte de quinta sinfonía de Prokofiev (la fusión del clasicismo
tradicional y la vigorosa modernidad), pero sólo obtuvieran el poderoso scherzo del segundo movi-
miento. ¡Ahí es nada!
27
Remy de Gourmont afirmaba que los hombres son tan estúpidos que dando un nombre nuevo a
una cosa vieja creen haber pensado algo nuevo. Bierce, más práctico, ironizaba: “Cogito cogito
ergo cogito sum”.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 109
(como el de la comunidad de Mexicali). ¿Entonces -preguntará el ahora decidi-
damente inquieto lector- los patrones no funcionan en arquitectura? Bueno, queri-
do lector, piense que Alexander, en sí, no es la piedra angular de ningún sistema
software. Recordemos, por ejemplo, que Collodi fue un mediocre escritor antes
de “Pinoccio” y siguió siéndolo después de éste. A veces una solitaria buena idea
genera resultados extraordinarios, y Alexander expone, en un inglés exaltado, va-
rias excelentes ideas. Piénsese, también, que los hijos no resultan nunca como
los padres porfían han de ser, y es que en la comunidad software a Cronos se lo
comerían sus hijos sin darle tiempo siquiera a posar para Goya. Parece, por otro
lado, que los patrones son “nuevos”, pero en absoluto es así, pues existen patro-
nes-marcos formales desde hace tiempo: MVC de Smalltalk, MacApp, etc., así
como patrones-de-rutinas que todos conocemos: las bibliotecas de algoritmos.
Resulta, al fin, que nos encontramos en una fase incierta de captura y formaliza-
ción de la rica experiencia en diseño extendida en multitud de maduros sistemas
software, y aparece claro que el sentido de la marcha es irreversible. ¿Patrones?
¡Sí, pero con prudencia!
PATRONES ELECTRÓNICOS
Listas de correo: esta es la materia viva de la que el lector podrá extraer lo último
en patrones. Es aquí, también, donde se pueden exponer ideas, pedir consejos,
etc.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 110
pueden o no aplicarse al software, así como herramientas y métodos que so-
porten patrones en el desarrollo de software, y si los patrones software son si-
milares o diferentes de otras clases de patrones. Para añadirse a la lista debe
enviar un mensaje a listserver@cs.uiuc.edu con el siguiente cuerpo: “subscribe
patterns-discussion Nombre Apellidos”. Si tienen problemas para obtener la
subscripción y contraseña, pónganse en contacto con Ralph Johnson (sí, ama-
ble lector, otro del GOF), el propietario de la lista, en johnson@cs.uiuc.edu.
• PLoP ‘94: La Primera Conferencia Anual sobre Patrones (PLoP: Pattern Lan-
guages of Programs) se celebró del 4 al 6 de agosto de 1994 en Monticello,
Illinois, USA. El planteamiento de esta conferencia resultó particularmente gra-
tificante, porque los trabajos no fueron expuestos directamente por sus autores,
sino por un grupo de revisores pre-seleccionados que en cada caso expusie-
ron sus gustos, quejas y sugerencias, fomentando así la participación entre los
asistentes.
• PLoP ‘96: La Tercera Conferencia Anual sobre Patrones. Los interesados pue-
den contactar con los organizadores en plop95@parcplace.com, o dirigirse
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 111
bien Richard P. Gabriel en rpg@parcplace.com bien a Kent Beck28 en
70761.1216@compuserve.com.
28
Kent Beck, que pertenece al Grupo de Patrones de Hillside, presentó en OOPSLA ‘89, junto
con Ward Cunningham, las fichas CRC, como el lector orientado-a-objetos posiblemente ya sa-
brá.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 112
ROLES Y OBJETOS EN C++
7
E
mpecemos con una pequeña disgresión linguística: el vocablo “rol” no exis-
te en castellano, pues habitualmente se utiliza “papel” en el sentido de “car-
go o función que uno desempeña en alguna situación o en la vida (RAE)”.
Lamentándolo mucho <grin> tal término “papel” parece referirse más bien a per-
sonas, y además, al poseer un signicado contextual, casi siempre tendríamos que
utilizar la frase “papel desempeñado/interpretado/jugado/acometido por”, mien-
tras que el barbarismo “rol” (del inglés: role) nos permite expresar sin ambigüe-
dad situaciones como, por ejemplo, “el rol de médico” o “el rol de la impresora”,
tal y como hacen los psicólogos y los malos literatos. El barbarismo es, pues, más
directo y claro. Eugenio D’Ors decía que el estilo, como las uñas, es más fácil
tenerlo brillante que limpio, pero en informática quizás haya de ser simplemente
eficaz. Algún lector se habrá preguntado, con todo, por qué enfatizo tanto las de-
cisiones lingüísticas. Pues porque resulta que el modelado software del mundo
real se basa en requerimientos, verbales o escritos, en los que los vocablos y la
sintaxis juegan un papel esencial. De hecho buena parte de los métodos de
OOA/OOD se basan en la bien-establecida técnica de Abbott que sustituye sus-
tantivos por clases y verbos o frases verbales por responsabilida-
des/relaciones/métodos/mensajes. Resulta al fin que, como afirma Nietzsche, es-
tamos “presos de las redes del lenguaje”, y los filólogos tienen un gran futuro en el
campo informático.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 113
CLASES DE ROLES
class Cliente {
public:
String nombre();
void nombre( String* );
Date fechaDeAlta();
PlazoDePago plazoDeCobro();
// etc., etc.
private:
String* nombre_;
String* apellidos_;
Date* fechaAlta_;
PlazoDePago* plazoDeCobro_;
// etc., etc.
};
class Proveedor {
public: // un interfaz similar al de cliente
private:
String* nombre_;
String* apellidos_;
Date* fechaAlta_;
PlazoDePago* plazoDePago_;
// y sigue y sigue
};
Es fácil ver que el resultado es ingenuamente ineficaz: los roles comparten mucha
información que aquí simplemente se replica (con las dificultades de manteni-
miento que esto conlleva). Necesitamos, pues, que estas clases de “rol” posean
como porción común la representativa de la clase “Persona”. Y rápidamente aquí
el lector exclamará: “hay que derivar”, con la misma segura solemnidad con que
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 114
Luis XIV exclamara “¿Ha olvidado Dios todo lo que he hecho por Él?”. Pero no
tan deprisa. En realidad una de las causas del fracaso de primeros proyectos en
C++ es la sobredosis de herencia. Intentemos, no obstante, la sugerencia del lec-
tor, muy avisado ya en estas cuitas.
Así las cosas, ¿un Político ES-UNA Persona? Bueno, esto significaría que allí
donde se espere una persona podría perfectamente aparecer un político. Y, claro,
aparte del lógico disgusto, esto es defendible -al menos jurídicamente. De esta
manera tendríamos que funciones con prototipo similares a
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 115
DINÁMICA DE CLASES
Bien, parece que la derivación puede funcionar y que los roles son objetos (por
clases) de pleno derecho, como establecen Shlaer y Mellor. Pero resulta que és-
tos afirman poco después que “este conjunto de objetos (los representativos de
roles) deberá contemplar el caso de una enfermera que momentáneamente es
paciente en un hospital”. O sea, que los roles, como evidencia la realidad, son
esencialmente dinámicos. Según Grady Booch, “el rol de un objeto denota la se-
lección de un conjunto de comportamientos que están bien-definidos en un punto
concreto en el tiempo”, siendo tal rol “la cara que un objeto presenta al mundo en
un momento dado”, de forma que “la mayoría de objetos interesantes interpretan
diferentes roles durante su vida”, como por ejemplo “en el curso de un día, la mis-
ma persona puede interpretar el rol de madre, doctor, jardinera y crítico de cine”.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 116
// ...
// poco después el médico enferma (el tabaco, ya saben)
Paciente paciente( cardiologoJefe.personaFisica() );
LA HERENCIA INNECESARIA
class Medico {
public:
String nombre() {
return persona->nombre();
}
Medico( PersonaFisica* pPF ) {
persona_ = pPF;
// resto inicialización
}
PersonaFisica* persona() {
return persona_;
}
// resto interfaz público
private:
PersonaFisica* persona_;
EspecialidadMedica* especialidad_;
};
Bueno, esto ofrece un mejor aspecto. Pero, ¿no cumple la misma función la
herencia privada en C++, en el sentido de “insertar” en los objetos de clases deri-
vadas una porción “privada” de la clase base? En esencia sí, pero sin procurar-
nos una porción “separada” representativa de tal parte privada. Y es que la heren-
cia es como las armas, el ingenio o la cucharilla del postre: sólo hay que usarla si
es inevitable.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 117
Tenemos, pues, que la opción de capas expuesta (layering) permite, de forma
sencilla, que dos objetos-rol compartan al mismo individuo de fondo:
La diferencia respecto del anterior esquema derivativo es que aquí existe un obje-
to diferencial de tipo PersonaFisica al que pueden apuntar distintos roles. La per-
sona representada por “juanNadie” no abandona -al menos no necesariamente- el
rol de médico cuando asume el rol de paciente, a la vez que se preserva la noción
de identidad (una noción fundamental que repasaremos cuando examinemos las
Bases de Objetos) respecto del sujeto que desempeña el rol. Sin embargo aquí
se nos plantea un nuevo problema: ¿cuándo se destruye el objeto de tipo Persona
contenido en un objeto de tipo Medico? Tal y como lo hemos planteado, en el
destructor de la clase Medico podemos hacer dos cosas igualmente malas: bien
eliminar el objeto Persona, con lo que otros objetos, como por ejemplo de tipo
Paciente, que apunten hacia el mismo quedarían en estado indefinido; bien no
eliminar tal objeto, de tal forma que se irán consumiendo valiosos recursos de
memoria: en definitiva, dos vertientes del desastre. Necesitamos, pues, de la ma-
tización de una estructuración conocida como “Clase Carta de Singleton”, bien
explicitada en el texto de Coplien (y de forma sintetizada en el de Murray), y que,
en breve, se basa en que una clase, a modo de sobre o envoltura, sirve de inter-
faz respecto del mundo exterior de la carta (por clase) que contiene:
class PersonaFisicaRep {
friend class PersonaFisica;
private:
PersonaFisicaRep() {
// inicialización básica datos miembros
}
// sigue resto de constructores
String* nombre;
String* apellidos;
Date* fechaNacimiento;
int contador;
};
class PersonaFisica {
public:
PersonaFisica() {
// aquí se accede al constructor privado
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 118
// de la representación de PersonaFisica
rep = new PersonaFisicaRep();
rep->contador = 1
}
// sigue resto de constructores
PersonaFisica& operator=(
const PersonaFisica& pPersonaFisica ) {
// incrementamos el contador de objetos
// que apuntan a la Persona del argumento.
pPersonaFisica.rep->contador++;
// si la representación de la persona
// contenida en el presente objeto ya no
// es apuntada por nadie, se elimina.
// (sin contar el presente objeto, claro)
if ( --rep->contador <= 0 )
delete rep;
// se sustituye una representación por otra
rep = pPersonaFisica.rep;
return *this;
}
~Persona() {
// comprueba si existe más de un objeto que
// apunte a la representación interna de
// Persona. En otro caso lo elimina.
// (más de uno, porque al menos uno lo
// apunta: el presente objeto: *this)
if ( --rep->contador <= 0 )
delete rep;
}
String* getApellidos() {
return rep->apellidos;
}
// sigue resto interfaz público
private:
PersonaFisicaRep* rep;
};
class Medico {
public:
Medico( PersonaFisica* pPF ) {
// se cambia la asignación a objetos
// en lugar de la anterior a punteros,
// para que actúe el operador de asignación
// redefinido anteriormente.
*persona_ = *pPF;
// resto inicialización
}
// resto definición de la clase
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 119
Así que ¿ésta es la solución? ¡Claro que no! Bueno, esto funciona, pero ... es de-
masiado artificioso (respecto del problema que pretende resolver), pedestre e
inseguro: debemos definir en cada rol un método que devuelva la porción de
PersonaFisica (o PersonaJuridica, en su caso); se establece, además, un
contrato con los programadores (usar asignación con objetos, etc.) sin establecer,
no obstante, precondiciones y postcondiciones en otro lugar que no sea la
documentación. Y es que al renunciar a la herencia hemos renunciado a algo muy
importante: al grueso del polimorfismo en C++. Resulta que ahora no contamos,
entre otras cosas, con la conversión implícita de tipos, y que funciones como las
siguientes:
void tributaAHacienda( Persona* );
void aprendeDeAnterioresErrores( PersonaFisica* );
tributaAHacienda( politico->persona() );
DIVIDE Y HEREDARÁS
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 120
del Sujeto que cada una contenga. Pero los sujetos pueden pertenecer a distintas
clases, por lo que parece adecuada una jerarquía como la que sigue (y aquí tam-
bién abreviaremos la descomposición):
class Rol {
public:
Rol( Sujeto* pSujeto ) {
*sujeto = *pSujeto;
}
virtual Sujeto* getSujeto() {
return sujeto;
}
private:
Sujeto* sujeto;
};
class RolDePersona {
public:
RolDePersona( Persona* pPersona ) :
Rol( pPersona ) {}
// Atención: la próxima función es virtual,
// porque aunque el tipo de retorno es distinto
// del de la clase Rol, es un puntero a un tipo
// que deriva públicamente de aquél.
Persona* getSujeto() {
return (Persona*)sujeto;
}
// resto definición de clase
};
class RolDePersonaFisica {
public:
RolDePersonaFisica( PersonaFisica* pf ) :
RolDePersona( pf ) {}
PersonaFisica* getSujeto() {
return (PersonaFisica*)sujeto;
}
// resto descripción protocolo de clase
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 121
};
class Empleado {
public:
Empleado( PersonaFisica* pf ) :
RolDePersonaFisica( pf ) {}
Salario* getSalario();
private:
Salario* salario;
Date* fechaContratacion;
// resto definición de clase;
};
Como vemos los roles concretos únicamente deben preocuparse de incluir códi-
go en su constructor, mientras que la asignación del sujeto, y por tanto el nudo de
los problemas, se circunscribe a la clase base Rol. Necesitamos, por fin, una je-
rarquía de representaciones internas de los sujetos (las cartas de los sobres de
Singleton, que son las clases derivadas de Sujeto), y cuya definición se obviará
por ser idéntica a la anteriormente expuesta:
class PersonaFisicaRep;
class PersonaJuridicaRep;
// etc., etc.
Bien, esto parece funcionar, así que es momento de que el lector se cuestione:
“¿Cuál es el fallo? Porque cuando el autor afirma que “parece funcionar” es segu-
ro que algo falla”. Bueno, bueno, ya nos vamos conociendo y se aprecian ciertos
leitmotivs wagnerianos. Y sí, algunas cosas no encajan bien.
Lo que de todo lo expuesto en primer lugar se infiere es que, como ahora parece
evidente, un rol NO-ES una persona, ni un tipo de persona, aunque, por ejemplo,
Politico es claramente un tipo de Rol. La separación de jerarquías aparece, pues,
inapelable. ¿Qué pasa, sin embargo, con la interoperabilidad en el mundo real
respecto de los roles y de quienes los asumen por la que asimilamos, verbigracia,
un médico a la persona que ejerce de médico? ¿Qué ocurre, por otro lado, con el
cambio dinámico de roles? Piénsese, por ejemplo, que tenemos la posibilidad de
cambiar el objeto, de tipo Sujeto o derivado, que ostenta el rol mediante una fun-
ción del tipo:
que será heredada por todos los roles concretos. Pero, ¿realmente sirve de algo
esta posibilidad de cambio? ¿Puede un rol cambiar de persona, o es más bien la
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 122
persona la que cambia de rol? Parece que, por un lado, existen ciertas capacida-
des básicas o comunes asociadas a determinados roles, pero es claro que es el
sujeto el que cambia, o más bien simultanea, roles. Por otro lado, ¿no les resulta
molestamente repetitivo el mimetismo de la jerarquía de roles respecto de la suje-
tos? ¿Por qué reflejar en aquélla la estructuración de esta última? ¿Qué ocurre,
por otro lado, con el fin del rol? ¿Se deberá añadir a los objetos de tipo Rol un
atributo de término del Rol que será establecido justo antes de eliminar el objeto?
Quizás todo este asunto necesite un re-enfoque, ¿y quién mejor que los expertos
para asesorarnos? Leamos el oráculo.
¡Oh, oh! ¡Patrones! Bueno, no podía ser de otra manera, pues lo que se pretende
es la transmisión formal de la experiencia. El problema de los roles no es nuevo y
parece lógico pensar que existan distintas sintetizaciones del mismo. Como es
costumbre, empezaremos por la más débil: Peter Coad establece que el proble-
ma del rol se enmarca en un patrón estructural genérico que denomina “Patrón de
Roles Intercambiables” (Changeable Roles Pattern) y que en definitiva consiste en
que existe un objeto que actúa de Intérprete del rol y que se relaciona con un solo
objeto a la vez de una clase derivada de Rol, que a su vez es una clase abstracta
base de una jerarquía similar a la expuesta. Coad establece la siguiente configu-
ración mínima:
class Interprete {
private:
Rol* rol;
// ...
};
class Rol {
private:
Time* momentoDeComienzo;
Time* momentoDeFin;
// ...
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 123
roles. Respecto del primer problema (la concurrencia) el lector me permitirá una
elegante elipsis hasta solucionar en alguna medida el segundo. Bien: este patrón
nos ha dejado insatisfechos, así que, ¿por qué no más de lo mismo?
EL PATRON DE ESTADOS
Pree, tras constatar la inoperante genericidad del patrón de Coad, afirma que el
problema de la implementación de la relación entre Intérprete (o Jugador) y Rol se
soluciona con otro patrón: el denominado “Patrón de Estados (State Pattern)”,
que se detalla en el libro GOF de Gamma y otros. El cometido básico de tal pa-
trón es permitir a un objeto modificar su comportamiento cuando quiera que su
estado interno cambie, apareciendo como que el objeto cambia de clase. Su im-
plementación en C++ es, básicamente, la siguiente: en vez de que una clase dis-
ponga de datos miembros específicos cuyos valores en distintos objetos reflejen
sus distintos estados y afecten, así, al comportamiento de sus funciones miem-
bros, tales datos miembros y funcionalidad asociada son extraídos y encapsula-
dos en objetos aparte, de forma que el objeto original mantiene un puntero a los
mismos y posee métodos para cambiar tal apuntamiento de un objeto representa-
tivo, por ejemplo, del “estado de recepción” a otro valedor de “estado de envío”.
Si sustituimos en el patrón original los nombres “Contexto” y “Estado” por los ya
usados “Sujeto” y “Rol” tendremos:
class Sujeto {
public:
setRol( Rol* unRol ) {
rol = unRol
}
unMensajeCualquiera() {
rol->maneja( this );
}
private:
Rol* rol;
};
class Rol {
public:
virtual Rol* maneja( Sujeto*);
};
de manera que los mensajes (relativos al rol) dirigidos a un Sujeto serían pasa-
dos, como una llamada a una función virtual, al rol concreto contenido en cada
caso en el objeto Sujeto. Bien: esto es mejor que lo anterior pero, a mi juicio, Pree
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 124
peca de ingenuidad (lo cual es lógico, dado el carácter anecdótico con que trata
este tema, pues su libro está enfocado hacia Metapatrones y Hot-Spots). La apli-
cación de este patrón no nos soluciona bien el problema planteado: piénsese
que, en primer lugar, todas las funciones de todas las clases derivadas de Rol
deberían declararse como virtuales en la clase base Rol, y además luego deberí-
an definirse en la clase Sujeto para permitir el redireccionamiento previsto. Así,
cada vez que añadiéramos un nuevo rol deberíamos modificar la clase Rol y la
clase Sujeto, y ¡recompilarlo todo! Esto, naturalmente, no encaja agradablemente
con la modularidad propugnada por la Tecnología de Objetos. ¿Es necesario,
pues, cambiar de patrón? ¡No! Yo más bien diría que hay que añadir algún patrón
más.
Este patrón establece cómo controlar el acceso a un objeto desde otro distinto.
Exactamente -es un decir- lo que queremos, pues se pretende controlar el acceso
a la funcionalidad embebida en los roles a través de objetos de tipo Sujeto. Ne-
cesitamos, pues, llamar en objetos de la clase Sujeto a funciones que no pertene-
cen a esta clase y sí a cualquiera derivada de Rol, pero no queremos replicar este
conjunto de funciones en Sujeto. ¿Cómo solapar, pues, el chequeo estático del
compilador relativo a tales funciones? Pues con la sobrecarga del operador pun-
tero. Apliquemos, sin más, el patrón al código:
class Sujeto {
public:
setRol( Rol* unRol ) {
rol = unRol;
}
Rol* operator->() {
return rol;
}
private:
Rol* rol;
};
class Rol {
public:
virtual void noPiensoDimitir();
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 125
};
Bien, esto funciona y parece suficientemente elegante, pero, como siempre, hay
que explicitar algunas consideraciones, matizar algunos comportamientos y co-
rregir ciertas inconveniencias.
CONVERSIONES E INDIRECCIÓN
class Sujeto {
public:
operator Rol*() {
return rol;
}
operator Rol&() {
return *rol;
}
private:
Rol* rol;
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 126
};
Así, en las dos últimas líneas se produce, mediante la aplicación de los operado-
res definidos, una conversión del objeto Persona en la parte de Rol que contiene:
en la última línea en forma de objeto, y en la penúltima en forma de puntero a tal
objeto. Naturalmente se podría objetar que lo que se necesita es precisamente lo
contrario: que funciones que esperan objetos de tipo Sujeto admitan objetos de
tipo Rol o derivados. Pero no, realmente no encaja bien este esquema cuando
hemos estimado que el rol carece de sentido autónomo funcional (aunque no de
comportamiento definido) sin el sujeto que lo desempeña.
Fíjese el lector, con todo, que la sintaxis se va complicando: a la función que es-
pera un puntero a Politico se le pasa ... un objeto de tipo Persona. Pero es que si
el lector retrocede un poco más verá también como el operador puntero se aplica
... ¡a objetos! Esto conlleva algunas consecuencias:
pues, como el hábil lector ya habrá adivinado, la última línea usa del operador ->
predefinido y, por tanto, no se produce redirección alguna, y dado que la función
que se llama no pertenece a la clase PersonaFisica (ni a la sección pública de
sus clases base), el compilador justamente se queja. Otra consecuencia es que el
mecanismo virtual no funciona directamente mediante el operador -> sobrecarga-
do, pues aquél sólo funciona sobre punteros y referencias, no sobre objetos.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 127
class Sujeto {
public:
Sujeto() {
controlRol = new ControlRol( this );
}
~Sujeto() {
delete controlRol;
}
ControlRol* operator->() {
return controlRol;
}
Rol* getRol() {
return rol;
}
private:
Rol* rol;
ControlRol* controlRol;
};
class ControlRol {
public:
ControlRol( Sujeto* unSujeto ) {
setSujeto( unSujeto );
}
void setSujeto( Sujeto* unSujeto ) {
sujeto = unSujeto;
}
// aquí seguiría el interfaz que antes
// debía replicarse en la clase base Rol:
// cada función se reencamina hacia la
// clase adecuada mediante casts.
void noPiensoDimitir() {
((Politico*)(sujeto->getRol()))
->noPiensoDimitir();
}
private:
Sujeto* sujeto;
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 128
que contemplara la intensa casuística a modelar. Afortunadamente parece que
Erich Gamma y Richard Helm han alumbrado un nuevo patrón (ExtensionObjects),
que se publicará próximamente en la columna bimensual que ambos escriben en
el Dr. Dobbs Journal Windows Sourcebook, y que serviría de base al esperado
Patrón de Roles. La idea es aportar una clase con un interfaz que permita pregun-
tar a un determinado objeto si soporta o asume un determinado interfaz o rol. El
resultado de tal consulta sería un objeto con la funcionalidad del rol buscado, que
naturalmente permitiría interactuar con el objeto inicial a través de su interfaz. Pa-
rece que tal nuevo objeto sería una suerte de Adaptador (véase el Patrón del
Adaptador en el libro GOF), y permitiría a sus clientes utilizar un determinado in-
terfaz para acceder a clientes solamente si pueden asumir un rol dado. Según
Helm, “lo magnifico de este patrón es que permitiría definir dinámicamente nue-
vos interfaces de clases sin compilarlos en la declaración de tales clases, evitan-
do así que las clases tuvieran interfaces hiper-hinchados para reflejar todos sus
posibles usos por clientes”. La idea parece interesantemente afortunada, y aun-
que aparenta tener puntos en común con la anteriormente expuesta, habrá que
esperar un poco más para discutirla.
Todo lo anterior está relativamente bien, pero obvia una cuestión esencial: un
mismo sujeto, en un período de tiempo dado, suele asumir distintos roles concu-
rrentemente. El tratamiento secuencial que hasta ahora le hemos dado a la asun-
ción de roles presenta, con todo, serios inconvenientes: ¿Qué ocurre cuando sus-
tituimos en un sujeto un rol por otro? ¿Se crea cada vez un nuevo rol y se destruye
el sustituido? ¿Dónde queda la memoria de lo asumido? Naturalmente aquí no
funciona el esquema de Singleton, pues no se intenta compartir un mismo objeto,
sino más bien mantener “vivos” unos objetos de tipo rol. Es claro que si el objeto
de tipo Sujeto se destruye (ojo: no es lo mismo que un sujeto muera -esto es, que
definitivamente cambie de estado- que el objeto que lo representa sea destruido)
deberán desaparecer con el todas las referencias que a él apunten, junto con to-
dos los objetos que con exclusiva dependencia maneje. Bien: intentaremos solu-
cionar a la vez los problemas planteados por la secuencialidad y la concurrencia
de roles.
class Rol {
public:
Bool activo();
Bool finalizado();
private:
Time* momentoDeComienzo;
Time* momentoDeFin;
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 129
// ...
};
class Sujeto {
public:
Sujeto();
~Sujeto();
ControlRol* operator->();
void setRol();
Rol* getRol();
operator Rol&();
operator Rol*();
private:
Rol* rol; // el rol actual
ColeccionDeRoles* roles;
ControlRol* controlRol;
};
Si, desde una óptica sindical, decidimos que hay escasos patrones que realmen-
te nos sirvan de ayuda, y que necesitamos nuevas luces, ¿qué mejor que la
asociación? Atendamos, de nuevo, a los expertos: Para Rumbaugh un rol es “un
nodo de una asociación”, puesto que “una asociación binaria tiene dos roles,
cada uno de los cuales puede tener un nombre de rol”. Esto resulta
significativamente importante. Hasta ahora hemos considerado que un Rol es un
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 130
portante. Hasta ahora hemos considerado que un Rol es un objeto de pleno dere-
cho, pero ... ¿y si no lo fuera? Consideremos un array o vector de objetos (de
cualquier tipo): el primer objeto es, en realidad, un objeto que juega el rol de “pri-
mero”; naturalmente tal rol es intercambiable mediante operaciones en el objeto
continente, pero ... ¿a alguien se le ocurriría modelar tal rol como una clase “Pri-
mero”? Bueno, seguro que a alguien, pero ¿es razonable tal modelado? En gene-
ral parece que no. El rol se transforma aquí en un mero vocablo que designa un
nodo direccional dentro de una relación. Pero leamos a más autoridades. Para
Embley, por ejemplo, un rol “es un atajo para expresar especialización”. De esta
manera un rol, al nominar una conexión entre objetos, es “una especialización de
la clase del objeto en la conexión cuyos objetos totalmente participan en el conjun-
to de relaciones en la conexión”, queriendo así expresar que la única diferencia
entre una especialización de rol y una generalización/especialización es el carác-
ter mandatorio de aquélla primera respecto de las clases que participan en la re-
lación: o sea, un Empleado de un hospital no tiene por qué tener pacientes asig-
nados, pero un médico siempre tendrá al menos uno: el conjunto de los emplea-
dos de hospital que poseen pacientes es el que determina la relación de rol. Pero
curiosamente Embley parte de un “Empleado” como clase, quizá derivada de
Persona, y según lo expuesto parece que “Empleado” es un rol desempeñado por
una persona en relación con una empresa: en realidad se trata de la cualificación
de uno de los nodos de una “Relación Laboral”. Y ... es hora de tomar un pequeño
respiro, que la cosa parece complicarse. Porque ¿realmente un rol no es un obje-
to? Examinemos esta afirmación con más detenimiento, usando a tal fin una Re-
lación Laboral. Este tipo de relación se establece entre una Persona y una Perso-
naFisica, de forma que la relación se definiría como (y obviaremos de momento
las cuestiones de jerarquía de relaciones):
class RelacionLaboral {
private:
Persona* empleador;
PersonaFisica* empleado;
long salarioAnual;
Date* fechaDeIncorporación;
Date* fechaDeCese;
RangoTemporal* horarioDeTrabajo;
// etc., etc.
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 131
añadimos sendos objetos de tipo Rol a la relación. Optaremos -razones de eco-
nomía tipográfica- por el segundo caso, así que roles siguen siendo objetos.
Veámoslo:
class RelacionLaboral {
private:
Persona* empleador;
Empleado* rolEmpleador;
PersonaFisica* empleado;
Empleador* rolEmpleado;
// resto protocolo clase
};
Pero, ¿por qué no encapsular los objetos de tipo Rol en los sujetos, como se ex-
puso anteriormente, en lugar de añadirlos a la clase Relacion? Pues porque de tal
manera los roles quedarían sin conexión con la relación que los genera, de mane-
ra que encapsulándolos en la relación podemos tener, verbigracia, tres roles de
tipo Empleado bien diferenciados. Como quiera, por otro lado, que todas las re-
laciones cualifican a los sujetos relacionados en virtud de roles direccionales,
necesitamos extender la asunción de roles a más entidades, para lo cual
debemos ampliar la jerarquía de intérpretes, que ahora pasarán a ser Entes,
resultando algo singularmente más extenso que lo siguiente:
Ente
Bien
BienInmueble
Finca
BienMueble
Arma
Prenda
Bolso
Cartera
Gafas
Joya
Vehiculo
Bicicleta
Ciclomotor
Motocicleta
Turismo
Persona
PersonaFisica
PersonaJuridica
AsociacionDeVecinos
SeccionOrganizativa
Ubicacion
ComunidadAutonoma
Localizacion
Provincia
Pais
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 132
Poblacion
Via
Calle
Carretera
Cruce
Bajo esta nueva situación se puede fácilmente hablar, por ejemplo, del rol de pro-
pietario que asume una sociedad limitada respecto de un vehículo, que a su vez
asume el rol de poseído, ambos roles siempre respecto de una relación binaria
de pertenencia. Pero sigamos: dado que todas las relaciones binarias encierran
entes asumiendo roles, ¿por qué no encapulsar tal comportamiento en una clase
base? Y de paso, ¿por qué no tipificar las relaciones entre distintos tipos de en-
tes? Intentémoslo:
class TipoDeRelacionEntreEntes {
public:
TipoDeRelacionEntreEntes( const Ente&,
const Ente&, Rol* = 0, Rol* = 0 );
~TipoDeRelacionEntreEntes();
private:
// los entes se tratan como referencias para
// obligar a su inicialización en el momento
// de la construcción de los objetos, y forzar
// la inmutabilidad de los tipos tras esto.
// El ente en sí no importa: sólo su tipo.
Ente& origen; // nodo inicial
Ente& destino; // nodo final
// nombre de la relación (v.b. "Propiedad")
String* nombreGenerico;
// relación del origen respecto del destino
// (v.b. "Posee" ó “es propietario de”)
String* nombreRelacion;
// relación del destino respecto del origen
// (v.b. "es poseído por" ó “es propiedad de”)
String* nombreRelacionInversa;
// objetos roles asumidos por los entes
Rol* rolOrigen;
Rol* rolDestino;
// etc., etc.
};
class RelacionEntreEntes {
public:
RelacionEntreEntes();
RelacionEntreEntes( Ente*, Ente*,
TipoDeRelacionEntreEntes* = 0 );
~RelacionEntreEntes();
// función de modificación
void set( Ente*, Ente*,
TipoDeRelacionEntreEntes* );
// funciones de acceso
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 133
Ente* getOrigen();
Ente* getDestino();
TipoDeRelacionEntreEntes* getTipoRelacion();
private:
Ente* origen;
Ente* destino;
TipoDeRelacionEntreEntes* tipoRelacion;
// etc., etc.
};
De esta manera contamos con la posibilidad de trabajar bien con meras asocia-
ciones nominadas bien con relaciones especializadas resultantes de aplicar la
herencia a aquéllas. Naturalmente sobre lo anterior cabría aplicar sendos interfa-
ces gráficos: En primer lugar deberíamos ocuparnos de una colección que man-
tenga de forma dinámica los tipos de relación activos en cada momento aplica-
bles a los Entes. Hay que tener en cuenta que los tipos de Entes en tales relacio-
nes representan la clase base a que son aplicables (la mínima base común), de
forma que la búsqueda de relaciones será fundamentalmen-te polimórfica. Segui-
damente el interfaz básico de los tipos admitidos para una determinada relación.
Lo que estamos haciendo es, en definitiva, aislar de la clase Relacion y de sus
derivadas el chequeo de tipos exactos de Entes aplicables para la asunción de
roles. Tal flexibilidad nos permitiría mdelar con facilidad, incluso gráficamente,
prolijas relaciones de roles entre objetos, como por ejemplo las siguientes:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 134
LA CITA DEL DESASOSIEGO
REFERENCIAS DIRECTAS
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 135
• Advanced C++ Programming Styles and Idioms, James O. Coplien, 1992,
Addison-Wesley, 0-201-54855-0.
• Object-Oriented Patterns, Peter Coad, 1992, Communications of the ACM,
33(9).
• C++ Strategies and Tactics, Robert B. Murray, 1993, Addison-Wesley, 0-201-
56382-7.
• Design Patterns for Object-Oriented Software Development, Wolfgang Pree,
1995, Addison-Wesley, 0-201-42294-8.
• Design Patterns: Elements of Reusable Object-Oriented Software, Erich
Gamma, Richard Helm, Ralph Johnson y John Vlissides, 1995, Addison-
Wesley, 0-201-63361-2.
• Object-Oriented Modeling and Design, James Rumbaugh, Michael Blaha, Wi-
lliam Premerlani, Frederick Eddy & William Lorensen, 1991, Prentice Hall, 0-
13-629841-9.
• Object-Oriented Systems Analysis: A Model-Driven Approach, David W. Em-
bley, Barry D. Kurtz & Scott N. Woodfield, 1992, Prentice Hall, 0-13-629973-3.
• Patterns discussion mailing lists, GOF y otros, 1995.
• Asistencia Técnica para la Mecanización de la Policía Local de Logroño, Ri-
cardo Devis, 1994, Infoplus SL.
• Object-Oriented Software Engineering: A Use Case Driven Approach, Ivar
Jacobson, Magnus Christeron, Patrik Jonsson & Gunnar Övergaard, 1992,
Addison-Wesley, 0-201-54435-0.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 136
BASES DE DATOS ORIENTADAS-A-
8
OBJETOS
E
n alguno de los cursos de Tecnología de Objetos que imparto muestro una
transparencia con el título “Diseño de Bases de Datos” para seguidamente,
tras una estudiada pausa, superponer otra con una señal de prohibición, a
la vez que afirmo categórico: “No hay diseño sustantivo de bases de datos”. Y
punto: nada que añadir. Naturalmente el buscado efectismo intenta comunicar que
si en Tecnología de Objetos el abismo (gap) semántico entre Análisis y Diseño se
difumina, tal solapamiento debiera ampliarse a las etapas de codificación y al-
macenamiento. O sea, las entidades que se encuentran en la fase de análisis de
requerimientos se corresponderán biunívocamente con clases/objetos en las de
análisis y diseño, para después mantener su integridad modular y conceptual tan-
to en la implementación como en el esquema de persistencia. Para abreviar: el
objeto finalmente almacenado en la Base de Datos se corresponderá estructu-
ralmente con aquél encontrado en el dominio del problema, significando así que
queda sin sentido el trabajo de descomposición en estructuras de datos asumi-
bles por gestores concretos que luego habrán de ser nuevamente compuestas
para su uso efectivo. La cuestión es ¿desmontaría usted cada noche su coche en
piezas para reconstruirlo en la mañana siguiente, cuando desee usarlo? Eviden-
temente no 29, al menos directamente. El enfoque más elegante sería dejar que un
guardacoches responsable se ocupara del auto, sin necesaria sujeción a un gara-
je dado, y nos lo entregara cada mañana en perfecto estado de funcionamiento. Y
es aquí donde aparecen las bases de datos orientadas-a-objetos en sus distintas
graduaciones.
29
Cuando formulo esta pregunta ante equipos de análisis y diseño estructurados la respuesta
invariablemente es: “¡Por supuesto! ¡Es lo que hacemos a diario!”
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 137
• Bases de Objetos Puras (ODBMSs: Object DataBase Manager Systems): Los
productos que se enmarcan en esta categoría usualmente ofrecen la misma
funcionalidad que puede encontrarse en gestores relacionales maduros (inte-
gridad, concurrencia, distribución, persistencia, recuperación de errores, etc.),
con la particularidad de basarse en un estricto modelo de objetos, significados
por OIDs (Object Identifiers). La naturaleza avanzada de los mismos procura
además, por lo general, servicios de migración de objetos, soporte de trabajo
en grupo, transacciones distribuidas, etc.
30
El equivalente gastronómico es claro: el cocinero eficaz es, a efectos del comensal, un “wrap-
per” entre los simples alimentos y las pesadas composiciones culinarias. Evidentemente, cuando
las viandas poseen calidad, sabor y textura per se, el cocinero se troca en mero transportista:
vamos, la antítesis de la nouvelle cousine.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 138
lacional/es a que accede, separando así, de una forma adecuada para los su-
fridos mantenedores de aplicaciones, la oscura parte tabular de los volátiles
dibujos de ventanas. Hay que decir, empero, que subsisten -naturalmente- los
problemas de eficacia relacionados con la gestión de información compleja: un
vale de entrada y el abandono de andrajos facilitan la asistencia a la ópera, pe-
ro en absoluto ayudan a la inmersión musical en las obras.
Qué producto usar depende en gran medida del lenguaje, de las herramientas,
del tipo de aplicación. Y aunque lo usual es empezar por el ámbito más relacional
e ir escalando características de objetos según se encuentran problemas o impo-
sibilidades, yo recomendaría comenzar con las bases de objetos puras e ir ba-
jando a esquemas con mayor componente relacional conforme no se cumplan las
características de eficacia, rapidez, etc. Deseadas. Pero vayamos a la parte
humana de los objetos.
Seguro que los programadores, como clase, albergan toda suerte de deseos no-
civos, pero entre ellos uno destaca por su interés morboso: el de liberarse de las
repetitivas codificaciones de acceso y recuperación de datos en bases de datos.
Si, de acuerdo con el esquema involutivo en espiral (de fuente o de piscina) de
las fases de análisis y diseño, la mayor parte del tiempo se pasa intentando gene-
rar un interfaz limpio de clases para su implementación, ¿por qué no dedicar el
tiempo restante a la codificación algorítmica inteligente, en vez de tratar con as-
pectos que podrían ser en gran medida mecanizados o, cuando menos, obviados
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 139
por sistemas de gestión de más alto nivel? La respuesta a la pregunta retórica es
obvia. El lector se cuestionará, empero, el calificativo “morboso”: lo cierto es que
la solución de las cuitas aquí planteadas pasa por una degradación de la profe-
sión misma de programador, cuya funcionalidad básica ha sido, tradicionalmente,
trasladar a código los resultados exactos de la fase de diseño. Si, con el nuevo
esquema del ciclo de vida del software, la codificación queda grandemente susti-
tuida por la lectura y el reuso de clases insertas en bibliotecas y entornos-marcos,
y además prácticamente se elimina la codificación final de almacenamiento, ¿qué
queda para el programador? ¿No resulta más rentable y efectivo, más aún te-
niendo en cuenta el gran acervo actual de herramientas software, que el mismo
diseñador traslade al código los resultados del diseño? Edward Berard afirma
que la figura del programador habrá de ser sustituida por la del “Analista del Do-
minio del Problema Orientado-a-Objetos” (OODA: Object-Oriented Domain Ana-
lyst). Tal presunción es un tanto efectista, pero la idea subyacente es prudente-
mente razonable. De cualquier forma el hecho es simple: el programador tiende a
desear un gestor de almacenamiento transparente (por invisible), o cuando me-
nos translúcido. El presupuesto inicial es sencillo: el manejo de instancias de ob-
jetos en memoria ha de ser igual o muy parecido al manejo de los mismos obje-
tos en un espacio de almacenamiento físico. Así, si consideramos que la memo-
ria es el almacenamiento primario (AP) y, verbigracia, el disco el secundario
(AS), el esquema ideal de cosas pasaría por considerar que los objetos (instan-
cias) pueden, merced a mecanismos muy simples, pasear entre AS y AP consi-
derando éstos como zonas de un hábitat global para nuestras instancias.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 140
y su capacitación para asumir características persistentes. Al decir “ortogonal” se
pretende indicar una relación similar a la de dos ejes perpendiculares en un pla-
no, representativos de distintas dimensiones y, por ende, independientes. La di-
cotomía queda reflejada en los siguientes distintos enfoques:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 141
tente de tipo agregado con identificador “miFamilia”, las instancias concretas
significadas por variables en nuestro objeto “miTio” se trocarán también en
persistentes. La persistencia se perderá cuando la instancia deje de ser apun-
tada por objetos persistentes (cuando, por ejemplo, “miTio” sea expulsado de
“miFamilia” por crápula). Naturalmente este enfoque es el preferido por los
programadores, porque convierte en invisible la gestión de almacenamiento.
Desgraciadamente, también, sus implementaciones actuales muchas veces no
se ajustan a lo requerido.
Bien, bien. Las cuestiones prácticas son: ¿realmente funcionan las Bases de
Objetos? ¿Facilitan las tareas de codificación y, por ende, favorecen la ejecución
de proyectos? ¿La velocidad y eficacia son aceptables? ¿Puedo contar, al
menos, con las mismas características disponibles en el sector relacional?
¿Puedo ... ? Sí, sí, sí, sí y ... err ... no. La tecnología anda en buena medida
renqueando tras los productos comerciales, así que los esquemas de
persistencia, recuperación de errores, versionamiento, concurrencia, integridad
referencial31, etc. dependen del producto en cada caso elegido. Mi experiencia
señala que los conceptos que aquí se han apuntado, siquiera someramente, son
asimilados con cierta eficacia cuando pueden ejemplificarse aplicándolos a un
producto concreto. La comprehensión aumenta cuando los mismos ejemplos se
refieren a porciones conceptuales de una aplicación homogénea. Así que lo mejor
será emplazar al lector para que use (y abuse) de una Base de Objetos
comercial. Bueno: la intención es lo primordial.
Los interesados en las cuestiones aquí esbozadas pueden acercarse por el grupo
de noticias de usenet “comp.databases.object”, excelente punto de partida para
novicios, donde encontrarán interesantes discusiones e información práctica de
uso de productos. Las típicas preguntas, por otro lado, sobre productos comercia-
les relacionados con las Bases de Objetos obtendrán su respuesta en la FAQ
informal del grupo que, con el calificativo de mini-faq, mantiene y actualiza regu-
larmente Tim Harvey. Yo mismo mantengo, de acuerdo con Tim, una copia de
esta mini-faq en “http://www.well.com/user/ritchie/mini-faq.html”.
31
Incidentalmente cabe notar que, como en otros ámbitos, la mejor manera de solucionar los
problemas de integridad referencial es precisamente ignorarlos. GemStone, por ejemplo, impide
la eliminación efectiva de cualquier objeto apuntado por otro, posponiendola hasta que el objeto
quede totalmente desreferenciado y entre en marcha el recolector de basura.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 142
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 143
CONSIDERACIONES PRÁCTICAS
9
L
a generación de aplicaciones, en su justa acepción de construcción de mo-
delos representativos de sistemas de información con funcionalidad en el
mundo real, ha experimentado cambios sustanciales en los últimos años
debido, sobre todo, a la hiper-influencia de los entornos gráficos de usuario que,
de forma necesaria pero abruptamente demoledora, han redefinido los roles per-
sonales clásicos respecto del uso de los aplicativos software. De esta manera, no
se da en la práctica una distinción clara entre programas finales (v.b.: MS Word
for Windows), herramientas de ayuda al usuario (v.b.: macros o shortcuts), herra-
mientas verticales de desarrollo asistido (v.b.: wordbasic, el "lenguaje de progra-
mación de MS Word"), etc. La patente exigencia del mercado resulta, por otro
lado, meridianamente clara: aplicaciones "amigables" (desafortunada traducción
de "friendly") basadas en sistemas gráficos multi-ventanas, apoyados en siste-
mas operativos o shells con capacidades para compartir, o al menos simular
compartir, tareas y procesos. Esta serie de circunstancias, tan sucintamente so-
brevoladas, ha conducido a claros desajustes en los esquema de desarrollo que,
finalmente, se han asentado sorprendentemente como "estándares implícitos de
facto" en la mayoría de las empresas de programación. Así, por ejemplo, las
herramientas de desarrollo se han transformado (o pretenden hacerlo) en "entor-
nos visuales de desarrollo" (bajo la irónica mirada de los expertos en auténticos
lenguajes visuales, cuyas batallas y gestas discurren en la más alejada ucronia de
aquéllos) donde los modelos de información se unen de forma "flexiblemente in-
disoluble" (según afirma una conocida empresa del sector, rea de crimen linguís-
tico-publicitario) y todo resulta "drag-n-drop", "apropiado para RAD" (rapid appli-
cation development), "idóneo para RPD", etc.
Hasta aquí pudiera parecer que el autor mantiene una absurda batalla contra los
entornos gráficos: ¡nada más alejado de la realidad! En realidad el firmante es un
acérrimo defensor de los entornos gráficos de usuario (y actualmente de los sis-
temas WIMP, tan viejos en el tiempo), pues estos tienden (y desgraciadamente en
muchos casos sólo tienden) a generar aplicativos más intuitivos en los que la ton-
tería, si realmente la hay, es más evidenciable. Lo que al fin se lamenta es la falta
de normalización de estructuraciones básicas que permitan desarrollos gráficos
modulares no basados únicamente en su propia y discutible representación visual
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 144
(sorprende, por ejemplo, constatar que no existen estándares en la confección de
cuadros de diálogo, en la arquitectura de aplicaciones gráficas, en la disposición
de controles visuales, etc.). Se generá, así, lo que Kafka llamaba "El Pozo de Ba-
bel" y que, en esencia, es un acopio de procedimientos propietarios en un es-
quema recolectivo que podríamos llamar de "basurero", del que la fuerza del mer-
cado y mayormente de la publicidad rescatan algunos productos, con toda su
carga de decisiones y soluciones particularizadas.
La propia arquitectura inducida en los aplicativos software por los sistemas gráfi-
cos, usualmente restringida a esquemas monomodales, origina graves desajus-
tes en la concepción de la representación del sistema de información a modelar:
la secuencialidad (o la ilusión de secuencialidad) inducida por el esquema gráfico
soportado origina la necesidad de construir enlaces (links) entre estructuras de
datos, de manera que éstas puedan "comunicarse" (la profusión de vocablos "en-
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 145
trecomillados" no es en absoluto casual, como el lector habrá ya adivinado), pro-
duciéndose el curioso efecto de que las deficiencias de la arquitectura gráfica
ocasionan deficiencias en la información que sus componentes manejan, lo que a
la vez provocará un rediseño cada vez más pernicioso de los mismos interfaces
gráficos, que repercutirá de nuevo en la estructuración interna de la información, y
así hasta ... que el "schedule plan" obligue al lanzamiento del producto. En reali-
dad los enlaces que se generan son tan férreos que las aplicaciones resultantes
suelen ser "monolíticas", proporcionando una apariencia de diversidad similar a
la que tiene un recluso cuando, el primer día, recorre su celda en la oscuridad.
REFLEXIONES REBAJADAS
¿Existe una solución global para los problemas y deficiencias expuestos? ¡No,
por supuesto! Aún más: se diría que en absoluto es deseable un bálsamo de fie-
rabrás que restañe y cure todo lo curable, en lo que a software se refiere. Es difícil
pensar que la diversidad natural, difícilmente asimilable en su completitud, de los
sistemas de información pueda ser simplificada en un único esquema mecanicis-
ta. Lo que se pretende, al fin, con este modesto capítulo, es explicitar una serie de
criterios, decisiones y esquemas estructurales que habrían de conformar las ba-
ses estáticas y de comportamiento dinámico de un grupo mayoritario de sistemas
software, teniendo en cuenta que, puesto que tales circunstancias normalmente
serán presupuestos de migración entre tecnologías (usualmente de RT a OOT),
se habrá de ponderar más la inmediata practicidad tangible que la formalidad
huera del efectismo tecnológico, de dudosa utilidad en relación con una aproxi-
mación conscientemente simplificada cual es la presente.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 146
paradigma aplicado de orientación-a-objetos, no aportando, empero, ninguna
característica adicional de efectividad o seguridad en proyectos típicos de migra-
ción (en realidad el firmante trabaja casi siempre con esquemas no cósmicos y
hace uso intensivo de la herencia múltiple, pero tal no es de pedagógica aplica-
ción aquí).
El Paradigma M2VC
La arquitectura del sistema se basará en una matización del paradigma MVC que
denominaremos M2VC. En primer lugar atendamos a lo que MVC (siglas de Mo-
del View Controller) significa: se trata de la separación de los módulos de un sis-
tema software en tres capas: la del modelo, la de la vista y la del controlador, in-
teractuando de la siguiente forma: un objeto perteneciente a la capa del modelo
sólo puede ser accedido por un objeto perteneciente a la capa de la vista, que, a
su vez, envía y recibe mensajes del objeto controlador. Existe un objeto controla-
dor por cada aplicación activa, y es tal objeto el encargado de transformar las
arquitecturas subyacentes en estructuras orientadas-a-objetos, trocando las lla-
madas a funciones y eventos en mensajes comprensibles para las vistas. Aunque
el paradigma MVC se ha demostrado enormemente eficaz, no existe ninguna ex-
posición teórica del mismo que sobrepase, en esencia, las sucintas notas ante-
riormente expuestas, aunque sí se pueden examinar multitud de sistemas basa-
dos en el mismo. En realidad el enfoque MVC fue el adoptado, de facto, por
Smalltalk-80, y aparece omnipresente en los trabajos de Adele Goldberg y Alan
Kay. Este paradigma facilita sobremanera la independencia de un objeto respec-
to de su representación visual o interfaz con los usuarios, de forma que tales inter-
faces podrían variarse sin afectar apenas a la estructura de la aplicación. La única
desventaja que tal enfoque presenta es, a nuestro juicio, que las vistas son jerár-
quicamente anteriores a los objetos, de forma que no se producen llamadas a
objetos, sino a vistas que a su vez llaman a objetos: esto obliga a que, si se cam-
bia un interfaz, deba modificarse el código de la llamada al mismo en la aplica-
ción. Para solventar esta situación hemos decidido aplicar una matización de es-
te enfoque que nosotros denominamos M2VC. Se trata, en definitiva, de que las
llamadas a las vistas las gestiona el objeto en sí. De esta manera, todos las cla-
ses tienen acceso a una función miembro que genéricamente denominamos "dia-
log()" o "dialoga()", que se hace "virtual" en la clase base cósmica "BaseObjeto" y
que permite acceder al interfaz apropiado de cada objeto con independencia del
conocimiento de su tipo exacto. Así, el cuerpo típico de tal función en una clase
dada responde al siguiente esquema:
miClaseModelo::dialog()
{
new DlgClaseModelo( controlador->getFocus(), this );
}
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 147
Esto es, se crea un objeto de tipo vista (derivado, en nuestro caso, de BaseDia-
logo), no persistente, al que se la pasa como parámetros la vista que actualmente
retiene el focus en el entorno gráfico (para poder "ahijar" la nueva vista), además
de un puntero al mismo objeto del modelo para que la nueva vista lo pueda asimi-
lar como el puntero al modelo que se cita en el epígrafe Gestión de Objetos a tra-
vés de Vistas. La ventaja de esta matización es que si se cambia la vista a través
de la que se accede a un objeto de una clase dada, únicamente habrá que cam-
biar la implementación de tal clase, sin tocar en absoluto el código de la aplica-
ción. Y aun, en un esquema de "Constructores Virtuales" de vistas, ni siquiera
habría que cambiar la implementación de la clase modelo, sino añadir un nuevo
objeto estático de tipo vista a la cadena de vistas asociada a una clase dada,
aunque este último enfoque es excesivo para una primera aproximación a
C++/OOP/OODB.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 148
la gestión de vistas. Naturalmente, también, podría haberse obviado tal aproxima-
ción y trabajar con un esquema dinámico (y voluntario) de dependencias, pero la
realidad es que el primer esquema permite montar, como una mera disgresión o
curiosidad, el segundo, de forma que no hay contradicción ni solapamiento: úni-
camente comportamiento práctico por defecto. De esta manera existe una vista
que calificamos de Vista Principal de la Aplicación y que directamente depende
del entorno gráfico elegido en sí. Esta Vista única (de acuerdo con las normas
CUA) contiene menús desplegables y se constituye en "padre" de todas las de-
más vistas de la aplicación, con el siguiente esquema: cualquier vista creada di-
rectamente desde la Vista Principal mantiene a ésta como "padre" y la vista en
cuestión pasa a ser la "hija" de aquél (quizá en un entorno menos masculino de-
beríamos hablar de "madre" e "hijo", o de "progenitor" y "progenie", pero en este
caso dejaremos que el lenguaje, con sus géneros y traducciones, nos arrastre).
Así, repetimos, la Vista Principal produce Vistas Primeras, directamente depen-
dientes de aquélla; pero éstas, a su vez, pueden generar Vistas Secundarias (las
adjetivaciones de las vistas son, por supuesto, únicamente pedagógicas), y éstas
generar otras, y así ad nauseam (o hasta que "se acaben los recursos", según
rezan algunos inopinados mensajes de ciertos entornos gráficos -lisez MS Win-
dows). De esta manera resulta que, puesto que cada "padre" conoce a sus
"hijas", éstas habrán de conocer a su "padre" (noténse las características educa-
cionales y canallescamente sociales de esta aserción). En un entorno gráfico úni-
camente una vista puede retener el focus en un momento dado: esto significa que
siempre hay una única vista localmene activa: o sea, los mensajes que dirijamos
al sistema se "focalizan"" sobre la vista activa y de ésta se dice que "retiene" o
posee el "focus" (foco, en un castizo menos latino). Los mensajes a otras vistas
son generalmente, pues, ignorados o sobreestimados. La aparición de una nueva
vista (siempre dependiente de una anterior, o "padre") origina que el focus se
traspase a ésta, así como la misma podría automáticamente traspasarlo a otra de
la que dependa. En un arquitectura modal el focus es retenido por una vista mien-
tras no se destruya (con lo que el focus pasaría automática al "padre" del que de-
pende) o cree una vista depeniente a la que traspasarlo. A efectos de codifica-
ción esto significa que si en una línea del programa se produce una llamada, dire-
cta o indirecta, a una vista derivada, ésta asumirá el focus y no lo devolverá a la
vista en que se produce la llamada hasta que desaparezca. Naturalmente esto
sugiere e invoca una inevitable secuencialidad en el esquema de mensajes entre
vistas (y aun entre objetos). Significa, también, que la secuencialidad del código
es absolutamente determinista: esto es, tras la línea que llama a la vista (en un
ejemplo típico con C++):
void ClaseCualquiera::llamaAVista()
{
DialogoCualquiera* miDialogo = new DialogoCualquiera();
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 149
el control indefectiblemente, tras la desaparición del diálogo, pasará a las si-
guientes líneas, que podrían perfectamente ser las siguientes:
de tal manera que se podría interrogar al diálogo por los objetos o estados de
éstos que nos interesen. Este esquema fuerza un tipo de codificación demasiado
basada en las dependencias casuales entre los distintos tipos de vistas. Obliga,
también, por su propia naturaleza basada en dependencias jerárquicas, a cance-
lar una vista para poder acceder a otras o, en el peor de los casos, a incluir en
una vista controles gráficos que permitan acceder a otra nueva vista sin cancelar
la primera. Por supuesto que esta última estrategia, usada de forma intensiva por
la práctica totalidad de las empresas de desarrollo de software, es particu-
larmente nociva y origina con demasiada facilidad vistas o interfaces en absoluto
reutilizables fuera del contexto para el que fueron creados. ¿Qué ofrece, por otro
lado, el enfoque multimodal? Pues sencillamente la posibilidad de traspasar vo-
luntariamente el focus desde una vista a otra cualquiera, actualmente visible o no
(normalmente mediante el uso del ratón, pero también del teclado u otros me-
dios). Esto causa que los interfaces no habrán de depender de las relaciones que
entre ellos se establezcan dinámicamente, reforzando, al descontextualizar su
uso, la reutilizabilidad práctica de los mismos. Se derivan, a la vez, nuevas e im-
portantes consecuencias con respecto de la secuencialidad del código: una línea
típica de llamada a una vista (en C++) sería la siguiente:
void ClaseCualquiera::llamaAVista()
{
new DialogoCualquiera();
}
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 150
concreta o por una más general desasignación (el cierre de la aplicación entera).
Así, el código de destrucción de una vista estaría -naturalmente- escondido en el
destructor de ésta (y volvemos a la nomenclatura C++), de la forma:
DialogoCualquiera::~DialogoCualquiera()
{
// desasigna la memoria dinámica
// asignada en el constructor
}
Pero, ¿quién llama a este destructor? ¡El usuario! Esto es: el usuario manda un
mensaje a la vista requiriendo su desaparición bien directamente (lanzándole un
mensaje "ciérrate" o "close"), bien indirectamente (lanzando un mensaje "close" a
cualquiera de sus padres o accionando una operación de la misma -típicamente
"aceptar" o "cancelar"-). o aun lanzando una orden de cierre masivo de vistas
(como la procurada por el cierre de la aplicación). Naturalmente el esquema antes
apuntado se mantiene, y, por ende, cualquier Vista conoce a sus hijos (mantiene,
en definitiva, una colección de punteros a los mismos, en lenguaje coloquial o de
programador). Bien: no hay problemas con la memoria, pero se plantean dos nue-
vas cuestiones: ¿qué ocurre con los objetos que una vista ha gestionado, leído y/o
modificado? ¿qué ocurre, por otra parte, cuando en una vista se leen o modifican
objetos o algunos de los atributos de estos que, a su vez, están siendo leídos y/o
modificados por otras vistas, o aun por otras vistas en otros terminales o clientes?
Bien, esta última cuestión es oportunamente tratada en el epígrafe dedicado a la
Gestión de Concurrencias, mientras que la respuesta a la primera perfectamente
corresponde al esquema multimodal como solución aplicativa, pero será tratada
en detalle en el epígrafe dedicado a la Gestión de Objetos a través de Vistas. Y
este es el momento de anunciar que el "multimodo" es, de hecho, una generaliza-
ción del comportamiento "modal", por lo que lo establecido para aquél puede
perfectamente ser aplicado en éste, aunque no a la inversa.
Gestión de Concurrencias
El esquema de control de concurrencias se basa en que cada usuario de un obje-
to o grupo de objetos, identificado por el acceso único al interfaz de éstos, traba-
jará con un conjunto intermedio de punteros a los objetos de la base de objetos en
cada caso manejados. Se trata, en definitiva, de una "shallow copy" (copia super-
ficial) de los objetos en cada caso utilizados por el usuario (naturalmente esto
incluye objetos simples a la vez que colecciones y, en general, objetos de tipo
agregado). Se trata, por tanto, de que cada interfaz, en correspondencia biunívo-
ca con el usuario único que lo accede respecto del terminal en que anida, utiliza
un objeto intermedio del mismo tipo que el objeto al que se intenta acceder, te-
niendo en cuenta que se trabaja en un entorno gráfico multiusuario y multimodal.
Los casos posibles son: un objeto simple (que puede contener enlaces navega-
cionales a otros objetos) y una colección, o agrupación de objetos (simples o co-
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 151
lecciones a su vez). En cualquiera de los casos, en orden a la arquitectura gráfica
elegida (el paradigma matizado M2VC), tales objetos intermedios serán maneja-
dos únicamente por las vistas (interfaces gráficos de los objetos correspo-
ndientes), pudiendo ser o no persistentes, aunque una elemental prudencia inicial
aconseja su inclusión en la memoria transient, toda vez que este sistema no ne-
cesita de persistencia de objetos intermedios para recuperar fallos en el sistema.
Veamos los comportamientos por separado:
Los dos casos detallados ofrecen, empero, un problema relacionado con el bo-
rrado de objetos: qué ocurre si se intenta acceder mediante el puntero que mane-
ja una vista a un objeto que ha sido físicamente borrado por mediación de otra
vista. Bien, este caso simplemente no se puede producir. Veamos el esquema:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 152
Eliminación de objetos: en ningún caso se producirá la eliminación física
directa de los objetos persistentes, sino que se utilizarán recolectores de
basura (garbage collectors) a aplicar sobre objetos desreferenciados. Es-
to supone que el acceso desde una vista a un objeto (vía puntero) está
siempre garantizado, pues al ser apuntado precisamente por la vista tal
objeto no puede desaparecer, manteniendo a la vez la posibilidad de que
el mismo objeto pueda ser aparentemente borrado o apartado del interfaz
accesible por un usuario dado o un conjunto de éstos. ¿Cómo se consigue
ésto? Se pueden dar dos casos: si el objeto está en una colección de uso,
se procede a su extracción de la misma desde el interfaz de ésta y se de-
posita bien en el extent (para su posible reutilización ulterior) bien en una
colección genéricamente denominada "basurero" (de la que será física-
mente eliminado cuando quiera que ningún otro objeto lo referencie); si el
objeto está únicamente en el extent, la eliminación consistirá en su inser-
ción (en la inserción de un puntero que lo apunte) en un objeto "basurero".
Naturalmente la eliminación aparente o no de un objeto generará una inci-
dencia interna auditable, según se detalla en el epígrafe Incidencias de
Usuarios.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 153
class BaseDialogo : public Dialog {
public:
boolean estaBloqueado( BaseObjeto*, long = 0 );
private:
// colección de objetos bloqueados en
// la OODB transient (en memoria primaria)
BaseColeccion* bloqueosActivos;
// sigue resto descripción de clase
};
if ( estaBloqueado ( BaseObjeto* ) )
modelo->set(...);
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 154
pudiéndose sustituir la doble condición por una función única en la clase base
"BaseDialogo", de la misma forma que se ha hecho con la función "estaBloquea-
do( BaseObjeto* )".
Este es, a nuestro parecer, el enfoque menos intrusivo, pues no afecta al modelo
de la aplicación, sino únicamente a las vistas que lo manejan.
class DialogoCualquiera {
private:
ObjetoCualquiera* punteroAlObjeto;
// resto representación interna diálogo
};
donde la lectura se realizaría siempre por medio de una función que, por razones
que se evidenciarán en el epígrafe Actualización de Vistas, denominaremos "re-
fresca":
void DialogoCualquiera::refresca()
{
// editLineN son miembros privados de tipo EditLine
// y representan campos gráficos de edición de textos
editLine1->putText( punteroAlObjeto->getAtributo1() );
editLine2->putText( punteroAlObjeto->getAtributo2() );
// etc., etc.
}
mientras que los accesos para modificación (y aquí se obviarán los aspectos re-
lacionados con la concurrencia, como se ha hecho respecto de la lectura) se codi-
ficarán en las funciones (callbacks) a ser llamadas como resultado de la acción
sobre un elemento gráfico (típicamente un botón):
void DialogoCualquiera::callbackOkButton()
{
punteroAlObjeto->set( /* actualización de atributos */ );
// termina el diálogo y pasa el objeto
// al diálogo padre
getParent()->admite( punteroAlObjeto );
}
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 155
Pero este simplificado esquema origina una grave dificultad: como se ha visto la
actualización del modelo (objeto) al que apunta cada vista (aunque también se
pueden dar vistas multimodelo, sin que en absoluto cambie el esquema de actua-
ción) se realiza mediante una función, usualmente denominada set(...), que efecti-
vamente cambia los atributos (o datos miembros) del objeto apuntado. Pero, en el
caso más general, posiblemente una vista dependa de otras vistas "padres" de
ésta, de manera que un cambio en el estado del objeto (u objetos) que la vista
maneja haya de ser validado por cualquiera de los objetos apuntados por una o
más de las vistas "padres", y si en algún caso tal validación resultara negativa, los
cambios habrían devenido irreversibles, por lo que el sistema se encontraría con
un cul de sac de sesgada solución. Imagínese, por ejemplo, que una Vista es el
interfaz de una colección de HombresCuyoNombreEmpiezaPorX, y que de tal
deriva (o se ahija) una vista que modela objetos del tipo HombreCualquiera. Si en
esta última vista se cambian los atributos de un determinado HombreCualquiera,
perteneciente originariamente a la primera colección, y el nuevo atributo de nom-
bre, ya irremediablemente cambiado, no empieza por X, la vista que accede a la
colección rechazará la inserción o actualización de tal objeto en la colección y no
podrá, por otro lado, recuperar el antiguo nombre, produciéndose un deadlock
(bloqueo mortal, en la más pura tradición hollywoodense) cuya posible resolución
será naturalmente oscura para el usuario. ¿Cómo evitar esto? Pues establecien-
do un mecanismo que permita el "backtracking" o vuelta atrás a partir de una mo-
dificación de atributos (esto es, un acceso de tipo escritura, siguiendo la más tra-
dicional nomenclatura de gestores de bases de datos). Tal mecanismo puede
implementarse, básicamente, mediante las tres formas distintas siguientes (o, por
supuesto, por cualquier combinación de ellas):
• versionamiento (versioning)
• transacciones anidadas (o bloqueos anidados con roll-back)
• copias temporales de trabajo
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 156
El versioning representa un esquema general que incluye, como concreción, el de
las copias temporales de trabajo y, por tanto, parece el más adecuado para ges-
tionar "versiones temporales" de objetos, que en cualquier momento pueden "ol-
vidarse" (forget) o, más bien, sustituir de forma efectiva a la anterior (aunque sin
perder la información de partida). El versioning, empero, necesita de unos gesto-
res típicamente imbricados con bases de objetos, de manera que no es natural-
mente accesible desde el modelo relacional, y a pesar de resultar la opción más
elegante, clara y rápida, como quiera que obligaría al uso de determinadas herra-
mientas de implementación y restringiría, a efectos prácticos, los resultados del
diseño, hemos optado por considerar como eminentemente práctica la última op-
ción: copias temporales.
Únicamente hace falta una copia temporal por cada objeto que se esté manejan-
do en un momento dado, lo que equivale a afirmar que se necesita, al menos, una
copia temporal de cada objeto accesible desde cualquier vista activa. Esto inme-
diatamente sugiere que no es responsabilidad en sí del objeto original mantener
un tal sistema temporal, sino más bien de las vistas que actualmente lo acceden.
De esta manera resulta que será la vista la que, en una secuencia más de su
construcción (y nótese que estamos siempre hablando de vistas no-persistentes)
creará un objeto temporal del mismo tipo de cada objeto que maneja y copiará en
él sus mismos atributos (presumiblemente, en C++, mediante un constructor de
copia o por la sobrecarga de un operador de asignación, o por la aplicación de
una función virtual de clonado). El código sería el siguiente:
DialogoCualquiera::DialogoCualquiera()
{
// asigna valores iniciales a atributos de la vista
// seguidamente crea un objeto temporal
punteroObjetoTemporal = punteroAlObjeto->clone();
// sigue resto constructor vista
}
De esta manera se sobreentiende que cada vista poseerá como atributos (como
datos miembros privados, en C++), aparte del puntero a los objetos que maneje,
de acuerdo con el paradigma MVC, sendos punteros a los objetos temporales
que se clonen a partir de éstos, de forma que puedan ser accedidos desde cual-
quier lugar dentro del protocolo de descripción de la clase y con una formalización
similar a la siguiente:
class DialogoCualquiera {
private:
BaseObjeto* pObjetoOriginal;
BaseObjeto* pObjetoTemporal;
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 157
// sigue resto descripción clase
};
Pero esto plantea un nuevo problema de eficacia: una copia por objeto es razo-
nablemente efectiva y no supone penalización en tiempo de ejecución, siempre
que el objeto a copiar no sea de tipo agregado. Esto es, el sistema de copia fun-
ciona mientras que se aplique a objetos simples y no a colecciones, pues en és-
tas se produciría una copia de cada uno de los objetos contenidos en la colec-
ción, y tal es simplemente aberrante. ¿Quiere esto decir que, al no usar de obje-
tos temporales, no hay posibilidad de roll-back en colecciones? ¡Efectivamente!
Y, de hecho, éste es el esquema general normalizado en entornos gráficos ( y
bien se dice general porque podría darse el caso de una aplicación concreta del
esquema de copia en colecciones de número determinado y corto de elementos,
pero tal no sería sino lo mismo que aplicar las copias a una secuencia también
bien determinada y corta de objetos manejados por una vista). En resumen: las
copias temporales sólo se aplicarán a objetos simples de tipo no-agregado. Hay
que tener en cuenta, no obstante, que usualmente una vista manejará un solo ob-
jeto del modelo, de forma que las colecciones las manejarán vistas especiali-
zadas, mientras que el acceso a los objetos concretos contenidos en la colección
se realizará mediante vistas también especializadas para los mismos: no hay,
pues, solapamiento de esquemas. Cada vista conoce, pues, por su propia espe-
cialización, si ha de aplicar o no el esquema de copia.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 158
mente denominada set(...), que sería llamada tras pulsar el botón adecuado, co-
mo por ejemplo:
void DialogoCualquiera::aceptar()
{
pObjetoTemporal->set( atributo1, atributo2, atributo3 );
// ...
}
la cancelación, por otro lado, únicamente causaría la salida del diálogo sin haber
llamado a tal función. Parece evidente, así, que la modificación de atributos resul-
ta más elegante, clara e intuitiva mediante el esquema de modificación global.
Pero si la modificación se produce al final, y piénsese que el comportamiento es-
perado (que no normalizado, desafortunada o afortunadamente) de un típico bo-
tón "aceptar" es que la vista se cierre, ¿por qué no aplicarla directamente sobre
el objeto original? Pues, básicamente, porque el proceso de validación depende-
rá, de acuerdo con los presupuestos arquitectónicos en que se basa la presente
aplicación, del objeto, jerárquicamente anterior, que posibilita la modificación de
éste: se aplica, así, el comportamiento notado anteriormente sobre colecciones y
reflejado en el ejemplo "HombresCuyoNombreEmpiezaPorX". Pero, si no se pro-
duce validación, ¿qué ocurre cuando se cierra el diálogo? Pues que tal vista (diá-
logo) habrá de "enviar" a la vista "padre" desde la que se generó el par compues-
to por el ObjetoOriginal y el ObjetoTemporal, de forma que ésta, tras acceder al
modelo al que a su vez apunta, pueda decidir si se produce o no actualización de
los atributos conforme a lo requerido por el usuario, o más bien se cancela tal
modificación y se notifican al usuario los problemas encontrados. En C++, la codi-
ficación se parecería a la siguiente:
void DialogoCualquierHijo::aceptar()
{
pObjetoTemporal->set( /* lista de atributos */ );
// getParent() devolvería un puntero a la vista padre
// mientras que parDeObjetos(...) sería, típicamente,
// la instanciación de una plantilla del tipo
// par< class T, class T >,
// o también una colección de dos elementos
getParent()->admite( parDeObjetos( pObjetoOriginal,
pObjetoTemporal ) );
}
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 159
// una cancelación)
// entonces simplemente no hace nada
// y luego destruye el temporal
if ( !( par.sonIguales() ) &&
!( par->getCopia()->esBlanco() ) )
// si los objetos son distintos entonces
// chequea la validez de las
// modificaciones realizadas en el temporal (o copia)
if ( chequea( par->getCopia() ) )
// y si el chequeo es válido, entonces
// copia los atributos del objeto
// temporal en el original (suponemos definido el opera-
tor=)
getOriginal() = getCopia();
// se destruye después el objeto temporal
delete getCopia();
// seguidamente realiza con el objeto original ya modifica-
do
// las acciones pertinentes, como por ejemplo su inserción
// en una colección dada, de la forma:
// miColeccion |= getOriginal();
}
Como fácilmente se aprecia, buena parte del código (y por ende, del comporta-
miento) aquí mostrado sería común para todas las vistas, de manera que se po-
dría, y de hecho así se hará, traspasar a la clase base de todas las vistas: Base-
Dialogo, mientras que cada vista poseería una función virtual chequea(...) que se-
ría llamada desde BaseDialogo::admite(...), aunque esto deberá ser examinado
con más detenimiento en tal clase base.
Incidencias de Usuarios
Toda modificación o alteración de los elementos del sistema deberá ser registra-
da, de manera que quede constancia auditable de las mismas. Esto aquí se con-
sigue merced a un esquema de gestión de lo que en adelante llamaremos inci-
dencias del sistema, o simplemente Incidencias, unido al mecanismo general de
autorizaciones de acceso imbricado en lo que se denominan Perfiles.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 160
pues tal política desdibujaría la esencia básica del sistema (por ejemplo, si se
constata que una persona vive en tal domicilio, distinto de aquél que se mantenía
por el sistema, no ha de producirse una mera actualización del objeto Domicilio
referenciado por persona, sino que lo que se espera, y este es realmente el com-
portamiento de la aplicación, es que se genere una nueva relación de domicilio
con fecha (piénsese que la mayoría de la información asumida por el usuario final
como parte de sus necesidades negociales puede poseer momento cronológico
de entrada, pero difícilmente observará momento de finalización: es normalmente
constatar la caducidad de una determinada información). Este esquema de
modificación por error resulta en que cada modificación (y una eliminación se
entiende como tal) generará una Incidencia que recogerá el objeto Original, el
objeto Modificado (ambos encapsulados en un objeto de tipo ParDeObjetos), el
momento de la Modificación y un posible comentario, automático o no, razonando
la incidencia:
class IncidenciaAuditable {
friend class DlgIncidenciaAuditable;
public:
IncidenciaAuditable();
IncidenciaAuditable( ALTiempo*, Usuario*,
ParDeObjetos*, BaseString* = 0 );
~IncidenciaAuditable();
void dialoga();
private:
ALTiempo* crono;
Usuario* usuario;
ParDeObjetos* parDeObjetos;
BaseString* comentario;
set( ALTiempo*, Usuario*,
ParDeObjetos*, BaseString* = 0 );
};
{bmc incidaud.shg}
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 161
Actualización de Vistas
Se trata de que al modificar un objeto, siempre a través del interfaz público de
éste (usualmente mediante la función set( ... )) y mediante mensajes dirigidos a
través de la correspondiente vista que lo referencia, el resto de vistas deberían
ser convenientemente actualizadas para reflejar tales cambios, provocados por el
mismo usuario o por otros en otros terminales. Examinemos estos dos casos por
separado, pues cada vez que una vista expresamente realiza una modificación en
un objeto (agregado o no), se pueden seguir dos políticas de actualización del
resto de las vistas, dependiendo de las capacidades del entorno en que el siste-
ma se asiente:
• local: las modificaciones sólo se comunican a las vistas del terminal que
directamente las generó. El resto de los posibles terminales opera con
vistas desactualizadas en tanto no se genere un refresco de éstas debi-
do a una condición de salto (bien mediante un timer, bien mediante che-
queos funcionales de atributos). Naturalmente el acceso desde uno de
tales terminales a un objeto modificado con posterioridad a su lectura
resultará en que el usuario trabaje con información distinta de la real, de
manera que puede llegar a modificar el objeto por el solo hecho de pul-
sar el botón aceptar con la información antigua. La ventaja, por otro
lado, es que no se producen largas secuencias de inactividad debido a
las modificaciones inter-usuarios en un entorno medio-grande.
En las presentes notas nos decidimos por el primer caso, la actualización local,
matizada por un mecanismo que impediría el solapamiento inadvertido de modifi-
caciones en objetos. Pero antes de nada examinemos lo que conlleva la modifi-
cación de objetos.
Existen dos tipos básicos de modificaciones, cualificadas en razón del tipo del
objeto a modificar: las de objetos simples y las de objetos de tipo agregado o
colecciones. En el caso de colecciones, las modificaciones se refieren a la varia-
ción de la estructura interna que las compone: esto es, a la adición y extracción
de elementos, junto con la creación y destrucción de objetos del tipo de la colec-
ción precisamente. Consideramos, pues, que la modificación de la representa-
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 162
ción interna de un objeto perteneciente a una colección se adscribiría al primer
caso, en su propia calidad de objeto simple. Examinemos ambos casos:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 163
¿cómo determinar qué vistas manejan objetos simples y cuales no?
¿qué tipo de mensaje de actualización hay que envíar y cómo habrá que
preparar a las vistas para que respondan al mismo? ¿Se dará algún
esquema de optimización de actualizaciones, a fin de no mandar el
mensaje de refresco a vistas que no lo necesiten? Bien, vayamos por
partes.
class Actualizacion {
public:
// constructor y destructor
Actualizacion( const TipoBaseObjeto&, BaseColeccion* );
~Actualizacion();
// objeto
TipoBaseObjeto getTipoObjeto();
// llama iterativamente a la función refresco
// de cada una de las vistas del terminal activo
// cuyo tipo coincida con alguno de los contenidos
// en la colección de tiposVistas
refresca();
protected:
private:
TipoBaseObjeto tipoObjeto;
BaseColeccion* tiposVistas;
};
class VistaPrincipal {
public:
static void refresca();
// sigue resto descripción clase
};
class BaseDialogo {
protected:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 164
//llama a VistaPrincipal::refresca();
virtual void actualiza();
// implementa polimorfismo en refrescos
virtual void refresca() {};
// sigue resto descripción clase
};
class BaseDialog {
private:
void actualiza( BaseObjeto* );
// sigue resto clase
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 165
class VistaPrincipal {
public:
static void refresca( BaseObjeto* );
// sigue resto clase
};
¿Se debe redefinir la función virtual refresca() en todos los descendientes de Ba-
seDialog, esto es, en todas las vistas de la aplicación? ¡No! Únicamente se pro-
ducirá tal redefinición en las vistas que gestionen objetos no simples, para evitar
así actualizaciones secuenciales masivas. La cualificación de tales vistas será
expresamente establecida por la documentación de diseño mediante la inclusión
o no de la redefinición de tal método.
class TipoDeSuceso {
public:
// establece el dato miembro "nombre"
set( const BaseString& main& );
private:
BaseString nombre;
// resto descripción clase
};
class TipoDeSucesoView {
protected:
void aceptar() {
// ...
set( const BaseString& );
// ...
}
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 166
// sigue resto descripción de clase
};
TipoDeSuceso miTipoDeSuceso;
miTipoDeSuceso.set( "Traición" );
class TipoDeSuceso {
friend class TipoDeSucesoView;
// sigue descripción de clase
};
Pero este enfoque plantea dos inconvenientes: por un lado se está ligando de
forma tajante el modelo de la aplicación a una vista determinada, de manera que
si se quiere cambiar de vista (de clase de vista) se deberá modificar la clase del
modelo; por otro lado, la declaración de "amistad" no trasciende a las posibles
clases derivadas de la vista, de manera que no se podría dar un comportamiento
polimórfico inmediato en los diálogos.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 167
tipoModelo, ... )", que podría ser utilizada por sus clases derivadas. Así, toda cla-
se de tipo diálogo debería derivar de "BaseDialogo" y también de nuestra nueva
clase "DlgBaseModelo", única para cada modelo, distinta de BaseDialogo en
tanto que no necesita de las características heredadas de la vista, sino que es un
cruce, a su vez, de funcionalidad con vista. Para intentar aclararlo, seguidamente
se ejemplifica:
class Etiqueta {
friend class DlgBaseEtiqueta;
public:
Etiqueta();
Etiqueta( const BaseString& );
~Etiqueta();
protected:
set( const BaseString& );
private:
BaseString* nombre;
};
class DlgBaseEtiqueta {
protected:
set( Etiqueta*, const BaseString& );
private:
Etiqueta* etiqueta;
};
Existe, pues, una opción óptima de seguridad arquitectónica para el sistema, pe-
ro quizá no sea la opción más adecuada para un primer proyecto de OOP/C++.
De esta manera, nuestro consejo es que se utilice un esquema simple inicial,
donde las funciones "set(...)" sean públicas en el modelo, y se acceda a ellas a
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 168
través de las vistas (cualesquiera que éstas sean) que lo manejen. La seguridad
se daría, así, a nivel de usuario y no a nivel de programación, según lo ya expre-
sado, pero este enfoque permite pasar, en futuras versiones (2.0, 3.0 o aun
6.3.7.4.9) al ya expresado de "Constructores Virtuales", sin apenas tener que va-
riar la codificación (únicamente habría que cambiar las llamadas a los constructo-
res por llamadas a la función de clonación usando del RTTI -RunTime Type Identi-
fication de C++. Seguidamente se podría pasar al esquema de herencia múltiple
si así se desea, aunque, como ya se ha expresado en otra sección, en la presente
arquitectura sólo se está usando, en aras de la simplicidad, de la herencia simple.
class Usuario {
friend class DlgUsuario;
private:
enum Acceso { sinAcceso, soloLectura, Total };
PersonaFisica* persona;
BaseString* nombre;
BaseString* contrasena;
// Colección de pares de objetos donde uno de ellos
// es la clave y el otro el objeto asociado.
// (la class VDictionary existe en C++/Views).
// En nuestro caso la clave sería un objeto de tipo
// vista (derivado de BaseDialogo), sobre el que se
// aplicaría el mecanismo RTTI para identificarlo,
// mientras que el objeto asociado sería el enumerador
// de Acceso.
// El interfaz del VDictionary sería moldeado a través
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 169
// de la vista DlgUsuario (clave también del mismo).
VDictionary* accesos;
};
Para saber qué usuario está activo en cada momento, a la clase ApplicationView
deberá serle añadida una función del tipo
ApplicationView::setUsuario( Usuario* );
ApplicationView( Usuario* = 0 );
class ApplicationView {
private:
static Usuario* usuario;
// sigue resto descripción sección privada
public:
static Usuario* getUsuario();
// sigue resto descripción sección pública
};
Dado, por otro lado, que todos los diálogos de la aplicación derivan de BaseDia-
logo, habría que hacer una modificación leve en el comportamiento de éstos:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 170
constructores) para que se modifique el nivel de "sinAcceso" al correspon-
diente para tal diálogo al usuario a obtener desde "Application-
View::getUsuario()".
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 171
Nuestro enfoque se basa en crear, si es que la OODBs comercial concreta no lo
provee implícitamente, tantos EPs como clases de modelo aniden en el presente
sistema, de tal manera que cada objeto creado será automáticamente insertado
en una Colección que representará el extent de tipo del mismo. Usualmente tales
extents serán accedidos por una clave alfanumérica, representativa del nombre
de la clase de objetos que manejan. Cuando un objeto se destruya será extraído
de su extent. Se perfila así el extent como un dato miembro estático de la clase
correspondiente, conocido por todos los objetos instanciados de la misma. No se
ha modelado expresamente esta funcionalidad porque algunas OODBs incluyen
tal comportamiento sin intervención del operador. Pero aunque los extents resul-
tan eficaces, no se puede trabajar con todos los objetos todo el tiempo: piénsese
que el extent agrupa a TODOS los objetos de un tipo dado: los ya no-usados, los
temporales, etc. De esta manera, la mayoría de los objetos son modelados a tra-
vés de colecciones que denominamos ColeccionesActivas, donde se insertan los
objetos (además de en el extent, siempre) con un significado concreto para tales
colecciones. Así, por ejemplo, una colección de agentes de policía en plantilla
contendrá únicamente objetos de tipo "AgenteDePolicia" que mantengan una re-
lación actual laboral con la Policía Local, conteniendo el extent de "AgenteDePoli-
cia" la colección total de "agentes", en plantilla o no. La extracción de un objeto de
una colección activa nunca significa la extracción del mismo del extent al que, por
su tipo, pertenece. Las ColeccionesActivas pueden ser consideradas, también,
como EPs, aunque como también estarán contenidas en un extent podrían ser
seleccionadas en tiempo de ejecución en función de un parámetro adicional o de
una actuación polimórfica. Nuestro enfoque, siempre en pos de la sencillez, será
calificarlas como EPs.
{bmc alcolact.shg}
void PoliciaView::itemMenuAgentesPlantilla()
{
miColeccionActiva->dialog();
}
Esquema de Consultas
El esquema habitual de consultas se basa en menus ad-hoc que conducen a in-
terfaces específicos que, en base a una selección un tanto arbitraria de atributos,
procuran un resultado conceptualmente pre-determinado aunque de extensión
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 172
variable. Naturalmente cada vez que se necesita información en nueva disposi-
ción es necesario acometer la generación de nuevos interfaces y modificar los
puntos de acceso (menús, controles, etc.). El enfoque a adoptar, sin embargo, en
la presente esquematización es esencialmente genericista y de planteamiento
basado en la reutilización del software ya generado, usando de los mismos inter-
faces utilizados para la lectura y modificación de los atributos de los objetos.
Esquema Teórico
{bmc querycol.shg}
class BaseObjeto {
public:
virtual SQLString SQL( const SQLString& ) = 0;
boolean estaVacio( BaseObjeto* objeto ) {
if ( objeto && !objeto->estaVacio() )
return TRUE;
return FALSE
}
virtual boolean estaVacio() = 0;
// sigue resto descripción de clase
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 173
};
class Etiqueta {
public:
SQLString SQL( const SQLString& );
private:
char* nombre;
// sigue resto descripción de clase
};
class Clase {
public:
SQLString SQL( const SQLString& );
private:
OtraClase* otraClase;
};
class OtraClase {
public:
SQLString SQL( const SQLString& );
private:
Etiqueta etiqueta;
Etiqueta* pEtiqueta;
};
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 174
SQLString tmp;
if ( !etiqueta.estaVacio() )
tmp += etiqueta.SQL( identifier + "etiqueta." ) );
if ( !estaVacio( pEtiqueta ) )
tmp += pEtiqueta->SQL( identifier + "pEtiqueta->" ));
return tmp;
}
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 175
Como fácilmente se comprenderá, el objeto de tipo Consulta no necesita ser per-
sistente, aunque sí podría ser interesante (quizás para controlar la frecuencia de
ciertas consultas) hacer persistente al objeto que representa los atributos de se-
lección, de forma que esto se deja al criterio del equipo de programación, aunque
se recomienda un tal control únicamente en las fases de prueba y validación de
estabilidad de la aplicación final.
Quedan, sin embargo, algunas cuestiones por resolver. En primer lugar, ¿cómo
se accede a la colección de tipos disponibles? Aquí aparece la misma opción
discutida en otros epígrafes: bien la lista dinámica enlazada de objetos estáticos
(uno por cada tipo disponible) bien una lista estática directamente codificada pa-
ra la aplicación. Nuestro consejo es, como en otras ocasiones, empezar por la
segunda opción, pero, aun así, enhebrándola en una solución más elegante que la
de escribir expresamente en el código la lista de clases como un mero "switch":
habría que mantener la estructura jerárquica de las clases haciéndola persistente,
para lo cual es necesario crear una jerarquía de colecciones de colecciones. O
sea, habría que mantener objetos de la clase TipoEnJerarquia, relacionados por
su inclusión o no en la bolsa de tipos derivados de cada tipo.
De esta forma, una vez instanciado un objeto de cada tipo, mediante un interfaz
accesible sólo para el equipo de programación, para formar la lista necesitada de
tipos sólo habría que iterar por el grafo de relaciones de inclusión formado. Esta
solución evita tener que codificar el acceso a tipos expresamente en cada por-
ción de la aplicación que se necesite, pero tiene la desventaja, frente a la lista
dinámica de objetos estáticos con capacidad de clonación, de que no se garanti-
za automáticamente la inclusión de tipos. Se mantendría, así, una colección de
tipos empezando siempre por el propio de BaseObjeto.
En cuanto a las consultas, por otro lado, hemos visto que hay que dotar a cada
clase de un "constructor SQL" (algo susceptible, en este enfoque, de ser perfec-
tamente mecanizado a través de un preprocesador, en una aproximación similar
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 176
a la de los preprocesadores de persistencia comerciales). En un esquema similar
al de persistencia utilizado por algunas bibliotecas de clases, el encardinado SQL
se lleva hasta tratar con tipos predefinidos (char, long, etc.). Pero en realidad, ¿se
está asimilando la selección únicamente con la igualdad de atributos? ¿Qué ocu-
rre con los rangos (de fechas, de cadenas alfanuméricas, etc.)? Bien: dado que la
codificación es nuestra, podemos dotar a tales funciones del comportamiento que
en cada caso resulte más apropiado. Así, por ejemplo, en el caso de búsqueda
en objetos de tipo BaseColeccionActiva, la inserción en un tal objetoQuery de un
nuevo objeto significará, y así deberá ser codificado, que lo que se busca es una
BaseColeccionActiva (del tipo adecuado, si acaso) que contenga al menos un
ítem con los atributos especificados (este sería el caso, por ejemplo, para encon-
trar los agentes en plantilla cuya brigada sea una dada). Este enfoque amplía los
límites del problema de búsqueda, pero no soluciona la cuestión de los rangos:
¿qué hacer si deseamos a todos los empleados en activo nacidos entre el 01-01-
60 y el 01-09-64? De entre todas las posibles implementaciones, y en fidelidad a
la idea de reutilización de interfaces, examinaremos únicamente una: rangos por
interfaces.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 177
bios sustanciales). De hecho tal enfoque supone un reestructuración arquitec-
tónica difícil de asumir en un primer proyecto orientado-a-objetos. ¿Cuál es, pues,
nuestra recomendación? Pues que se use la conceptualización detallada anterior-
mente, pero transladándola al interfaz. O sea: se usará el mismo esquema nave-
gacional detallado, pero tales funciones miembros constructoras de la frase SQL
estarán implementadas en la clase que defina el interfaz de acceso a los auténti-
cos objetos (esto es, en los diálogos que los manejan). De hecho bastará con
implementar un tal mecanismo navegacional genérico en la clase BaseDialogo
con las características anteriormente señaladas para la clase BaseObjeto. La
diferencia sustancial respecto del anterior planteamiento es que en el presente no
subyace ninguna representación real de la capa del modelo. Se trata, sin más, de
aprovechar el escalonamiento jerárquico de los diálogos (padre-hija) para cons-
truir las frases SQL correspondientes (naturalmente el esquema de tipos explica-
do sigue siendo válido). Esto significa, también, que no será posible una recons-
trucción navegacional automática de las frases SQL generadas (bueno, se puede
hacer, pero esto supondría que los diálogos dispondrían de analizadores léxicos
de implementación no elemental). El esquema recomendado se basa, pues, en la
siguiente secuenciación: del diálogo de Consulta básico se irán llamando a diá-
logos afectos a la modelización SQL que se pretende, con la anexión del siguien-
te diálogo auxiliar:
{bmc sql.shg}
donde aparecerán las sentencias SQL determinadas por los diálogos y que ac-
tuará como gestor de la construcción de la frase. Dado que una secuencia de ta-
les diálogos podría ser muy larga y, en principio, la cadena SQL se construiría con
la aceptación o validación de lo que en cada diálogo aparece, tal gestor dispone
de un pushbutton que automatiza la aceptación en cadena de los diálogos de
selección. Tras la construcción de la frase, el gestor será el responsable de
ejecutarla, apareciendo los resultados en el diálogo primero de "Consulta". De
esta forma la aceptación en los diálogos de expresiones regulares no presente
ningún problema, pues no habría que mapearlos a objetos reales del sistema. Lo
que se podría archivar, así, es la propia sentencia SQL dotada de un título. Este
esquema puede ser naturalmente extendido para soportar consultas genéricas
introduciendo marcas en expresiones que, en su ejecución (por compilación)
requieran la cooperación del usuario.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 178
Este esquema de dependencias supone que cuando una vista se destruye, mini-
miza o esconde, la acción pertinente es traspasada a sus vistas hijas. Natural-
mente el caso crítico es el de destrucción. Pero, ¿es siempre posible mandar un
tal mensaje a una vista actualmente con hijas? Examinemos esta cuestión desde
el punto de vista polar de la arquitectura elegida: modal o no-modal.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 179
da en BaseDialogo), lo que ocasionará una nueva cascada de validaciones con
el mismo método, tras la cual continuará la iteración de comprobación de diálo-
gos. Si el usuario pulsa "No" entonces se llamará a la función virtual "boolean
cancelar()" que simplemente eliminará las modificaciones realizadas en el interfaz
y ocasionará, de nuevo, una cascada de reconocimientos tras la cual seguirá la
iteración principal. Si el usuario, finalmente, responde "Cancelar", entonces sim-
plemente se cancelará la iteración principal en tal punto. Esta es la secuenciación
más elemental y permite una rápida y segura implementación. Pero examinemos
la función de validación individual de diálogos.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 180
GESTIÓN DE PROYECTOS
10
EL SÍNDROME DE ESTOCOLMO
Es opinión antigua, firme y consensuada que “no existe una bala-de-plata” en re-
lación con la OT32 (o sea, que la panacea software universal sigue estando en el
terreno de la alquimia), pero también se acepta de forma unánime que la OT pro-
porciona ventajas evidentes en el desarrollo genérico de software. Naturalmente
lo más fácil es pensar que los “nuevos” métodos que la OT propugna no van a
facilitar el trabajo diario “real” en empresas y departamentos de desarrollo de
software, pero ocurre que los que accidental o incidentalmente caen en ellos pron-
to incuban lo que los no-convertidos denominan un OOSS (Object-Oriented Stoc-
kholm Syndrome) y que resulta en una persistente y malsana atracción por las
nuevas técnicas. Los atractivos de los “objetos” aparecen innegables y, de acuer-
do con Lorenz, las siguientes etapas personales se cubren de forma inexorable:
• Aprendiz (3-6 meses): aquí se produce el “despertar” del que hablan los
textos de Zen, se ve el verdadero significado de la orientación-a-objetos
y se empiezan a bosquejar diseños pertinentes.
32
OT es la abreviatura inglesa de Object Technology: Tecnología de Objetos. TO suena dema-
siado castizo.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 181
Bien: todo esto, unido a la gran profusión de noticias sobre objetos en la prensa
especializada, resulta muy emocionante y atractivo, pero en las empresas necesi-
tan de métodos fiables, estables, bien documentados y a los que dé soporte un
buen conjunto de soluciones software desarrolladas con ellos. Hay, pues, que
examinar el estado de la OT para decidir. Pero aquí empiezan -o siguen- los pro-
blemas.
Tras todo lo anterior no dejen que el tono les intimide: la orientación-a-objetos -de
la que el autor es firme defensor- realmente “funciona”, y ya existe un importante
acervo práctico de soluciones software basadas en análisis y diseños orientados-
a-objetos. Pero también existe un nada despreciable anecdotario de fracasos y
despropósitos. La realidad es que el camino de la productividad, como el del in-
fierno, está fatalmente empedrado de ilusiones e intentos aventurados. Necesi-
tamos alguna luz. Intentemos una revisión de los métodos comerciales.
Es opinión extendida que en la arena de los métodos OOA/OOD existen dos co-
rrientes principales, dividiendo a estos en:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 182
• dinámicos (enfocados-a-comportamientos o enfocados-a-
responsabilidades): un objeto tiene sentido en estos métodos cuando
exhibe un comportamiento diferencial respecto del resto de los objetos.
Tal comportamiento puede referirse bien al objeto en sí (los cambios
que pueden operarse en su representación interna) bien a sus relacio-
nes con otros objetos.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 183
Berard Berard
ADM3 Donald Firesmith
Ptech OOA&D Martin & Odell
Object Oriented Rôle Analysis, OORASS Reenskaug et al.
Synthesis and Structuring
Fusion Coleman y otros
Desfray Softeam
Responsability Driven Design CRC Wirfs-Brock et al.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 184
añadiendo el modelo-de-interacción-de-objetos (OIM). Coad/Yourdon
aportan en su método unario (OOA/OOD) las plantillas de objetos y de
descripción de métodos. Etc., etc., ... ad nauseam.
Como el lector fácilmente podrá apreciar, la legibilidad no es lo que aquí más im-
porta: las anteriores frases tienen sentido sobre todo para el que ya tiene una opi-
nión formada sobre los distintos métodos. La comprensibilidad sí se echa en
falta: es fatalmente difícil asimilar opiniones como las anteriores sin conocer en
suficiente detalle cada uno de los métodos tratados, y tanto más en cuanto que
tales no representan unidades de comprensibilidad autónoma, pues cada uno
refleja una particular visión, usualmente basada en la experiencia de sus autores
en proyectos reales, del ciclo de desarrollo de software. ¿Y entonces? Pues que,
aun a riesgo de parecer estúpidamente trivial, debo sostener que para aplicar
un método de OOA/OOD (o un refrito de algunos de ellos) hay que conocerlos
casi todos. Pero examinemos con más detenimiento esta -aparentemente- sor-
prendente conclusión.
CÉSAR O NADA
A poco que el lector bucee en los textos y artículos de análisis y diseño orienta-
dos-a-objetos se encontrará con afirmaciones tales como que los métodos de
OOA/OOD se dividen en unarios y ternarios, o que los métodos de segunda ge-
neración pueden usar de uniones de métodos de primera generación, o simple-
mente que si un análisis contiene un solo DFD es que hay que rehacerlo (Cole-
man?!). Y es que no hay final donde no existen claros principios: si aun se discute
la esencia ortodoxa de la orientación-a-objetos (si la persistencia es una caracte-
rística, si la herencia es simplemente un mecanismo, bla-bla-bla), ¿cómo abundar
en tantas clasificaciones y divisiones? Epore il muove, como diría Galileo, pues
lo cierto es que los sistemas orientados-a-objetos comercial y realmente funcio-
nan. Debe ser posible, pues, extraer técnicas prácticas de los mismos, pues tales
normalmente se basan directamente en las experiencias prácticas (que sí suelen
funcionar) de sus autores. Pero ¿existe algo bueno en cada método que se pue-
da aislar y usar en un entorno separado? Absolutamente no, aunque quizás sí con
cierta matización. Resulta que los objetos no están ahí para cogerlos (object-
picking), sino que más bien el analista (OODA: Object-Oriented Domain Analyst)
los crea en cada análisis, y de aquí que la pertinencia de que cada método o téc-
nica deban ser específicamente evaluados en cada proyecto. Y precisamente
para esto hay que conocer muchos de ellos, pues si no limitaríamos de forma pe-
ligrosa la arquitectura, y aun el resultado final, de nuestros proyectos. Pero tal no
es exclamar, en un remedo barojiano, o “César o nada”: se trata más bien de
ponderar si la base metodológica del equipo de análisis y diseño es suficiente
para abordar proyectos no-triviales, y dado que no existen todavía criterios in-
amovibles de evaluación metodológica en OOA/OOD, parece que habrá que de-
jar, en buena medida, la concrección de elementos básicos arquitectónicos en la
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 185
construcción de software al buen criterio de tal equipo. Pero aquí surgen lógicas
inquietudes: ¿es posible dedicarse al estudio de las corrientes OOA/OOD sin
perder el rumbo del trabajo diario? ¿cómo se ajusta el anunciado eclecticismo,
de connotaciones subjetivas, con la deseable normalización de la gestión de pro-
yectos en las empresas de desarrollo? ¿cómo determinar la bondad práctica de
los métodos basándose solamente en consideraciones teóricas? ¿no existe, al
fin, un cierto rango de soluciones suficientemente probadas en análisis y diseño?
Bien: vayamos a las respuestas.
LA SOLUCIÓN ECLÉCTICA
Con todo, y para que el lector no se quede con una amarga sensación, sí puede
explicitarse un cierto núcleo metódico: Las fichas CRC y el enfoque a responsabi-
lidades facilitan mucho la labor en las primeras etapas del OOA/OOD (que bási-
camente trabajan sobre unas especificaciones obtenidas en la etapa del OORA,
Object-Oriented Requeriment Analysis, pero esto es otra batalla); después una
modelización tipo OMT ú OSA ayuda bastante, junto con aspectos de la metodo-
logía de Booch y la aplicación de casos-de-uso (use-cases) de Jacobson, e inclu-
so diagramas de transición de estados y redes de Petri. Al final se obtienen fi-
chas tanto de objetos como de sus relaciones, pero tales son, como casi todo,
susceptibles de ser mecanizadas. Naturalmente si todo lo anterior se envuelve en
un entorno visual (lisez VMT, de IBM), las cosas mejoran bastante. Si a este en-
torno añadimos capacidades de prototipación rápida y de documentación del
diseño, entonces parece que tendríamos la herramienta adecuada, con lo que
entramos en el resbaladizo terreno del CASE (OOCASE ahora).
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 186
HERRAMIENTAS OOCASE
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 187
tos y “mapeos” de componentes a documentaciones y responsabilidades. Lo que
es incuestionable es que algunos roles cambian, otros aparecen como nuevos,
mientras que otros desparecen por completo (como, verbigracia, el del mero pro-
gramador). Con la documentación (o los “deliverables”) ocurre otro tanto: dado
que el ciclo de vida del software es diferente (“Analiza un poco, diseña un poco,
implementa un poco y evalúa un poco”, según Berard), no existen fases estancas
y, por tanto, una fase no puede basarse en resultados completos de una supuesta
fase anterior, de lo que resulta que la documentación ha de generarse, también,
de forma involutiva. Parece claro, no obstante, que han de documentarse clases,
métodos y relaciones. Pero lo que definirá la estrategia de documentación nor-
malmente se define en la etapa de OORA (la gran desconocida, en manida fra-
se): especificaciones estáticas y dinámicas, de interfaces y comportamientos, de
modelización y control, etc. Trabajo de expertos, de nuevo. El lector podrá encon-
trar, empero, descripciones de particulares gestiones de proyectos, con diferen-
tes niveles de abstracción, en Lorenz, Berard, Firesmith, etc., pero difícilmente
podrán ser aplicadas a un proyecto concreto con limitaciones humanas, tempora-
les y dinerarias, cual suele ser el más común caso. ¿Desesperanza, entonces?
No: simplemente una cuestión de monitorización: suele acertar quien se ha equi-
vocado antes, directa o indirectamente; y usualmente la gestión de proyectos ne-
cesita de una experiencia interdisciplinar en campos dispersos.
SÍSIFO REDIVIVO
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 188
MODELOS DE ROLES
11
¿Qué es lo que, por encima de otras características, identifica a todos los lengua-
jes de programación orientados-a-objetos? ¡Los objetos, naturalmente!, como
quiera que en cada caso puedan llamarse. Pero tras éstos sigue una legión de
lenguajes que incorporan lo que se denominan “clases”, sean éstas propiamente
objetos o no, intentando proporcionar estructuras que encapsulen las comunali-
dades de conjuntos de objetos. Teniendo en cuenta, por otro lado, que los es-
quemas de diseño, y más tarde de análisis de sistemas, debieran provenir del
estudio de las estructuras linguísticas aplicadas en la implementación real de so-
luciones software, resultará evidente al lector por qué la mayoría de los métodos
de OOA/OOD se basan en el pre-establecimiento de una dicotomía inamovible:
clases y objetos. Pero, atención, si se examina brevemente esta aseveración pa-
rece que algo falla: ¿todos los sistemas reales se modelarán sólo en base a cla-
ses y objetos? ¿Es ésta la solución definitiva? Humm, atendamos a una pequeña
disgresión: como el lector sabe, los distintos métodos, técnicas, trucos y conjuros
que conforman el grueso de lo que pomposamente se ha dado en llamar Análisis
y Diseño en Ingeniería de Software no son sino resoluciones más o menos afortu-
nadas del problema genérico de la traslación de la realidad al dominio software.
Tradicionalmente tal correspondencia se ha basado, como antes se expuso, en
una inferencia posibilista basada en modelos prácticos de funcionamiento efecti-
vo: esto es, primero se han modelado, más o menos desconexamente, multitud
de sistemas, para más tarde extraer de éstos conclusiones genéricas teórica-
mente aplicables a problemas similares a los modelados. Actualmente, sin em-
bargo, la creciente explosión informativa ha dado en generar un fenómeno harto
curioso que yo denominaría “recursión desplazada”. Tomemos, por ejemplo, el
“Análisis y Diseño Orientado-a-Objetos”: originariamente bienintencionado y ba-
sado en simulaciones reales (lisez aquéllas basadas en Simula, Smalltalk-80,
etc.), pronto desembocó en un precipicio involutivo con ribetes atractivamente
comerciales (lisez Coad&Yourdon, Booch, etc.), mención aparte de las cualida-
des reales de cada método (bien escasas, con todo, en su relación con la gestión
real de proyectos). Así, como cuando se llevaron conejos a Australia, estas prime-
ras incursiones se asentaron en un terreno sorprendentemente fértil, e, igual que
ocurrió con aquellos animales, la profusión de métodos devino alarmantemente
rápida, ocasionando a la vez similares destrozos (y la mixomatosis no parece ser
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 189
aquí, tampoco, buena solución). Si a todo esto añadimos la avidez informativa
que caracteriza a estos últimos años obtendremos una situación en que las expe-
riencias quedan aplastadas por las inferencias: esto es, como no se da tiempo a
que se generen experiencias sólidas fiables para cada uno de los métodos publi-
cados, de forma que sobre ellas pudiera basarse una revisión de los mismos, los
nuevos métodos han de basarse, por fuerza, en las versiones más recientes de
métodos anteriores: o sea, nos elevamos tirándonos de las orejas. De esta mane-
ra, finalmente se convierte en incontestable esencialidad lo que fue contingencia
primeramente: los nuevos métodos33 orientados-a-objetos dan, así, por supuesto
que la base de su estructura y notación son, a la vez, objetos y clases, usualmente
aderezados después con sofisticadas, prolijas, tendenciosas o ridículas conside-
raciones contextuales y de establecimiento de capas comprehensivas (ya sabe el
lector, esas que consiguen hacer mínimamente abordables composiciones de
3.000 clases, 15.000 conexiones, 20.000 flechas, etc.): aparecen, así, subsiste-
mas, entornos de visibilidad, relaciones tipificadas, abstracciones de variación de
estados ... y multitud de artefactos intelectuales que intentan suplir las carencias
de una elección inicial cuando menos sesgada. Pues si sólo se dan inicialmente
clases y objetos, como sólo se dieron Adán y Eva 34, forzosamente ha de cons-
truirse inicialmente un modelo estático de relaciones entre entidades (agrupemos
la dualidad), para después estimar comportamientos, interacciones y reacciones
dinámicas: todo un pastiche gastronómico que podría haberse evitado eligiendo
mejor las viandas principales. “Y, claro, lo que faltan son los roles” -apuntará el
impaciente lector. ¡Vaya, así es! Y es que he dado muchas pistas. “Pero esto es
una afirmación tan gratuita como la que asegura la sola necesidad de clases-
objetos” -seguirá el lector crítico- “¿Por qué ésta sí y aquéllos no?” Humm, ob-
viando la importante cuestión que el enfoque de roles que aquí se expondrá inclu-
ye al de clases-objetos, y aplazando temporalmente la inmersión en definiciones y
procedimientos, intentaré dar satisfacción al lector atacando, antes de entrar en el
modelado genérico de roles, distintos aspectos esenciales a la construcción de
sistemas software, singularmente basados en la interpretación de la realidad y
extraídos, en buena parte, de mi experiencia personal.
ESCENARIOS Y APREHENSIONES
33
Observe el lector que conscientemente evito el vocablo “metodología” en un vano propósito, sin
duda, de resaltar con la repetición en la omisión cierta intención irónica, cuando no despectiva.
34
Oh, Adán y Eva se dieron entre sí de manera que vocablos como “conocimiento” y “congreso”
adquirieron su sentido exacto. Y es que seguro que a estas alturas el lector ya habrá asimilado la
subrepticia comparación entre la dicotomía “clase-objeto” y el Concilio de Trento. Claro que, ¿se
equiparará OOram al Concilio Vaticano II? ¡Demonios, espero que no!
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 190
puestos básicos en que se apoya el sistema; de hecho hay que volver a “analizar”
el problema. Pero ... ¡se trata de un sistema complejo, con demasiadas interac-
ciones para ser asimilado conceptualmente en una sola vista! ¿Solución? “Oh,
usemos una herramienta CASE -podría exclamar el impaciente lector”. “Mejor si
es OOCASE” -asumirá aquel otro lector, quizás un tanto receloso. “Alegradme el
día” -podría anunciar entonces yo, empuñando con soltura una Magnum. Porque,
¿para qué demonios quiero yo traspasar la complejidad del mundo real al plano
de los dibujitos inanimados35? Lo que aquí hace falta es algún enfoque compre-
hensiblemente simple que permita reducir la complejidad en el ataque para do-
mar el problema. Naturalmente no nos sirven, y más bien nos perjudican, las com-
posiciones de “tablas”: incontables entidades, con atributos de todos los tipos y
colores, que se relacionan mediante una inaprensible maraña de líneas con car-
dinalidades explícitas (0,n) por doquier, usualmente construidas mediante una
herramienta visual que genera los scripts de creación de tablas relacionales para
una amplia gama de gestores. Y es que en estos esquemas una entidad (por
ejemplo, una Persona) tiene los mismos atributos (columnas) respecto de muchí-
simas otras entidades, lo cual parece razonable en el contexto del diseño de ta-
blas, pero resulta descorazonador cuando respecto de una entidad concreta, co-
mo por ejemplo un Asistente Técnico, únicamente necesita de su dirección. ¿Por
qué repetir, pues, todos los atributos en todas las situaciones? Pues porque, sim-
plemente, no se consideran las situaciones en sí, sino sólo las relaciones estáti-
cas entre entes. Oh, las relaciones dinámicas también se estiman en los posterio-
res diagramas de transición de estados (y técnicas adláteres), pero sólo de ma-
nera que se rellenan y cambian algunos atributos del total que reúne la entidad:
esto es, cada situación dinámica mantiene un conjunto invariante de atributos,
que únicamente se deduce por su omisión del modelo dinámico, de forma que los
defectos del presupuesto inicial de diseño de tablas contaminan el proceso ente-
ro de análisis/diseño. Además este planteamiento supone una visión conciliadora
que pasa por muchas consideraciones, decisiones de diseño y soluciones ses-
gadas que en absoluto quedan documentadas con el mero diseño de las tablas.
Me explico: yo puedo decidir, por ejemplo, que el “Cliente” de este escenario es
el mismo “Abonado” de aquel otro, y que ambos son, en el fondo, instancias, qui-
zás con diferentes estados internos, de la entidad/clase “Persona Física”, que
fácilmente es una clase derivada de “Persona”, con la que operaré más genéri-
camente (también las “Personas Jurídicas” son “Clientes” y “Abonados”). Todo
esto está muy bien, pero son decisiones que, a lo sumo, se documentarán de
forma externa al diseño de marras, pues en éste lo que finalmente aparecerá será
una clase/entidad con demasiados atributos/columnas y alguna breve calificación
textual. Y es que no podemos abordarlo todo a la vez: según G.I. Miller, la memo-
35
Las neurosis de Walt Disney, a pesar de la animación, construyeron una realidad comercial
asexuada y muy cercana a los sueños infantiles del Estrangulador de Boston: muñecos que no
hablan y que siempre enseñan ambas manos, y ... ¡Pero bueno! ¿Qué clase de bicho es Goofy?
¡El sueño de un psicólogo rogeriano!
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 191
ria a corto plazo sólo puede asimilar simultáneamente tres bloques conceptuales
con un máximo de tres elementos cada uno (una variación de la regla, también
suya, del 7 más/menos 2), así que para comprender hay que segmentar: Divide et
Impera. Pero, ¿cómo encontrar los subsistemas, escenarios o porciones autó-
nomas sobre las que aplicar nuestra cuestionable inteligencia analítica? Exami-
nemos algunas posibilidades:
Volvamos a nuestro sistema de gestión comercial: ¿no hay ninguna forma de es-
tablecer módulos de trabajo a modo de componentes con los que construir, me-
diante su integración, el sistema final? ¡Naturalmente que sí! Un primer acerca-
miento incruento (al menos respecto del Jefe de Departamento, usualmente bien
pertrechado de arrojadizos laborales) sería intentar modelar procesos (o mejor
36
El lector deberá perdonarme el refrito de la infatigable verdad “El dinero llama al dinero”. Yo
mismo habré también de perdonarme, pues ciertamente aborrezco la incontinente vulgaridad de
la franqueza social de la que los refranes son odioso reflejo.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 192
actividades) a la manera de los casos de uso, controlando los estímulos externos
que afecten a la identidad del sistema (no las colaboraciones ni las cadenas de
mensaje), también como las repercusiones externas, pero recabando que los ro-
les a que se pueden adscribir las entidades del mismo conforman un modelo
conceptual claro y presumiblemente inamovible en ese contexto. O sea, en la
práctica se trataría de modelar por separado situaciones en las que en primer
lugar no se dé variación del rol asumido por cada entidad, pudiendo integrar des-
pués los intercambios de roles en el mismo modelo. Así una bienintencionada
primera fase práctica pudiera ser la de reconocimiento de los roles que se juegan
en razón de los procesos actuales que se dan en el dominio del problema: existe,
por ejemplo, un proceso de “Servicio de Reparación de Averías” en el que se dan
los roles de “Abonado con Problemas”, “Mecánico”, “Punto de Servicio”, “Servicio
Afectado” y “Material Estropeado”, entre otros. Nuestros punto de control respecto
de los límites de esta porción serían los de transición en una entidad de un rol a
otro. Así, por ejemplo, si como consecuencia de una avería irreparable el “Abona-
do” decide rescindir el servicio, o contratar más garantías para el mismo, el rol
que juegue habrá dejado de ser el de “Afectado”, pasando a desempeñar el de
activo “Contratante”, pero tales nuevas actividades deberían permanecer fuera de
nuestro modelo de Servicio Asistencial. Hay que recabar, también, que en esta
etapa en absoluto se prejuzga qué tipo de entidad o clase es la que “implementa-
rá” (y este calificativo es importante) cada uno de los roles encontrados: de esta
manera en cada escenario (o mejor, modelo de roles) se detallan únicamente los
atributos que interesan al modelo en estudio. Naturalmente en algún momento
habrá que integrar o sintetizar tales atributos para componer la entidad de imple-
mentación (“clase” o usualmente “tabla”): para conseguir tal habrá que considerar,
más o menos informalmente, cómo la unión de modelos de roles afecta al modelo
de roles resultante (pues eso es lo que obtenemos, en buena lógica). Lo que así
estamos consiguiendo es estratificar con límites semánticos bien definidos cada
una de las porciones de que se compondrá nuestro sistema, y la verdad es que
las perspectivas son halagüeñas: si el enfoque funcional se está abandonando en
favor del de objetos/entidades, para evitar la volatilidad de los sistemas, ¿por qué
no ir un paso más allá y afianzar el diseño en modelos fácilmente comprensibles,
reutilizables y componibles en distintos contextos? Ah, estos son los modelos de
roles. Pero ¿no suena todo lo expresado un tanto etéreo, como muy dejado a la
imaginación del analista? Bien, quizás suene así, como puede sonar a tarareo
una ópera de Verdi desde muy lejos, así que habrá que acercarse un tanto: en lo
que sigue examinaremos muy muy brevemente los aspectos más importantes de
un método, Ooram, analíticamente completo, intelectualmente satisfactorio y con
muchos años de experiencia a sus espaldas. Así que lo propio será recaer en el
libro en que se explicitan, mejor que aquí, tales ideas.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 193
EL LIBRO
Working with Objects: The OOram Software Engineering Method, por Trygve
Reenskaug, Per Wold y Odd Arild Lehne, 1996, Manning Publications, 1-884777-
10-4 (Prentice Hall 0-13-452930-8).
Atención, lector: a mi entender este es uno de los textos más importantes publi-
cados en los últimos años sobre construcción de sistemas software, de forma que
arriesgarse a ignorarlo es comprometerse con la oscuridad. Sepa el lector, de
cualquier forma, que no soy fanático: sólo vehemente. Esto es, en el texto se ex-
plicitan muchas ideas que a mí me parecen no sólo naturales y adecuadas, sino
también inteligentes, efectivas y, finalmente, humanas. Es curioso que sean los
trabajos europeos, y sobre todo los del norte, los que enfaticen la primordial im-
portancia del factor humano en la construcción de sistemas software. El libro
contiene, además, un importante componente pedagógico, pues evidencia los
importantes logros conseguidos mediante el uso prudente de Smalltalk y de la
más general Tecnología de Objetos en una empresa (Taskon) a lo largo de más
de 25 años. El autor principal, Trygve Reenskaug, es, además de un reputado
experto en el campo de la Orientación-a-Objetos, el creador del concepto
Modelo-Vista-Controlador (MVC) que seguro todos conocen. En fin, para abordar
el contenido del libro intentaré resumir los capítulos más significativos.
IDEAS PRINCIPALES
El método OOram se define como “un marco de referencia para una familia de
metodologías orientadas-a-objetos”, tras lo que se muestran las mejoras que el
método introduce en las tres dimensiones típicas que componen el grueso de me-
todologías:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 194
• Organización (las maneras en que la empresa acoge lo anterior): aquí
se explicitan las dificultades de diseñar para reutilizar y las ventajas que
supone el uso de cadenas de valor.
MODELADO DE ROLES
“El modelo de roles es una abstracción del modelo de objetos donde reconoce-
mos un patrón de objetos y lo describimos como un corespondiente patrón de
roles”. Y es que la clase se apoya en las capacidades (funcionalidad absoluta) de
los objetos, mientras que el rol se apoya en la posición y responsabilidades de un
objeto respecto de una estructura de otros tantos, que es precisamente lo que
percibimos cuando examinamos un conjunto de entidades/objetos en colabora-
ción. Pero el modelo de roles no representa la descripción de la estructura entera
de objetos observada, sino más bien de porciones de la misma, segmentadas
temporalmente, denominadas “áreas de interés” (areas of concern), y que mues-
tran fenómenos colaborativos de interés. Resulta, así, que un modelo de roles es
un modelo orientado-a-objetos de una estructura de objetos.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 195
nicas seguras de síntesis, bien por lo que se conoce como síntesis insegura, cu-
ya aplicación necesita de una personal y cuidadosa atención.
PUENTE A LA IMPLEMENTACIÓN
Aquí se muestra la idea básica de que para reutilizar es necesario utilizar antes,
de manera que la llave del éxito es la comunicación efectiva entre el proveedor y
los consumidores. OOram distingue entre reutilización por herencia (mediante
patrones y frameworks) y reutilización por encapsulación.
El reúso por herencia se basa en patrones (que respecto de OOram son paque-
tes de formato fijo contenedores de un modelo de roles junto con documentación
que describe cómo y cuándo debe éste ser usado) y en frameworks (entornos-
marco), que representan un modelo de roles junto con un conjunto de clases base
que definen direcciones y restricciones de extensibilidad.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 196
LEA, LECTOR: LEA
Como el lector puede apreciar en base a lo hasta ahora expuesto, no se trata aquí
de un simple método que postula elegantes y frecuentemente hueras descripcio-
nes étereas de sistemas, sino más bien un verdadero marco referencial muy den-
so en conceptos, notaciones y esquemas formales, pero donde el factor organiza-
tivo y humano juega un papel primordial. La extrema densidad de lo que en el tex-
to se expone troca casi en imposible su sola enumeración comprehensiva aquí,
así que emplazo de nuevo al lector a que lea.
OOram es, según sus creadores, un método adecuado de tratar con lo que se
denomina programming-in-the-large. Pues bien, aparte de lo expuesto, en el
mismo texto podrán encontrar cuatro casos bien desarrollados como ejemplos: el
desarrollo de un sistema de información negocial, el análisis y diseño de un sis-
tema de tiempo-real, la creación de un entorno-marco (framework) y los servicios
inteligentes de red organizados como cadena de valor.
REFERENCIAS DIRECTAS
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 197
• Constantin Arapis, Specifying Object Lifecycles, D. Tsichritzis (ed.), Object
Management, Universite de Geneve, 1990.
• Constantin Arapis, Specifying Object Interaction, D. Tsichritzis (ed.), Object
Composition, Universite de Geneve, 1991.
• Constantin Arapis, Object Behaviour Composition, D. Tsichritzis (ed.), Object
Frameworks, Universite de Geneve, 1992.
• P. Papazoglou, Roles: A Methodology for Representing MMultifaceted Objects,
Proc. of Conf. Database and Expert Systems Applications - DEXA 91, 1991,
pp. 7-12.
• Lynn Andrea Stein, Compound Type Expressions: Flexible Typing in Object
Oriented Programming, Proc. of Conf. on Object-Oriented Systems, Languages
and Applications (OOPSLA), 1988, pp. 360-361, Position Paper.
• Constantin Arapis, Type Conversion and Enhancement in Object-Oriented Sys-
tems, D. Tsichritzis (ed.), Object Oriented Development, Universite de Geneve,
1989, pp. 191-205.
• David McAllester and Ramin Zabih, Boolean Classes, Proc. of Conf. on Object-
Oriented Systems, Languages and Applications (OOPSLA), 1986, pp. 417-
423.
• Hendler, Enhancement for Multiple-Inheritance, SIGPLAN, V. 21, N. 10, Octo-
ber, 1986.
• Edward Sciore, Object Specialization, ACM Transaction on Information Sys-
tems, V. 7, N. 2, April, 103-122, 1989.
• Mohamed E. El-Sharkawi and Yahiko Kambayashi, Object Migration Mecha-
nisms to Support Updates in Object Oriented Databases, N. Rishe, S. Navathe
and D. Tal (eds.), Databases: Theory, Design and Application, A postconfer-
ence proceedings based upon the proceedings of PARBASE-90 Florida
March 6-9, 1990, IEEE Computer Society Press, 1991, pp. 73-109.
• Jianwen Su, Dynamic Constraints and Object Migration, Proceedings of the
Sixteenth International Conference on Very Large Databases, Barcelona,
Spain, VLDB 91, 1991, pp. 233-242.
• El lenguaje denominado LOOM, desarrollado en ISI, California. Para más in-
formación, contactar a David Brill (brill@isi.edu) o copiar el Manual de Usuario
mediante ftp de isi.edu:/pub/loom.
• Craig Chambers, Predicate Classes, ECOOP 93 proceedings.
• Robert Strom et al., Hermes A Language for Distributed Processing, Prentice
Hall, 1991.
• La característica CHANGE-CLASS del lenguaje CLOS, que permite convertir
un objeto de una clase a otra.
• Papel sobre roles implementados en Smalltalk: roles.ps via ftp anónimo de
140.78.58.1
• La tesis doctoral sobre Redes Semánticas escrita por Nicholas Roussopoulos
en 1977 en alguna universidad canadiense.
• El modelo de datos funcional permite que los tipos sean asociados dinámica-
mente con objetos surrogados, y esto significa que la identidad de un objeto
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 198
permanece invariante durante sus transformaciones de tipo. IRIS ú OPEN-DB,
de HP.
• Berard Software Enggineering, Inc., A Complete Object-Oriented Design Ex-
ample.
• J. Wieringa, Algebraic Foundations for Dynamic Conceptual Models, Depart-
ment of Mathematics, Vrije Universiteit, Amsterdam, May, 1990, Ph.D. Thesis.
• Wirfs-Brock, Johnson, Surveying Current Research in Object-Oriented Design,
Communications of the ACM, 33 (9), September, 1990, pp. 113-116. Este
artículo incluye una sección sobre modelado de roles.
• T. Hawryszkiewycz, Database Analysis and Design (Libro).
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 199
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 200
BIBLIOGRAFÍA COMENTADA
12
Lo que sigue es un conjunto de cortas reflexiones y personales consejos sobre
textos imprescindibles en C++ y Orientación-a-Objetos, sin dejar pasar los dedi-
cados a Java, Smalltalk, Bases de Objetos y metodologías en general. El lector
enterado constatará que algunos de los textos que se citan aquí (abrumadora-
mente en inglés) han sido traducidos ya al castellano, pero sea dicho que yo, en la
mayoría de los casos ya lo sabía, y he preferido un idioma extranjero a una tra-
ducción peligrosa, malvada o, simplemente, ridícula. El lector tiene, empero, una
garantía: todos estos libros forman parte de mi biblioteca personal y han sido se-
leccionados para su inclusión en esta relación por poseer una característica bási-
ca: merecen ser releídos37.
The C++ Workbook, por Richard S. Wiener & Lewis J. Pinson, 1990, Addi-
son-Wesley, 0-201-50930-X, 349 pág.
He de confesar que le profeso cierto cariño a este texto, sin duda el más elemen-
tal de todos los aquí comentados. Se trata de una introducción a AT&T C++ 2.0,
37
“El libro que no merece ser releído no merece ser leído”, confirmo yo.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 201
con multitud de ejemplos, letra grande y legible, y abundantes resultados de
programas. El libro se caracteriza por frecuentes inserciones de apartados "¿Qué
pasaría si ...?", que intentan resolverle al lector las dudas más habituales en el
primer acercamiento al nuevo lenguaje. Teniendo en cuenta la proliferación actual
de desenfocadas introducciones al lenguaje C++, repletas de dudosas intencio-
nes y de tontería, esta obra es un respiro que se puede completar en escasas
horas. Ni de lejos sustituye, por supuesto, a textos de introducción como el de
Lippman o el de Dewhurst & Stark, pero muy bien podría constituirse en el perfec-
to puente hacia éstos, pese a que la evolución del lenguaje convierte cualquier
libro de menos de 400 páginas de letra pequeña en un mero divertimento.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 202
On to C++, por Patrick Henry Winston, 1994, Addison-Wesley, 0-201-58043-8.
Reconozco que que este libro lo adquirí coercionado por un tanto de morbo hacia
su autor: Winston, del MIT, padre de la Inteligencia Artificial moderna y guru tecno-
lógico que ... “bueno, bueno, veamos qué cuenta éste” me dije. El libro, al fin, es
ciertamente curioso, pues expone en secciones breves enseñanzas de muy po-
cas líneas calificadas por epígrafes numerados (hasta 795), insertas en capítulos
que empiezan, sin variación, por “Cómo hacer ... (How to)”. Así tenemos: “Cómo
escribir programas que hallan funciones-miembro en tiempo de ejecución”, “Có-
mo construir constructores que llaman a otros constructores”, “Cómo diseñar cla-
ses y jerarquías de clases”, etc., etc. En fin, la brevedad no da cancha a la tonte-
ría, aunque en este caso tampoco a la profundidad (pero infiero que no era tal su
intención). Los amantes de aforismos encontrarán aquí su sustento, pero no los
buscadores de epigramas. Tan árido como la IA, pero más práctico.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 203
para el experto se convierte en paradigma de cómo debe escribirse un buen texto
de introducción.
Object-Oriented Design for C++, por Tsvi Bar-David, 1993, Prentice-Hall, 0-13-
630260-2.
El autor pretende aplicar los conceptos de la orientación-a-objetos al lenguaje
C++ a la vez que intenta construir un puente entre tales conceptos y “el mundo de
los métodos formales y las especificaciones formales”. Claro que el lector, yo
mismo y los periodistas científicos saben que tal no se consiguió, pues todavía se
suscitan debates sobre si métodos formales sí o no, y acaso cómo, en ingeniería
de software38. El texto tiene, con todo, un agradable aunque liviano regusto formal
y abunda sobremanera en la importancia evidente de “precondiciones” y “post-
condiciones” e intenta imponer éstas en un estilo de codificación en C++ loable
38
¿Oigo exclamaciones airadas? Reclamaciones a IEEE y ACM.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 204
pero en buena medida poco práctico, y es que el lenguaje C++ no aporta ninguna
facilidad embebida para el tratamiento de estas cuitas (como sí lo hace, por
ejemplo, Eiffel). Se pontifica también en este texto sobre la extrema importancia
de las jerarquías de subtipado como extensión e interrelación de las abstraccio-
nes de datos, ideas que parten del artículo “Data Abstraction and Hierarchy” de
Barbara Liskov (que aparece reproducido en su integridad en este libro) y que
influyó de forma decisiva en el autor. En cualquier caso el libro es una sorprenden-
te introducción “formalista” a C++ y está tan empedrado de buenas intenciones
como el infierno (que diría don Ramón, así que no vendrá mal a más de un cabe-
za-hueca que piense que manuales, referencias y normas de estilo sólo han de
ser leídos por programadores incompetentes. Una cosa hay que decir: en el am-
biente universitario el adjetivo “formal” posee poderosas connotaciones atractivas
que suelen crear adicción y cierta psicosis denominada “de método científico”, de
forma que a nadie le habrá de extrañar que esta obra se use como texto en un
primer curso de C++.
The C++ Programming Language, 2nd Edition, por Bjarne Stroustrup, 1991,
Addison-Wesley, 0-201-53992-6, 669 pág.
Esta es la segunda edición del texto que el Dr. Stroustrup publicó en 1.986 deta-
llando el lenguaje C++, en su calidad de creador del mismo. Se trata de un tutorial
del lenguaje en el que, a diferencia del texto de Lippman, se enfatizan los aspec-
tos claves de uso del mismo. Se asume que el lector tiene experiencia previa en
programación en C, y se detalla la especificación AT&T C++ 3.0 partiendo "de
cero". El estilo del texto es enormemente sintético, de manera que la cantidad de
tópicos revisados es netamente superior a la del texto de Lippman. Comparada
con la primera edición, la obra ha crecido también considerablemente en número
de páginas. Precisamente ahora, cuando se empieza a generalizar el uso de
plantillas (templates) y se empieza a asentar la posibilidad práctica de uso del
tratamiento de excepciones, las páginas de este libro sobre tales materias se
constituyen en una insustituible guía referencial a la vez que conceptual, pues el
conocimiento de la mera sintaxis es claramente insuficiente. Si en la primera edi-
ción se revisaba la biblioteca que entonces se denominaba "stream", implemen-
tada por el propio Stroustrup, aquí se repasa la biblioteca "iostream", sobre las
bases desarrolladas por Jerry Schwarz. Se muestran y discuten algunos intere-
santes trucos y técnicas del lenguaje y el texto termina con un manual de referen-
cia. Una sección importante del libro la constituye (120 páginas) la dedicada a
OOD (Diseño Orientado-a-Objetos), en la que, usando de una extensión de la
técnica de las fichas CRC (de la que el lector encontrará una sucinta descripción
más adelante, en el texto de Wirfs-Brock), se introduce con acierto al lector en
esta disciplina. Bien, se trata de un libro muy difícil de resumir por su buscada
tersedad conceptual y de estilo, pero es indiscutible que, quizá con el soporte
previo de una obra introductoria como la de Lippman, su posesión es indispen-
sable para cualquier programador de C++. Estúdienlo, sin más condiciones.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 205
The Annotated C++ Reference Manual, por Margaret A. Ellis & Bjarne Strous-
trup, 1990, Addison-Wesley, 0-201-51459-1, 447 pág.
Esta es la biblia del C++: el texto de referencia indispensable para cualquier es-
tudioso, interesado o programador del lenguaje. Y biblia es aquí un término usado
con intencionada literalidad: acaloradas discusiones entre miembros de la comu-
nidad C++ suelen zanjarse con citas del tipo "la sección 13.2 de ARM (el apelati-
vo cariñoso del texto) dice: ...", que surten el efecto del mágico ensalmo que sólo
puede emanar de la autoridad por todos reconocida. El texto de este libro fue to-
mado, en su momento, como documento base por el comité ANSI C++ para la
estandarización del lenguaje, y la carencia, en estos momentos, de tal estándar
ha redundado en confirmar como inamovible tabla de salvación, en el complicado
mar sintáctico y conceptual de C++, a esta obra. Nos encontramos ante un texto
eminentemente referencial, que no pretende enseñar al lector a usar los meca-
nismos del lenguaje, sino más bien a describirlos en una forma tersa y rigurosa,
pero que, fundamentalmente en las notas, explicita cuestiones sobre la naturaleza
de C++ que pueden llevar al lector a comprender mejor la esencia del lenguaje:
por qué tal o cual característica no ha sido contemplada, o por qué tal otra ha sido
implementada de esta determinada manera, o cómo podrían suplirse comporta-
mientos no previstos en el nudo lenguaje, etc. Nótese que la primera línea del pre-
facio dice así: "Este libro provee una completa referencia del lenguaje para el
usuario experto de C++". No se pretende que el lector estudie de golpe, del prin-
cipio al final, el texto, pues tal tarea sería como la de intentar abarcar por orden
alfabético una vasta enciclopedia (y esto trae reminiscencias, no obstante, de
aquel "autodidacto" de la nausea sartriana): queda, pues, como una insustituible
obra de consulta. De cualquier manera, y dado que desde mayo de 1.995 el bo-
rrador del estándar está disponible (en Internet) para el público en general, esta
obra, eminentemente referencial, ha perdido parte de su valor práctico, conser-
vando empero todo su valor histórico.
The Design and Evolution of C++, por Bjarne Stroustrup, 1994, Addison-
Wesley, 0-201-54330-3.
Este libro no versa sobre C++ sino sobre las decisiones de diseño que han con-
ducido al lenguaje, en lo esencial, a su actual configuración. Stroustrup posee un
tono exacto y pragmático que convierte su texto en un alegato contra la tontería,
más allá de consideraciones beligerantes entre lenguajes. Yo diría que su ante-
cedente más cercano es el inteligente libro de Bertrand Meyer “Object Oriented
Software Construction”, 1988, donde se explicitaban también las decisiones de
diseño del lenguaje Eiffel. Así que ... ¡alto! ¿Oigo las quejas de algún lector?
Humm, las comparaciones no son odiosas: la estupidez y la banalidad, en contra-
partida, sí son odiosas. Considero que aunque C++ se pervirtiera y sólo se usara
en el BOE, el libro seguiría siendo absolutamente recomendable. Si uno compara
las decisiones de diseño que se notan en este libro con las de otros lenguajes
como Java, el resultado es escandaloso. Al fin: racionalidad seria para un texto
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 206
inteligente y sentido. No se lo pierdan.
Tras superar la etapa introductoria y asimilar los recursos del lenguaje, lo siguien-
te es aprender a codificar en C++ con efectividad y limpieza. Los textos que se
detallan a continuación pretenden cubrir la etapa intermedia de formación del
programador de C++, recalando más que en la sintaxis en los esquemas concep-
tuales que subyacen bajo ésta.
Effective C++: 50 Specific Ways to Improve Your Programs and Designs, por
Scott Meyers, 1992, Addison-Wesley, 0-201-56364-9.
Este libro es, en esencia, una colección de 50 consejos sobre programación en
C++, debidamente comentados y justificados. Pero no se trata de un recetario al
uso, sino más bien de un compendio de líneas maestras, interrelacionadas entre
sí (como el lector pronto descubre) y tendentes a procurar al lector este tipo de
conocimiento que subyace tras la seca sintaxis del lenguaje. Así, aunque el len-
guaje permite usar con libertad la derivación pública, la aproximación de éste al
espíritu de OOD exige que tal derivación se use solamente cuando se da una re-
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 207
lación de subtipo (o sea, de "ES-UN") entre las clases a relacionar. El lenguaje
permite, también, por ejemplo, la redefinición en clases derivadas de funciones
miembros no-virtuales de las clases base: esta práctica vulnera, sin embargo,
como bien indica Meyers, la cualidad de coherencia de los programas: el com-
portamiento de un objeto variará dependiendo del puntero desde el que sea ac-
cedido. Como vemos, los casos estudiados son de enorme utilidad práctica. Jun-
to a éstos se exponen técnicas que suelen pasar desapercibidas a los principian-
tes en C++, como, por ejemplo, el chequeo de auto-asignación en la implementa-
ción del operador de asignación de una clase. Así, nos encontramos en el índice
con secciones como las siguientes: "Nunca redefinas el valor heredado de un pa-
rámetro por defecto", "Cualifica los destructores como virtuales en las clases ba-
se", "Chequea el valor de retorno de new", "Evita los datos miembros en el inter-
faz público", para terminar con "Lee el ARM". El libro, totalmente recomendable,
proporciona al lector la inteligencia de cómo usar los recursos sintácticos de C++
asimilados de los textos introductorios clásicos. Además, su lectura es tan amena
como la de una novela policial. Y para los que gusten de segundas partes he de
decir que Meyers amenazó con más consejos en su nuevo libro.
C++ Programming Style, por Tom Cargill, 1992, Prentice Hall, 0-201-56365-7
Junto con el libro de Meyers, configura una de las mejores inversiones en papel
impreso que puedan realizar los ya iniciados en el lenguaje C++. El enfoque
adoptado por Cargill es, no obstante, distinto al de aquél: en vez que acopiar re-
glas parciales y supuestamente independientes (como una shopping list), el libro
reúne porciones de código extraídas de otros textos de C++ y de productos co-
merciales, para luego examinarlos con el ojo crítico del estilo. Es sorprendente la
cantidad de elementos perturbadores, y aun de graves errores, que Cargill hace
aparecer ante nuestros ojos, demasiado acostumbrados a las revisiones rutina-
rias y a los esquemas del mínimo esfuerzo. Se tratan, así, temas como "Herencia
innecesaria", "Consistencia de clases", etc. analizando codificaciones de clases
como "String", "Stack", "Máquinas de Estados Finitos", etc. Cargill pretende im-
buir al lector de determinadas reglas de buen estilo en C++, tales como las si-
guientes: "Identifica el delete para cada new", "No uses un constructor para inicia-
lizar datos miembros estáticos", "Considera los argumentos por defecto como
una alternativa a la sobrecarga de funciones", etc. Como se puede fácilmente
apreciar, el texto no tiene desperdicio. El tipo de conocimiento que procura es,
por otro lado, de una madurez matizadamente más clara que en el anterior texto,
pues el lector adquiere una visión global de la cohesión del estilo a imprimir al
código. El mismo Scott Meyers reconoce su proximidad a este texto, indispensa-
ble a todo programador de C++.
C++ Programming Guidelines, por Thomas Plum & Dan Saks, 1991, Plum
Hall, 0-911537-10-4, 274 pág.
Los que experimenten cierta aversión por las colecciones de reglas y los manua-
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 208
les de estilo, encontrarán en este libro el arquetipo de sus pesadillas. Al menos en
el formato. Se trata, en efecto, de secciones codificadas que observan el siguien-
te esquema: TÓPICO (por ejemplo, 6.06 virtual_fct - funciones virtuales), REGLA
(descripción de las líneas maestras de estilo correspondientes al tema del título),
EJEMPLO (demostración práctica de la problemática contextual en que se desa-
rrolla la regla), JUSTIFICACIÓN (argumentación de apoyo, tanto mediante razo-
namiento directo como a través de informes y textos externos, de la regla expues-
ta), ALTERNATIVAS (opciones de la regla consideradas menores, o aun imprac-
ticables), NOTAS LOCALES (media página al menos, y normalmente página y
media, en blanco para el supuesto apunte de notas por el lector). Bien, decíamos
que una tal rígida esquematización pudiera resultar demasiado restrictiva. El pre-
sente texto es, sin embargo, enormemente provechoso. Muy en la línea de un an-
terior libro de los mismos autores ("C Programming Guidelines"), sus distintas
secciones tienden a reforzar una idea que los principiantes en C++ rápidamente
relegan al olvido: C++ no es C. C++ no es, tampoco, Smalltalk o Eiffel. Se trata de
sistematizar las soluciones a los cuellos de botella en la gestión de proyectos en
C++, fundamentalmente cuando intervienen equipos de más de dos personas: a
este fin se explicitan convenciones para nominar identificadores, facilidades para
comentar código, gestión de sobrecargas, etc. El libro es, en definitiva, un com-
pañero a tener muy en cuenta ante el diseño efectivo de clases realmente cohesi-
vas y portables.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 209
LIBROS DE PROGRAMACIÓN MEDIA Y AVANZADA EN C++
Advanced C++ Programming Styles and Idioms, por James O. Coplien, 1992,
Addison-Wesley, 0-201-54855-0.
Este es uno de esos escasos libros que redimen, con sobriedad textual y derro-
che de inteligencia, el aluvión de tonterías y libros triviales sobre C++ y OOP que
nos están inundando de forma inmisericorde. Al Stevens ha llegado a decir que
este texto representa para C++ lo mismo que el de Kernighan & Ritchie represen-
tó para C: bien, quizá este comentario se limite a exteriorizar una pasión (fácil de
comprender, por otra parte), porque sería más lógico aplicar tal comparación al
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 210
texto de Stroustrup, pero ciertamente indica un cierto estado de ánimo que per-
manece al terminar el texto. Siendo este libro uno de mis preferidos, mi única re-
comendación es: ¡cómprenlo!. Pero, ¿de que trata esta obra? ¿De técnicas más
o menos elaboradas de codificación en C++? Bien, no exactamente. Tras una
breve, rigurosa y modélica introducción a los más interesantes tópicos del lengua-
je, el autor nos anuncia de la existencia, dentro del lenguaje C++, de "idiomas"
autónomos: esto es, de abstracciones por encima del nivel sintáctico elemental
del lenguaje y que configuran, a partir de distintos supuestos, unas formas de co-
dificar y un sustrato conceptual esencialmente distinto entre cada una de ellas.
Recordemos, por ejemplo, que Stroustrup nos indica que los constructores en
C++ no pueden ser virtuales, pero, a la vez, expresa que con facilidad se puede
suplir tal característica. Coplien (Cope para sus amigos) habla, sin embargo, de
un "idioma de constructores virtuales". Tomemos como ejemplo este idioma para
que el lector pueda entender mejor qué se esconde tras tal denominación. Un
mensaje virtual permite posponer al tiempo de ejecución la ligadura entre prototi-
po e implementación de la función asociada; o sea, el mensaje se enviará a un
objeto, desconocido en tiempo de compilación, y éste responderá de la forma
más apropiada. Un constructor virtual supone lo siguiente: a un objeto, cuyo tipo
exacto desconocemos, se le envía el mensaje "constrúyete", y éste eligirá el mé-
todo de construcción apropiado pues, ¿quién habría de saber más de construirse
que el objeto en sí?. Mediante la estructuración de una codificación que permita
simular este comportamiento nos podríamos encontrar, por ejemplo, con que nin-
guno de los tipos de los objetos de nuestra aplicación sería chequeado en tiempo
de compilación, pues el tipo exacto de un determinado objeto no nos haría falta ni
siquiera para construirlo. Piense el lector que, de un plumazo, nos hemos "carga-
do" una de las cacareadas características de C++: el fuerte chequeo de tipos.
Piense ahora el lector cómo sería codificar en C++ sin el chequeo de tipos: ¡mu-
chas de nuestras ideas predeterminadas habrían de cambiar! ¡muchísimo de
nuestro código ya no tendría sentido! Es como si, de repente, estuviéramos traba-
jando con un dialecto de C++: con un "idioma". Coplien describe algunos idiomas
adicionales en su libro: "idioma de ejemplares", "idioma de estructuración en blo-
ques", "idioma de lenguajes simbólicos", "idioma de herencia dinámica múltiple",
etc. Ningún programador de C++ que aspire a algo más que a la codificación de
una lista enlazada debería dejar de leer este texto. Hay que recabar, no obstante,
que al lector se le supone un conocimiento adecuado de AT&T C++ 3.0, versión
en que la obra está basada. Una última nota: los apéndices son realmente intere-
santes, y convienen en procurar al lector un agradable sensación de efectividad.
The Power of Frameworks for Windows and OS/2 Developers, por Taligent
Inc., 1995, Addison-Wesley, 0-201-48348-3.
Teniendo en cuenta la disolución del trió Appel-HP-IBM, la inclusión de este texto
pudiera parecer vana. Lo cierto es que aun habiendo desaparecido el entente
conjunto, IBM finalmente se quedó con la tecnología, y ésta se repartirá en sus
productos de forma inexorable (como ya está ocurriendo). El texto es francamente
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 211
comercial, como un buen catálogo técnico, e intenta susurrarnos a cada página
“¿Viste que buena idea? ¿Observaste que inteligente implementación? ¿Notaste
que elegante jerarquía?”. Lo mejor de todo es que las ideas, implementaciones y
jerarquías son endiabladamente buenas, así que un repaso amable de estos
“frameworks” seguro que aclara a más de uno las ideas sobre qué pedirle a una
biblioteca-entorno de clases. De hecho este libro suple una carencia habitual en
la documentación de las bibliotecas comerciales de clases: índica algunas
decisiones de diseño. Por lo demás es una buena lectura de verano y un
agradable repaso de un ambicioso proyecto que quizás debiera haberse
planteado en otro lenguaje de programación (y ésta es una opinión de Andy
Novobilsky).
Data Abstraction and Object-Oriented Programming in C++, por Keith E. Gor-
len, Sanford M. Orlow & Perry S. Plexico, 1990, John Wiley & Sons, 0-471-
92346-X, 403 pág.
Este texto está basado en el estudio realizado por los autores para proveer de
optimizaciones software a los sistemas UNIX de los Institutos Nacionales de Sa-
lud (NIH) en USA. Se trata, en esencia, de una biblioteca de clases envolvente
(conocida como biblioteca NIH) modelada a imagen y semejanza del entorno
Smalltalk-80 y prescindiendo de las capacidades gráficas de éste. El libro exige
un solvente conocimiento previo de C++ y se apoya en AT&T C++ 2.0. Usando la
terminología de Coplien, podríamos decir que aquí se genera un "idioma tipo
Smalltalk", y lo cierto es que lo que en el texto se expone ha tenido una extraordi-
naria y reconocida influencia en el desarrollo de un gran conjunto de entornos de
aplicación y bibliotecass de clases genéricas. El provecho que los programado-
res de C++ pueden extraer de la obra es evidente, pues ésta está montada como
un tutorial, explicando detalles y decisiones de diseño de las clases (algunas de
ellas inapreciables para la adecuada construcción de componentes reutilizables,
una de las expectativas más cacareadas y, a la vez, más difíciles de C++) y, tras
esto, directamente utiliza el entorno creado como herramienta de desarrollo, ex-
plicando la posible extensión del sistema. La biblioteca NIH incluye clases como
Iterador, Bolsa, Diccionario, Tiempo, Vector, Fecha, Colección, Pila, Objeto (la
raíz de la biblioteca "cósmica", pues tal es el nombre por el que se conocen las
bibliotecas con una única clase base inicial). Como el lector puede fácilmente
intuir, este tipo de bibliotecas propende al usuario a practicar la derivación múlti-
ple, y dadas las dificultades no siempre evidentes que esto entraña, el libro dedi-
ca un largo capítulo a este respecto. Se detalla, incluso, un ejemplo de aplicación
de base de datos usando la biblioteca. ¿Mi sugerencia? Bien, el fuerte entronca-
miento de los conceptos de OOD con el acertado uso de C++ procuran un exce-
lente texto de uso referencial, de valiosísima lectura para cualquier programador
de C++ y aun de los estudiosos de OOP; las ventajas y defectos del enfoque tipo
Smalltalk adoptado, por otro lado, disgustarán o deleitarán al lector, dependiendo
en buena medida de su estilo y costumbres, pero esto aguzará, alternativamente,
el ojo crítico o el gozo del lector. ¡Léanlo!
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 212
C++ Strategies and Tactics, por Robert B. Murray, 1993, Addison-Wesley, 0-
201-56382-7, 273 pág.
Como el mismo título indica, Bob Murray, editor durante muchos años de C++
Report, ha querido mostrar, como en ajedrez, las estrategias y componendas que
trascienden los meros movimientos de las piezas del juego. No es exactamente,
en general, un libro "avanzado" sobre el lenguaje, sino que más bien ocupa ese
estadio intermedio entre los libros de estilo y la practicidad del código realmente
efectivo. En este sentido los dos capítulos dedicados a las plantillas ("templates")
justificarían, por sí solos, la lectura del libro, pues dada la novedad comercial de
esta adición al lenguaje, pocos textos se han ocupado hasta la fecha de revisar,
de forma seria, algunos aspectos no triviales de la misma. Junto con las plantillas,
el buen diseño de jerarquías de herencia en C++ y la reusabilidad del código ocu-
pan el grueso de la obra, que, además, procura un capítulo sobre el manejo de
excepciones. Nos encontramos, pues, ante una obra moderna y de potente clari-
dad, pensada para el lector no-experto y que contiene ejercicios, resúmenes y
una buena cantidad de ideas y sugerencias de buen diseño en C++. En definitiva,
una adición indispensable para la biblioteca de C++.
Designing and Coding Reusable C++, por Martin D. Carroll y Margaret A. Ellis,
1995, Addison-Wesley, 0-201-51284-X.
¿Reúso? ¿No es la característica esencial y automática de toda codificación en
C++? ¿No es una de las bases de la Orientación a Objetos? ¿No está ciertamen-
te de más un libro sobre algo que resulta evidente a todo programador en C++
imbuido en los fabulosos esquemas de la Programación Orientada-a-Objetos?
Bueno: sí, no, sí y no, respectivamente. A la Dra. Ellis la reconocerá el lector como
co-autora del ARM y co-columnista junto con Carroll (de AT&T Bell) en la revista
“C++ Report”. El libro es francamente bueno y muestra lo que da de sí un lenguaje
dúctil como C++: si en la mayoría de los textos al alcance del hirsuto lector se pri-
ma la eficiencia como alma mater del lenguaje, aquí se ensalza la capacidad de
reutilización por encima de aquélla. La buena noticia es que los autores analizan,
para cada posible tópico, los inconvenientes de la fijación en el reúso, y propor-
cionan estrategias, técnicas y trucos que habrán de incorporar el acerbo de expe-
riencia del programador prudente de C++. Las plantillas se utilizan profusamente
en el texto (que expresamente se desdice de los contenedores de tipo Smalltalk)
y el tono escéptico respecto del reúso de código es realmente de agradecer. Con
los pies bien plantados en tierra, la obra habla de diseño de clases, extensibili-
dad, eficiencia, errores, conflictos, compatibilidad, jerarquías de herencia, porta-
bilidad, uso de bibliotecas de clases ajenas, documentación y otros interesantes
tópicos (el lector avisado notará que he descrito el índice). Las ideas que aquí se
dan sobre excepciones, herencia invasiva, el uso de “const”, clases endógenas,
instanciación de plantillas, etc. son de una practicidad tal que el lector no podrá
por menos que exclamar: ¿Cómo nadie me recomendó este libro antes? En fin,
una obra indispensable.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 213
Taming C++: Pattern Classes and Persistence for Large Projects, por Jiri
Soukup, 1994, Addison-Wesley, 0-201-52826-6.
Teniendo el cuenta en panorama de obras sobre C++, el título anterior puede ha-
cer segregar jugos gástricos a más de un jefe de departamento o responsable de
proyectos no-triviales en C++. Bien: el texto, como aparece en su presentación,
versa sobre “las cosas obvias y simples que llevan a buen puerto o hacen
fracasar a los grandes proyectos”. De hecho su elección suele ir ligada al texto de
Taligent sobre estilo de codificación en C++, y se fundamenta en el sentimiento
de inseguridad que se genera al unir un equipo de personas mediante el pega-
mento C++. Aparte de los discutibles porciones dedicadas a la persistencia de
datos (un tanto forzadas por la actividad empresarial del autor) el libro está pla-
gado de revisiones, técnicas y consejos que intentan reflejar el éxito del autor en
su propia aventura C++ post AT&T. Así, por ejemplo, en el capítulo “Bibliotecas de
Patrones” se examinan estructuras, problemas de distintas bibliotecas actuales
(Tools.h++, NIH, Componentes C++ de Booch, etc.) para concluir con una biblio-
teca ideal: la implementada por Code Farms (la empresa del Sr. Soukup). Pero
en realidad esto es totalmente legítimo, pues nadie puede hablar de una expe-
riencia que no ha obtenido, y no hablar de experiencia es mentar el aire, claro.
Pues bien, el autor expone sus personales ideas sobre dependencias entre cla-
ses, tipos de datos abstractos, generación de patrones y ... persistencia. Es cier-
to, también, que la palabra resonante “patrones” en el título no encontró eco en la
comunidad establecida de patrones, así como las ideas del Sr. Soukup, siendo
radicales, son discutidas. Pero la verdad es, al fin, que este es uno de los pocos
libros que hablan de C++ en su relación con grandes desarrollos y, en este senti-
do, es imprescindible.
¿Smalltalk? ¿Por qué Smalltalk? Bueno, querido lector, Smalltalk es uno de los
lenguajes de más rancio abolengo dentro del mundillo de la Tecnología de Obje-
tos, y su influencia ha resultado decisiva en los aspectos prácticos de desarrollo
de las bibliotecas de C++. Además la literatura Smalltalk posee un tanto a su fa-
vor: al ser éste un lenguaje que aparentemente no está “en la cresta de la ola” y
que conserva un cierto rigor academicista (rigor mortis le llaman algunos) la tonte-
ría no ha penetrado de forma irremediable en su acervo bibliográfico. No se dan
así, al menos todavía, libros del tipo “Programe en 15 horas con Smalltalk, asom-
bre a sus amigos y dé un nuevo rumbo a su vida sexual”. Esto aparentemente
quiere decir que casi todos los libros actuales sobre Smalltalk son intelectualmen-
te legibles y no causan daños neuronales irreparables. Y la verdad es que, aunque
sin competencia respecto de C++, existe una buena cantidad de libros sobre
Smalltalk, pero, puestos a elegir, he aquí mi selección, aproximada y pretendida,
pero no necesariamente, en orden creciente de dificultad:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 214
Programación Orientada a Objetos: Aplicaciones con Smalltalk, Angel Mo-
rales & Francisco J. Segovia, 1993, Paraninfo, 84-283-2019-5.
Es éste el único libro original en castellano que, de forma pedagógicamente re-
glada, procura una razonable introducción al lenguaje, bien aderezada, además,
de ejemplos prácticos completos cuya utilidad, sin embargo, no sobrepasa el
ámbito de la didáctica académica. Resulta curiosamente actual el tendencioso
ejemplo en el que Empresarios, Funcionarios, Intermediarios, Matones y Perio-
distas son, por fuerza, Políticos (derivan de esta clase), y un objeto de tipo Em-
presario soborna a un objeto de tipo Funcionario conocido como John War (nada
que ver con Monsieur Alphonse, a lo que parece). Los ejemplos son, en general y
según lo visto, muy amenos (no faltan las ubicuas “Torres de Hanoi”), a la vez que
la primera parte teórica es suficientemente exacta: se describe el dialecto Small-
talk-80 de forma que se consigue adentrar en los conceptos básicos del lenguaje
a lectores con conocimientos al menos básicos de algún otro lenguaje de pro-
gramación, quizás Pascal o similar. Se echa quizás en falta un disquete con el
código de los ejemplos, siempre deseable en Smalltalk por las facilidades de
experimentación con el mismo.
Smalltalk Programming for Windows, Dan Shafer con Scott Herndon y Laur-
ence Rozier, 1993, Prisma Publishing, 1-55959-237-5.
Este libro es una revampirización del texto “Practical Smalltalk: Using Smalltalk/V”
de Dan Shafer y Dean Ritz, publicado en 1990 por Springer-Verlag. La obra des-
cribe ejemplos prácticos sobre Smalltalk/V versión 2.0 para Windows, y asume un
conocimiento cuando menos elemental de Smalltalk y de la programación Orien-
tada-a-Objetos, abordando la enseñanza mediante el desarrollo completo y gra-
dual de siete proyectos bien engarzados y cuyo código completo se acompaña
en un disquete: un “prioritizador” (un secuenciador de ítems en base a priorida-
des), un contador simple (con botones de incremento y decremento), un calenda-
rio con interfaz gráfico, un agenda de citas (que se añadirá al calendario), un pa-
quete gráfico elemental, un diseñador de formularios y un reloj multiproceso. El
texto está muy pegado a la tierra, y el nivel es bajo-medio. Resulta aconsejable su
lectura tras el estudio de los manuales de Smalltalk/V, quizá demasiado etéreos.
Object Oriented Programming, Peter Coad & Jill Nicola, 1993, Prentice-Hall, 0-
13-032616-X, con disquete del código C++ y Smalltalk.
El libro resulta sorprendentemente fresco, detallado y específico comparado con
los anteriores de Coad y Yourdon sobre OOA/OOD, y, la verdad, resulta muy di-
vertido de leer: se puede acabar de un tirón. Mediante el análisis, diseño e im-
plementación de distintos pequeños proyectos, en creciente grado de dificultad,
pero siempre muy pedagógicos (un contador elemental, una maquina vendedora,
un sistema de soporte de ventas y un sistema de control de tráfico), se introduce
al lector en un discurrir donde se alternan C++ y Smalltalk, convirtiéndose así en
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 215
una perfecta obra ambivalente de introducción a ambos lenguajes. Los autores
intentan, a la vez -y parece que consiguen-, imbuir al lector en lo que denominan
“object-thinking”, una suerte de estructuración mental en la que se ven objetos por
doquier en cualquier área39. En fin: un texto ameno y recomendable, de nivel me-
dio.
Smalltalk-80: The Language, Adele Goldberg & David Robson, 1989, Addison-
Wesley, 0-201-13688-0.
Este libro es un clásico y representa la segunda edición, convenientemente modi-
ficada y remozada, del anterior texto “Smalltalk-80: The Language and its Imple-
mentation”, familiarmente conocido como “libro azul”, de los mismos autores, pu-
blicado por Addison-Wesley en 1983, que contenía una interesante especifica-
ción, desaparecida en la presente edición, para la construcción de una máquina
virtual Smalltalk-80 (una buena razón para disponer de las dos obras). Este texto
se apoda “libro púrpura” y está estructurado como un manual de acceso y des-
cripción del lenguaje: la introducción sintáctica es seguida por un repaso de los
recursos del lenguaje-entorno para acabar con la exposición de distintas aplica-
ciones de simulación discreta orientada-a-eventos. El tono de la obra es exacto y
su lectura resulta cómoda y estimulante. En definitiva, como dicen los americanos,
un “must-have”.
39
Con esto pasa como con el tabaco y los vicios mayores: los más convencidos de la “objetivi-
zación mental” son precisamente los “estructuralistas arrepentidos”. Y la pregunta es ¿cuándo se
fundará “Estructuralistas Anónimos”? Hay ciertos pecados que necesitan pública confesión.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 216
Smalltalk-80: The Interactive Programming Environment, Adele Goldberg,
1984, Addison-Wesley, 0-201-11372-4.
Originalmente concebido como documentación de usuario del sistema Smalltalk-
80 de Xerox, debido a la extraordinaria integración del entorno con el lenguaje en
sí, este texto (denominado, según la costumbre, con el color de su portada: “libro
naranja”40) describe, en forma de manual tutorado, la interfaz de usuario del entor-
no-lenguaje, las técnicas de extracción de información de los objetos del sistema,
las operaciones CRUD sobre clases, la depuración del código y las relaciones
del entorno respecto del exterior. El libro presenta suficientes ilustraciones gráfi-
cas y el estilo es adecuadamente paternal. En fin, un manual “clásico”41.
Inside Smalltalk I, Wilf LaLonde & John Pugh, 1990, Prentice-Hall, 0-13-
468414-1.
Esta obra, junto con el segundo tomo, representa para los años 90 lo que para los
80 los textos de Goldberg y Robson. El papel impreso quédase obsoleto con mu-
cha rapidez, pero así y todo está obra es indispensable para todo aquél que quie-
ra trabajar de forma seria en Smalltalk. En este tomo se describen los fundamen-
tos del dialecto Smalltalk-80 versión 2 y de su entorno de programación, junto con
el detalle de las clases básicas y la gestión de imágenes gráficas.
Inside Smalltalk II, Wilf LaLonde & John Pugh, 1990, Prentice-Hall, 0-13-
465964-3.
Este tomo, inseparable compañero del anterior, se centra en la construcción de
aplicaciones con IGUs VIMP 42. Centrándose en el paradigma MVC (Modelo-
Vista-Controlador) con una profundidad difícil -si no imposible- de hallar en otros
textos, los autores introducen al lector con detalle, rigor y precisión en las opera-
ciones con ventanas, menús, ventanas emergentes, etc., para acabar con casi
200 páginas en las que se discute y expone el diseño e implementación de un
“constructor de ventanas” (una suerte de asistente que proporciona facilidades
gráficas para la creación de interfaces de usuario), una aplicación de tamaño
medio de gran interés. Se trata de una obra imprescindible.
40
El inquieto lector podría preguntarse si existen más “libros de colores”. Pues, bien, sí: al texto
“Smalltalk-80: Bits of History, Words of Advice”, de Glenn Krasner, editor, Addison-Wesley, 1983,
ISBN 0-201-11669-3, se le denomina “libro verde”. Nada malicioso, empero.
41
Mark Twain socarronamente afirmaba que “un clásico es un libro que todo el mundo elogia y
nadie lee”. Ya sabe, lector: sea original y lea.
42
VIMP (Ventanas, Iconos, Menú y Puntero) es la aventurada grafía castellana de WIMP.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 217
Smalltalk/V: Practice and Experience, Wilf LaLonde & John Pugh, 1994, Pren-
tice-Hall, 0-13-814039-1, con disquete.
LaLonde y Pugh son, entre otras cosas y desde hace tiempo, columnistas perma-
nentes de la sección Smalltalk del JOOP (Journal of Object-Oriented Program-
ming), de SIGS Publications. Fruto del ingente material publicado en sus colum-
nas es el presente texto, en el que se presentan convenientemente remozados
algunos casos prácticos de programación orientada-a-objetos en Smalltalk/V pa-
ra Windows. El libro está pensado, como los mismos artículos, para lectores con
conocimientos medios de Smalltalk, aunque como los casos son realmente inte-
resantes (conjuntos borrosos, intercambio dinámico de datos, combinación de
componentes modales y no-modales para construir un visor gráfico, etc.), la lectu-
ra de las 185 páginas del texto resultarán tan valiosas para los expertos como
para los recién llegados al lenguaje.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 218
inicial respecto de la rara nomenclatura de patrones utilizada se torna pronto en
un reconocimiento respetuoso a la experiencia de quien sabe de qué habla (y
sólo por esto el lector ya debería ir corriendo a adquirir este indispensable libro).
¿Java? ¿Java? ¿Java? Pues sí, parece que la unión de palabras resonantes (In-
ternet, C++, Smalltalk, herencia, etc.) ha dado en generar un síndrome ansioso
respecto de este lenguaje. A buen seguro que cuando el lector revise esta sec-
ción habrán ya aparecido decenas de libros sobre Java, la mayoría de ellos cri-
minales o simplemente estúpidos. La cuestión es, en lo que a este texto respecta,
su comparación respecto de C++. El lector podrá encontrar en internet papeles,
índices, métodos, referencias e incluso manuales completos, libros en pre-edición
y comentarios diversos a los distintos aspectos del lenguaje/entorno Java. Lo que
ocurre es que la naturaleza volátil de internet sigue aconsejando fiar el conoci-
miento de la seguridad de las hojas impresas. He aquí algunas de ellas:
Hooked on Java: Creating Hot Web Sites with Java Applets, por Arthur van
Hoff, Sami Shaio y Orca Starbuck, 1995, Addison-Wesley, 0-201-48837-X, con
CD-ROM.
Los autores, miembros del equipo de desarrollo de Java en Sun Microsistems
Inc., exponen en este texto la euforia de un proyecto con una liviandad que causa
escalofríos. Mi pronta reacción a la primera lectura del libro fue la de decepción
clara: mucho web, muchos applets, mucha euforia, pero poco lenguaje y dema-
siadas decisiones de diseño tomadas muy a la ligera, como porque sí. Van Hoff
es el autor del compilador Java e impulsor de Hot Java, mientras que Shaio dise-
ñó e implementó el conjunto de herramientas de interfaz de usuario (a la vez que
el mecanismo de seguridad de los applets) y Starbuck básicamente se ocupó de
la documentación. El libro a menudo refleja la vivacidad de Duke, la mascota Ja-
va, y semeja una versión descafeinada de Ecce Homo: “¿Por qué soy tan inteli-
gente?”, “¿Por qué escribo tan buenos libros?”, “¿Por qué soy un destino?”43. Con
todo el texto se deja leer y querer, como un buen pasatiempo, pues dedica su
mayor parte a la descripción de applets y de páginas web. El CD-ROM que lo
acompaña incluye todos estos applets, código y páginas web de ejemplo y el
JDK para Windows 95/NT y Solaris 2.X. Así resulta que el libro es totalmente re-
comendable, pues frente a la tontería de los muchos artículos que inmisericordes
ya se han publicado, la ligereza exenta de errores y las opiniones de primera ma-
no finalmente resultan un buen plato. Si no le interesa Internet (o, en el mejor de
los casos, Intranet), lo mejor será, por otro lado, que olvide Java.
43
Recapacite el lector que Nietzsche admiró profundamente a Wagner antes de denostarlo por su
decadencia insoportable, así que la comparación musical con el C++ quizás no resulte desafor-
tunada.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 219
Mecklermedia’s Official Internet World 60 Minute Guide to Java, por Ed Tittel
y Mark Gaither, 1995, IDG Books, 1-56884-711-4.
Este texto es exactamente lo que anuncia: una guía que se pretende tan supues-
tamente fácil como el lenguaje que describe. La verdad es que el enfoque sintéti-
co favorece enormemente la comprensibilidad y el lector puede acceder a
información práctica librándose de bastante basura literaria. Así, en 253 páginas,
los autores describen las características básicas del entorno Java, del lenguaje en
sí y de los applets, para pasar a examinar con más detalle estos últimos en el con-
texto de internet/html, y después exponer varias técnicas de codificación de apli-
caciones Java (incluido el ejemplo de un manejador de protocolos) y hablar de su
futuro. La descripción de la gramática de Java y del API que conforman lenguaje,
bibliotecas y Hot Java terminan de redondear el texto. Naturalmente el libro no
enseña a programar, sino que más bien muestra ordenadamente lo que finalmen-
te hay (muchos adverbios). En fin, que lo más agradable del texto es su carencia
de pretensiones.
The Java Handbook: The Authoritative Guide to the Java Revolution, por
Patrick Naughton, 1996, Osborne McGraw Hill, 0-07-882199-1.
Pese al petulante título, éste es quizá el más completo de los títulos aquí referidos.
Naughton cofundó FirstPerson Inc. y participó de forma clave en el proyecto
“Green” que dio lugar finalmente a Java, así que la información que aquí se da no
es producto de la publicidad del momento. En la primera parte se detalla el len-
guaje; en la segunda las clases del mismo y en la tercera el diseño detallado de
applets (quizá la literatura más precisa que hasta ahora haya leído sobre el tema).
El tono es abiertamente anti-C++, pero la gracia es que se pretende justificar ca-
da decisión de Java en razón de las supuestas insuficiencias de C++: así se dice
que C++ no es totalmente orientado-a-objetos por execrables razones de compa-
tibilidad y eficiencia (no como Java, claro), y sin embargo se da por sentado que
la decisión de Java de no considerar las clases como objetos en favor de la efi-
ciencia es absolutamente encomiable. El libro, con todo, está mucho menos infla-
do de aire que el de “Hooked on Java” y su lectura resulta divertida y estimulante,
sobre todo en los ejemplos de applets (donde se delata, de paso, la insuficiencia
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 220
clara de la actual versión de la AWT): el applet “Impresionista”, “DynaDraw” y
“Poesía en Imanes”. Si sólo ha de comprar un libro sobre Java, adquiera éste.
The Java Primer Plus: Supercharging Web Applications with the Java Pro-
gramming Language, por Paul M. Týma, Gabriel Torok y Troy Downing, 1996,
Wayte Group Press, 1-57169-062-X.
Con un título que podría venderse al peso y muy al estilo de la mayoría de los tex-
tos de el Grupo Wayte, esta obra intenta un acercamiento general al lenguaje y a
las bibliotecas de clases que comprende sin olvidar aspectos como la compara-
ción con C/C++, etc. El libro es muy completo y asequible, constituyendo una
suerte de manual de referencia elemental del lenguaje y su entorno, con muchos
dibujos bien cuidados y sin entrar en demasiadas profundidades. El CD que re-
gala incorpora la versión 1 del JDK, ya desfasada en favor del Java Workshop,
además del código fuente usado en el libro, applets incluidos. Nada nuevo, pero,
eso sí, explicado clarito y agradablemente. La parte III se titula “Uso de las capa-
cidades avanzadas de Java” y resulta la más interesante del libro, pues trata de
asuntos de red, hilos (threads), estructuras de datos, interfaz con C, gráficos y
sonidos.
El lector podría preguntarse aquí: ¿realmente necesito de textos sobre ideas ge-
nerales de la orientación-a-objetos? ¿Qué ayuda me pueden prestar tales ideas
en los procesos diarios de codificación en C++? Bueno, recordemos que C++ es
un lenguaje con facilidades para la Programación Orientada-a-Objetos, y que tal
es, en definitiva, la fase de implementación, tras las fases de diseño y análisis
orientados-a-objetos, de los objetos y sus relaciones modelados en base a los
conceptos de orientación-a-objetos a través de los que se matiza y visualiza nues-
tro problema en el mundo real. Las ideas generales de este nuevo paradigma nos
pueden ayudar, normalmente de forma inestimable, a encauzar nuestras codifica-
ciones hacia modelos conceptuales más adecuados a la nueva orientación, con-
siguiendo que nuestro software sea más robusto y fiable.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 221
parte de los cursos de OOA & OOD que imparto. La exposición es sorprenden-
temente concisa, de forma que la revisión de conceptos supuestamente conoci-
dos por el lector se torna en extremo interesante. Tras este análisis general de los
sistemas orientados a objetos, el Dr. Meyer se cuestiona por un lenguaje con faci-
lidades para su implementación, y como quiera que, según sus propias palabras,
no encuentra ninguno, decide crear el suyo propio, sujeto con exactitud al para-
digma de objetos. Aparece así Eiffel, lenguaje orientado a objetos puro donde los
haya, de sintaxis tipo Pascal e interesantísimas características. Pero, ¿interesa
esto al programador de C++? Así lo creo. El Dr. Meyer no se limita a describir el
lenguaje, sino que, como artífice del mismo, explica las disyuntivas en las decisio-
nes de diseño y justifica las medidas adoptadas en cada caso, trayendo a cola-
ción interesantes problemas presentes en muchos de los diseños orienta-
dos-a-objetos. Como ejemplo sirva el tratamiento que en el lenguaje se dan a lo
que se denominan "precondiciones" y "postcondiciones": su claridad conceptual
ha redundado en que, en aras de la modularidad, limpieza y coherencia del códi-
go, tal enfoque haya sido posteriormente adoptado por distintas bibliotecas de
C++, como, verbigracia, "Tools.h++" de Rogue Wave. Una tercera parte del texto
se ocupa de revisiones genéricas de lenguajes clásicos de programación, así
como de sus extensiones a objetos, y aun de C++, Smalltalk, Ada, etc. Se revisan
también cuestiones de herencia y, de forma leve, cuestiones como la persistencia
de objetos, que en el momento de publicación de esta edición no estaban todavía
en el ojo del huracán, como ocurre ahora. En los apéndices se retoma, por fin, el
lenguaje Eiffel a modo de fragmentos referenciales. Se trata, en resumen, de un
libro indispensable para cualquier con pretensiones mínimamente serias en el
ámbito de la OOP: reserven, pues, un hueco en su estante para él.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 222
Object-Oriented Methods, 2 nd Edition, por Ian M. Graham, 1994, Addison-Wes-
ley, 0-201-59371-8, 473 pág.
Es éste un libro caracterizado por la perspectiva globalizadora bajo la que se con-
templan las ideas y conceptos de orientación-a-objetos. La impronta pragmática
británica se deja notar, y su lectura es realmente amena. El texto comienza con
una bien entramada introducción crono-sectorial a los tópicos de la OOT: concep-
tos básicos, lenguajes de programación orientados-a-objetos, WIMPs, bases de
datos relacionales, bases de datos orientadas-a-objetos, etc.; hasta llegar a la
parte más significativa: análisis y diseño orientados-a-objetos. Aquí Graham, tras
una revisión crítica de bastantes métodos (Coad/Yourdon, Desfray, OOSE, OMT,
OOSA, etc.), expone su “metodología” (las comillas son mías) SOMA 44, una varia-
ción de Coad/Yourdon a la que se han añadido, simplificando, "triggers". La
orientación-a-objetos es filtrada a través de la experiencia del autor en los cam-
pos de inteligencia artificial e ingeniería del conocimiento y, así, resulta curiosa y
enormemente instructiva (a la par que descorazonadora y un tanto pretenciosa),
por ejemplo, la facilidad con que Graham aborda la fase de identificación de obje-
tos y de sus relaciones. La prototipación aparece descrita, seguidamente, de una
forma esclarecedora, para terminar con un vistazo al futuro posible y un muy inte-
resante apéndice sobre "objetos borrosos". En fin, se trata de un texto muy acon-
sejable para aquéllos que busquen una visión integradora de las nuevas técnicas
en el continuum de la evolución informática. Servirá, también, para aquellos que
deseen contemplar un panorama global de métodos, herramientas CASE, ten-
dencias y perspectivas en el área de la OT. No está de más, al fin, probar un poco
de solidez europea frente a las montañas (magníficas, por otro lado) norteameri-
canas.
44
Graham expone SOMA detalladamente en su siguiente texto “Migrating to Object Technology”.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 223
la pena leerlo. Aparecen, además, situaciones y decisiones de gran valor peda-
gógico. La campaña de comercialización del libro incluye "El Juego de los Obje-
tos", con pelotita, silbatos y fichas de cartón, junto con un vídeo en el que se pue-
de apreciar la vitalidad yanqui de Peter Coad (acompañado por señoritas ligeri-
tas de ropa que sostienen cartones con clases y otras barbaridades).
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 224
(esto es, la relación de clases necesarias para llevar a cabo las tareas o respon-
sabilidades asignadas y para las que la clase no es autosuficiente). Se trata en
síntesis del siguiente proceso: en una primera etapa exploratoria se produce la
identificación de clases, identificación de clases abstractas, identificación y asig-
nación de responsabilidades e identificación de colaboraciones; en la siguiente
etapa, denominada de análisis, se modela la construcción de jerarquías (clases
en derivación), se identifican los contratos (una serie cohesiva de responsabilida-
des normalmente requeridas por otras clases) y se asignan a las colaboraciones,
se identifican los subsistemas (abstracciones que permiten un manejo más ade-
cuado del sistema global a modelar), se refinan las colaboraciones y se protocoli-
zan las responsabilidades (esto es, cada una de las responsabilidades se trans-
forma en el prototipo de una función). Se obtiene, al final, algo así como una es-
tructura de clases y sus relaciones vacía de implementación. Pero es que la im-
plementación no es lo importante: la identificación de las responsabilidades (por
servicios) públicos de las clases permitirá fragmentar la implementación de cla-
ses de una manera adecuada para el trabajo en equipo (una clase o serie de cla-
ses pueden serle asignadas a una persona, por ejemplo, y ésta únicamente sabrá
del resto de las clases que pueden ser accedidas a través de un protocolo públi-
co ya bien definido, independientemente de su implementación concreta). El se-
guimiento del clásico ejemplo del cajero automático es particularmente revelador
sobre el proceso de diseño expuesto, con abundantes comentarios y la explica-
ción detallada de las decisiones tomadas. Este ejemplo, y otros, están expuestos
en su totalidad en los apéndices del libro. Expuesto lo anterior, reitero mi reco-
mendación de uso de este libro quizás como el primer libro de OOD que los prin-
cipiantes debieran estudiar.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 225
declararán inestimable: el mapeo de las fichas a construcciones C++. Oh, el libro
no expone ninguna idea de pasmo, pero la descripción del conjunto de prácticas
de uso de fichas CRC constituye un manual perfecto para un primer proyecto de
migración a la Tecnología de Objetos, así como el texto es excelente para un cur-
so complementario del método de Wirfs-Brock, o aún para la enseñanza primera
de la Tecnología.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 226
Se aprecia, por último, una importante característica de cohesividad a lo largo de
la exposición de la metodología que le proporciona una solidez conceptual a que
otras son ajenas. La OMT ha ido ganando, desde su publicación, adeptos entre
los usuarios de OOA&OOD, habiéndose posicionado, en estas fechas, como una
de los métodos de uso más extendido. Se utilice o no esta técnica, lo cierto es
que el libro es, en todo caso, una valiosísima contribución a cualquier biblioteca
de OT. General Electric ha desarrollado una herramienta denominada OMTool
para distintas plataformas que computeriza estas técnicas, pero lo cierto es que
prácticamente cualquier herramienta actual multi-método soporta OMT. Finalmen-
te el método se ha asociado de forma indisoluble con James Rumbaugh, que jun-
to con Grady Booch e Ivar Jacobson en Rational están pariendo un entente unifi-
cado que ya ha cambiado de nombre más de una vez. ¡Oh, divina eclecsis!
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 227
Migrating to Object Technology, por Ian M. Graham, 1994, Addison-Wesley, 0-
201-59389-0, 552 pág.
El autor extiende su anterior libro “Object Oriented Methods” con esta obra, dividi-
da en dos claras partes: en la primera se examinan distintas cuestiones relacio-
nadas con el proceso de migración hacia la Tecnología de Objetos (necesidad,
oportunidad, beneficios, problemas, interoperación, reúso, interfaces gráficos,
almacenamiento de objetos, sistemas distribuidos y sistemas expertos), y en to-
das ellas se analizan dificultades, beneficios, direcciones, oportunidades y reali-
dades comerciales; en la segunda parte se detalla como abordar este proceso
de migración utilizando SOMA, con un muy interesante capítulo dedicado al análi-
sis y captura de requerimientos y una siempre bienvenida exposición dedicada a
métricas orientadas-a-objetos (Graham, por parte de la Corporación Suiza de
Banca, es uno de los promotores del Club de Métricas Orientadas-a-Objetos). No
faltan las referencias extensas a la re-ingeniería de procesos de negocio y los
aspectos de diseño físico e implementación para completar un libro redondo que,
no obstante, se complementa perfectamente con aquél primero del autor. El libro
esconde, finalmente, un disquete con una versión truncada (sin capacidades de
impresión) de una herramienta no-CASE denominada SOMATiK, que intenta au-
tomatizar el uso de SOMA.
Object-Oriented Analysis, 2nd Edition, por Peter Coad & Edward Yourdon,
1991, Yourdon Press/Prentice Hall, 233 pág.
Nos encontramos ante la segunda edición de uno de los primeros textos apareci-
dos en el mercado sobre OOA. Esta premura editorial consiguió que las ideas
propuestas por Coad y Yourdon se extendieran con gran rapidez, siendo así que
este método ha permanecido durante mucho tiempo como uno de los más am-
pliamente difundidos. El libro es uno de los más breves de los comentados en
este anexo y está escrito en un lenguaje coloquial de muy fácil lectura. Los con-
ceptos básicos del paradigma de objetos se exponen con la ayuda de definicio-
nes de diccionarios y enciclopedias. La graficación, una de las primeras y, por
tanto, de las más rudimentarias en este campo, básicamente expone el resultado
gráfico de la herramienta comercializada por los autores (OOATool). Las seccio-
nes de introducción y comparación de distintas metodologías de análisis anterio-
res al OOA (Yourdon-de Marco, Jackson, etc.) son agradablemente sucintas y
claras. Lo único que se puede reprochar es la falta de un formalismo metodológi-
co práctico que permita al lector hacer uso de lo aprendido. De hecho el lector se
queda al final del texto con una cierta sensación de borrachera de objetos, gene-
rada en buena medida por el énfasis y la excitación con que los mismos autores
tratan a la OT, pero sin direccionamiento práctico claro en el que sostener sus
primeros pasos en este campo. El libro es, pues, perfectamente aconsejable co-
mo texto introductorio a OOA.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 228
Object-Oriented Design, por Peter Coad & Edward Yourdon, 1991, Prentice
Hall, 0-13-630070-7.
Estamos ante una clara continuación del anterior libro de los autores sobre OOA,
que usa de una extensión apropiada a OOD de la herramienta de análisis OOA-
Tool de los autores. Tras una leve introducción (pues el texto, como el anterior, es
singularmente corto), se repasa la metodología de Análisis orientado-a-objetos
de Peter Coad: un modelo multicapa (sujeto, clase-objeto, structura, atributos y
servicios) y multicomponente (dominio del problema, interacción humana, gestión
de tareas y gestión de datos), con una notación específica de aplicación. Los au-
tores intentan, con cierto éxito, integrar de forma incruenta las técnicas de OOD
con las del proceso de OOA, para pasar después a exposiciones sobre sectores
de parcial interés, como el de las herramientas CASE o los distintos lenguajes de
programación. El texto, con las mismas salvedades de la obra anterior, es total-
mente recomendable como introducción no reglada al campo del OOD.
Object-Oriented Analysis: Modeling the World in Data, por Sally Shlaer &
Stephen J. Mellor, 1988, Yourdon Press/Prentice Hall, 144 pág.
Tenemos aquí a uno de los pocos textos serios focalizados en el área de análisis
orientado-a-objetos. Con un corto número de páginas, la obra comienza con una
simpática introducción a los típicos conceptos básicos, pasando a poco a clasifi-
car los objetos en: tangibles, roles, interacciones, incidentes y especificaciones
(he de reconocer que esta fragmentación conceptual yo siempre la he asumido
como de identificación de clases). Seguidamente expone un modelo de control
textual de especificaciones de clases como soporte de la técnica desarrollada
por los autores y denominada modelado de información. No es éste un libro que
proporcione un bagaje semejante al de Wirfs-Brock, ni la técnica en él descrita es
particularmente fácil de aplicar, pero, con todo, el texto ofrece detalles muy intere-
santes para el estudioso, así como ejemplos altamente intuitivos y de ilustracio-
nes autoexplicativas.
Object Lifecycles: Modeling the World in States, por Sally Shlaer & Stephen
J. Mellor, 1991, Prentice Hall, 0-13-629940-7.
Esta obra estudia, tras un breve repaso comprehensivo de la anterior obra de los
autores, el comportamiento dinámico de los sistemas de objetos. Éstos se asimi-
lan a máquinas de estados (así como las clases a modelos de estados), de tal
forma que el ciclo de vida de un objeto puede modelarse como un conjunto de
estados, de eventos, de reglas de transición y de acciones. Seguidamente se
muestra el desarrollo de las relaciones entre objetos afectadas por el tiempo, pa-
ra pasar después a la exposición de los métodos de modelado de secuenciacio-
nes de eventos y terminar con una extensión de los diagramas de flujos de datos
denominada ADFD y referida a los datos asociados a acciones de los objetos.
Se exponen diversas posibles aplicaciones de la técnica de la obra y se muestran
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 229
algunas líneas de migración a esta metodología desde el enfoque estructurado.
En definitiva nos encontramos ante el perfecto compañero de la anterior obra.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 230
nota sin tapujos) que no es más que un breviario del método de Jacobson (Objec-
tory), de forma que algunos de mis clientes no han comprendido el alcance del
mismo hasta que han pagado la licencia del método entero.
Object Oriented Program Design with Examples in C++, por Mark Mullin,
1990, Addison-Wesley, 0-201-51722-1, 303 pág.
Este texto ha llegado a ser muy popular entre un cierto sector de la comunidad
C++, principalmente entre los desarrolladores provenientes de C y de esquemas
de diseño estructurado, debido quizás a la inmediata practicidad de los concep-
tos que, sin esquematización rigurosa, se van proponiendo: es como si se dise-
ñara en C++. El autor asume un ejemplo (la creación de una base de datos corpo-
rativa para Bancroft Trading Company) y en sucesivos capítulos va refinando su
diseño. La mayor ventaja para algunos de este libro (su proximidad a la vida real)
es, sin embargo, también su principal defecto, pues aparte del diseño de bases
de datos la importancia habría de traspasarse a la identificación de clases y rela-
ciones, algo que en el texto se relega a un segundo plano. Planteada esta obser-
vación, por lo demás el libro es levemente recomendable como primer estadio de
paso en la codificación C++ basada en la conceptualización de objetos, sin de-
masiadas pretensiones adicionales. Yo diría que sin ninguna pretensión adicional.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 231
Working With Objects: The OOram Software Engineering Method, por Tryg-
ve Reenskaug con Per Wold y Odd Arild Lehne, 1996, Manning Publications, 1-
884777-10-4 (Prentice Hall: 0-13-452930-8)
Atención, lector: a mi entender este es uno de los textos más importantes publi-
cados en los últimos años sobre construcción de sistemas software, de forma que
arriesgarse a ignorarlo es comprometerse con la oscuridad. Sepa el lector, de
cualquier forma, que no soy fanático: sólo vehemente. Esto es, en el texto se ex-
plicitan muchas ideas que a mí me parecen no sólo naturales y adecuadas, sino
también inteligentes, efectivas y, finalmente, humanas. Es curioso que sean los
trabajos europeos, y sobre todo los del norte, los que enfaticen la primordial im-
portancia del factor humano en la construcción de sistemas software. El libro
contiene, además, un importante componente pedagógico, pues evidencia los
importantes logros conseguidos mediante el uso prudente de Smalltalk y de la
más general Tecnología de Objetos en una empresa (Taskon) a lo largo de más
de 25 años. El autor principal, Trygve Reenskaug, es, además de un reputado
experto en el campo de la Orientación-a-Objetos, el creador del concepto
Modelo-Vista-Controlador (MVC) que seguro todos conocen. El libro destila
inteligencia y sentada experiencia en todas sus páginas, a la vez que pone de
manifiesto un principio que no por evidente se aplica en otros métodos: las
mismas técnicas empleadas en el análisis y diseño de software debieran servir
para el análisis y diseño de organizaciones humanas. En fin, casi me aventuro a
proclamar: si sólo han de comprar un libro sobre objetos, adquieran éste.
Hay unos cuantos textos relacionados con los patrones de diseño software, buena
parte de ellos de Alexander, naturalmente. Para evitar el pataleo de los lectores,
reseñaré brevemente las obras de arquitectura. He aquí mi selección:
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 232
1.171 páginas (muchas pero pequeñas y con fotos e ilustraciones, no tema el lec-
tor), se dan cita en este texto (ya difícil de conseguir), en el que además se pro-
pugna una integración del mejor-vivir con el medio físico circundante: gente-gente-
patrones-gente. Cuando se habla del “libro de Alexander” (CA patterns book) o
del “libro AIS” (las iniciales de los primeros autores) se refieren a esta obra. Para
que el lector se forme una adecuada idea del tono del libro, sirvan estos ejemplos
descafeinados y salvajemente simplificados: ¿Cómo se sabe que un parque está
adecuadamente insertado en el terreno urbano? !Cuando los mendigos duermen
en él! ¿Dónde deben construirse las paradas de autobuses: en zonas tranquilas o
en zonas de bullicio vital urbanístico? Pues en ... humm, dejaré que el lector lea el
libro. Realmente estas ideas tienen impacto en los arquitectos noveles (como las
ideas de Le Corbusier sobre las medidas humanas de las farolas, etc.), para bien
o para mal.
Advanced C++ Programming Styles and Idioms, por James O. Coplien, 1992,
Addison-Wesley, 0-201-54855-0.
Desde su publicación he venido recomendando efusiva e insistentemente este
inteligente libro a todo aquél que de verdad quiera conocer el lenguaje C++ y aun
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 233
usarlo. Resulta claro ahora, como el mismo autor expresamente reconoce, que los
idiomas aquí descritos son en realidad patrones, presentados empero sin formato
definido. El libro es, pues, doblemente (mi comentario ya se dió en la sección de
C++ Avanzado) imprescindible.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 234
sayo en ella de la tecnología entera. Humm ... ¿Quise decir pretencioso?
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 235
cierta simpatía (que por definición podría calificarse de afinidad con lo inútil). Las
ideas presentadas aquí son claras -por simples- y leves -por meramente intuiti-
vas-: así, por ejemplo, la parte dedicada a Interfaces de Usuario Orientados-a-
Objetos rebosa candor desde nuestra perspectiva actual. El libro se constituye,
pues, en una introducción amable a esta área tecnológica. Las Selecciones del
Reader’s Digest serían una buena comparanza.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 236
The Object Database Standard: ODMG-93, editado por R.G.G. Catell, 1994,
Morgan Kaufmann Publishers, 1-55860-302-6.
Con la intención de normalización “de facto” subyaciendo en cada párrafo, este
libro, instructivo y afortunadamente breve, es de lectura obligada no tanto por la
realidad que refleja sino por la pretensión formalizadora que insufla. ¿OMG está
muerto? No sabría decirlo, pero su cadáver (en todo caso) atrae muchas moscas.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 237
distintos autores que se estructuran en dos capítulos tecnológicos: Bases de Da-
tos de Próxima Generación e Interoperabilidad con Bases de Datos Preexisten-
tes. La adecuada disposición de las contribuciones, mayormente originales para
el texto, permite una lectura secuencial y muestra una precisa visión del estado
actual de la Tecnología.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 238
software fiable. De una forma un tanto desmitificadora en estos tiempos de reina-
do del “proceso” Taylor prácticamente señala: “¿Focalización en los procesos?
¡No, gracias! No sustituya: ¡Integre!”. El libro es agradablemente corto y deja un
buen regusto final.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 239
Orientación-a-Objetos por razones equivocadas, (6.8) Ser seducido por el lado
oscuro, etc. etc. En fin, con esta obra (que se supone complementaria del magní-
fico texto de Goldberg y Rubin, Succeeding with Objects) se pretende conseguir
algo parecido a lo que con los patrones de diseño: comunicar la experiencia con-
trastada en diseño real de sistemas a los postulantes, aunque aquí por el lado
morboso del castigo y el didactismo. Muy entretenido, al fin y a la postre.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 240
201 Principles of Software Development, por Alan M. Davis, 1995, McGraw-
Hill, 0-07-015840-1.
Davis plantea en este texto una completa conjunción de princi-
pios/mandamientos/patrones que, aplicados, debieran procurar sistemas softwa-
re más racionales, sólidos y mantenibles: en resumen, de calidad. Los principios
son cortos y no tienen desperdicio: (34) Todo documento software necesita un
índice, (82) Los grandes diseños vienen de grandes diseñadores, (30) Sigue a
los lemmings con cuidado, (22) Técnica antes que herramientas, (170) Sé pesi-
mista sobre la evolución del software, ... y muchos otros. Cada principio se acom-
paña de una corta justificación, sirviendo así el texto de guia referencial a ingenie-
ros (sic) software, directivos y estudiantes. Conviene recordar que los seres
humanos tienden a trivializar rápidamente lo que les parece obvio en un contexto
dado, así que a más de uno le resultará tremendamente instructivo repasar algu-
nos conceptos que tenía por asimilados pero que nunca realmente ha aplicado
con claridad.
Ricardo Devis Botella C++: STL, Plantillas, Excepciones, Roles y Objetos Página 241