Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Teoria Sintacticogramatical de Objetos
Teoria Sintacticogramatical de Objetos
Diseo evolucionado de sistemas informticos orientados a objetos desde el lenguaje natural, con ejemplos en Python y PHP
Eugenia Bahit
Copyright 2012 F. Eugenia Bahit La copia y distribucin de este libro completo, est permitida en todo el mundo, sin regalas y por cualquier medio, siempre que esta nota sea preservada. Se concede permiso para copiar y distribuir traducciones de este libro desde el espaol original a otro idioma, siempre que la traduccin sea aprobada por la autora del libro y tanto el aviso de copyright como esta nota de permiso, sean preservados en todas las copias. Creative Commons Atribucin NoComercial CompartirIgual 3.0 Registrado en SafeCreative. N de registro: 1210292587717 Impreso en Espaa por Bubok Publishing S.L. Una copia digital de este libro (copia no impresa) puede obtenerse de forma gratuita en http://orientacionaobjetos.eugeniabahit.com/
A mis alumnos, quienes da a da llenan mis tardes de esperanzas; a Richard Stallman, por haberme enseado el verdadero valor del conocimiento y a todas aquellas personas que disfrutan jugando con el ingenio y compartiendo su sabidura Happy Hacking!
Contenidos
Captulo I: Introduccin informal para perderle el miedo a la orientacin a objetos................................................................9 Cmo pensar en objetos?..................................................9 Entendiendo el paradigma de la programacin orientada a objetos...............................................................................20 Elementos y Caractersticas de la POO .........................21 Captulo II: Teora sintctico-gramatical de objetos y el diseo de objetos en lenguaje natural................................................25 Del lenguaje natural al lenguaje de programacin.............35 Captulo III: Creacin de objetos y acceso a propiedades........39 Captulo IV: Patrn de diseo compuesto (composite pattern)45 Introduccin a la Arquitectura de Software .......................45 Atributos de calidad .....................................................46 Niveles de abstraccin ......................................................48 Estilo Arquitectnico ....................................................49 Patrn Arquitectnico ...................................................50 Patrn de Diseo ..........................................................51 Composite design pattern (patrn de diseo compuesto). .52 Captulo V: Objetos compositores exclusivos, identidad, pertenencia y agregacin........................................................57 Captulo VI: Objetos relacionales simples -o multiplicadores-. 67 Captulo VII: Mapeo relacional de objetos y estructuras de almacenamiento de datos sustentables...................................73 Captulo VIII: Objetos, subtipos y herencia real......................83 Captulo IX: Modelado de objetos y agrupacin......................89 Captulo X: Bases de datos, consultas y abstraccin................91 Creando una capa de abstraccin en Python......................92 Creando una capa de abstraccin en PHP con mysqli ........94 Recetario.......................................................................95 Captulo XI: El mtodo save() en objetos simples, compuestos y relacionales..........................................................................107 Captulo XII: El mtodo destroy().........................................119 Captulo XIII: Mtodos get() estndar, para objetos simples y objetos compuestos..............................................................121 Captulo XIV: Los mtodos get() en objetos compositores de
pertenencia..........................................................................127 Captulo XV: El mtodo get() de los objetos relacionales multiplicadores....................................................................133 Captulo XVI: Factora de objetos con Factory Pattern. Objetos compuestos con mtodos get() mucho ms simples..............137 Captulo XVII: Objetos colectores de instancia nica y Singleton Pattern.................................................................................143 Caractersticas de un Singleton colector en PHP..............145 Caractersticas de un Singleton colector en Python..........147 El mtodo get() del singleton colector.............................151 Captulo XVIII: Objetos relacionales complejos (conectores lgicos relacionales).............................................................153 Los mtodos save(), get() y destroy() del conector lgico157
necesariamente signifique sencillo. Y qu es un objeto? Pues, como dije antes, es simple. Olvidemos los formalismos, la informtica y todo lo que nos rodea. Simplemente, olvida todo y concntrate en lo que sigue. Lo explicar de manera simple: Un objeto es una cosa. Y, si una cosa es un sustantivo, entonces un objeto es un sustantivo. Mira a tu alrededor y encontrars decenas, cientos de objetos. Tu ordenador, es un objeto. T, eres un objeto. Tu llave es un objeto. El cenicero (ese que tienes frente a ti cargado de colillas de cigarrillo), es otro objeto. Tu mascota tambin es un objeto.
Cuando pensamos en objetos, todos los sustantivos son objetos.
Sencillo cierto? Entonces, de ahora en ms, solo concntrate en pensar la vida en objetos (al menos, hasta terminar de leer este libro). Ahora qu me dices si describimos las cualidades de un objeto? Describir un objeto, es simplemente mencionar sus
cualidades. Las cualidades son adjetivos. Podemos decir que un adjetivo es una cualidad del sustantivo. Entonces, para describir la manera de ser de un objeto, debemos preguntarnos cmo es el objeto? Toda respuesta que comience por el objeto es, seguida de un adjetivo, ser una cualidad del objeto. Algunos ejemplos: El objeto es verde El objeto es grande El objeto es feo
Ahora, imagina que te encuentras frente a un ni o de 2 aos (nio: objeto que pregunta cosas que t das por entendidas de forma implcita). Y cada vez que le dices las cualidades de un objeto al molesto nio-objeto, ste te pregunta: -Qu es...?, seguido del adjetivo con el cul finalizaste tu frase. Entonces, tu le respondes diciendo es un/una seguido de un sustantivo. Te lo muestro con un ejemplo:
El objeto es verde. Qu es verde? Un color. El objeto es grande. Qu es grande? Un tamao. El objeto es feo. Qu es feo? Un aspecto.
Estos sustantivos que responden a la pregunta del nio, pueden pasar a formar parte de una locucin adjetiva que especifique con mayor precisin, las descripciones anteriores: El objeto es de color verde. El objeto es de tamao grande. El objeto es de aspecto feo.
Podemos decir entonces -y todo esto, gracias al nio-objeto-, que una cualidad, es un atributo (derivado de cualidad atribuible a un objeto) y que entonces, un objeto es un sustantivo que posee atributos, cuyas cualidades lo describen. Algunos objetos, tambin se componen de otros objetos... Adems de cualidades (locucin adjetiva seguida de un adjetivo), los objetos tienen otras cosas.
Estas otras cosas, son aquellas pseudocualidades que en vez de responder a cmo es el objeto? responden a cmo est compuesto el objeto? o incluso, an ms simple Qu tiene el objeto?. La respuesta a esta pregunta, estar dada por la frase el objeto tiene..., seguida de un adjetivo cuantitativo o cuantificador (uno, varios, muchos, algunos, unas cuantas) ms un sustantivo.
Algunos ejemplos: El objeto tiene algunas antenas El objeto tiene un ojo El objeto tiene unos cuantos pelos
Los componentes de un objeto, tambin integran los atributos de ese objeto. Solo que estos atributos, son algo particulares: son otros objetos que poseen sus propias cualidades. Es decir, que estos atributos-objeto tambin respondern a la pregunta Cmo es/son ese/esos/esas? seguido del atributo-objeto (sustantivo).
Ampliemos el ejemplo para que se entienda mejor: El objeto tiene algunas antenas. Cmo son esas antenas? Las antenas son de color violeta Las antenas son de longitud extensa El objeto tiene un ojo. Cmo es ese ojo? El ojo es de forma oval El ojo es de color azul El ojo es de tamao grande El objeto tiene unos cuantos pelos. Cmo son esos pelos? Los pelos son de color fucsia Los pelos son de textura rugosa Podemos decir entonces, que un objeto puede tener dos tipos de atributos: 1. Los que responden a la pregunta Cmo es el objeto? con la frase El objeto es... + locucin adjetiva + adjetivo (atributos
definidos por cualidades) 2. Los que responden a la pregunta Qu tiene el objeto? con la frase El objeto tiene... + adjetivo cuantitativo (cantidad) + sustantivo (atributos definidos por las cualidades de otro objeto) Hay objetos que comparten caractersticas con otros objetos Resulta ser, que nuestro Objeto, es prcticamente igual a un nuevo objeto. Es decir, que el nuevo objeto que estamos viendo, tiene absolutamente todas las caractersticas que nuestro primer objeto. Es decir, tiene los mismos atributos. Pero tambin, tiene algunas ms. Por ejemplo, este nuevo objeto, adems de los atributos de nuestro primer objeto, tiene un pie. Es decir, que las caractersticas de nuestro nuevo objeto, sern todas las del objeto original, ms una nueva: pie.
Repasemos las caractersticas de nuestro nuevo objeto: El nuevo objeto es de color verde.
El nuevo objeto es de tamao grande. El nuevo objeto es de aspecto feo. El nuevo objeto tiene algunas antenas. Cmo son esas antenas? Las antenas son de color violeta Las antenas son de longitud extensa
El nuevo objeto tiene un ojo. Cmo es ese ojo? El ojo es de forma oval El ojo es de color azul El ojo es de tamao grande
El nuevo objeto tiene unos cuantos pelos. Cmo son esos pelos? Los pelos son de color fucsia Los pelos son de textura rugosa
pie? El pie es de forma rectangular El pie es de color amarillo El pie tiene 3 dedos. Cmo son esos dedos? Los dedos son de longitud mediana Los dedos son de forma alargada Los dedos son de color amarillo Podemos observar como nuestro nuevo objeto es una especie de objeto original ampliado. Es decir que el nuevo objeto, es exactamente igual al objeto original (comparte todos sus atributos) pero posee nuevas caractersticas. Est claro adems, que el objeto original y el nuevo objeto, son dos objetos diferentes cierto? No obstante, el nuevo objeto es un sub-tipo del objeto original. Ahora s, a complicarnos an ms. Los objetos, tambin tienen la capacidad de hacer cosas
Ya describimos las cualidades de nuestros objetos. Pero de lo que no hemos hablado, es de aquellas cosas que los objetos pueden hacer, es decir, cules son sus capacidades. Los objetos tiene la capacidad de realizar acciones. Las acciones, son verbos. Es decir, que para conocer las capacidades de un objeto, debes preguntarte Qu puede hacer el objeto? y la respuesta a esta pregunta, estar dada por todas aquellas que comiencen por la frase el objeto puede seguida de un verbo en infinitivo.
Algunos ejemplos: El objeto original puede flotar El nuevo objeto (adems) puede saltar
Objetos y ms objetos: la parte difcil Si entendiste todo lo anterior, ahora viene la parte difcil. Viste que esto de pensando en objetos viene a colacin de la programacin orientada a objetos? Bueno, la parte difcil es que en la programacin, todo lo que acabamos de ver, se denomina de una forma particular. Pero, la
explicacin es la misma que te di antes. Al pan, pan. Y al vino, vino. Las cosas por su nombre Cuando antes hablamos de... Objeto: en la POO1, tambin se denomina objeto. Atributos y cualidades: en la POO se denominan propiedades. Acciones que puede realizar un objeto : en la POO, se denominan mtodos. Atributos-objeto: en la POO se denomina composicin y es una tcnica. Objetos que tienen los mismos nombres de atributos (por ejemplo: color, forma, etc.): en la POO se denomina polimorfismo, y representa la capacidad que tienen los objetos, de poseer los mismos nombres de propiedades y mtodos. El polimorfismo, es una caracterstica esencial de la POO. Sub-tipos de objetos: en la POO se denomina
Cmo tal, nos ensea un mtodo -probado y estudiado- el cual se basa en las interacciones de objetos (todo lo descrito en el ttulo anterior, Pensar en objetos) para resolver las necesidades de un sistema informtico. Bsicamente, este paradigma se compone de 6 elementos y 7 caractersticas que veremos a continuacin.
objeto (y no otro). Cada mtodo debe tener una -y solo una- responsabilidad. Objeto Las clases por s mismas, no son ms que modelos que nos servirn para crear objetos en concreto. Podemos decir que una clase, es el razonamiento abstracto de un objeto, mientras que el objeto, es su materializacin. A la accin de crear objetos, se la denomina instanciar una clase y dicha instancia, consiste en asignar la clase, como valor a una variable, la cual se convertir en una variable de tipo objeto, puesta que la misma, tendr como valor, a las propiedades y mtodos que hayan sido definidos en la clase. Herencia Como comentamos en el ttulo anterior, algunos objetos comparten las mismas propiedades y mtodos que otro objeto, y adems agregan nuevas propiedades y mtodos. A esto se lo denomina herencia: una clase que hereda de otra. Composicin Como comentamos anteriormente, algunos objetos se componen de las propiedades de otro (lo cual,
no significa que las hereden, sino simplemente eso: se componen de). Cuando la propiedad de un objeto, se compone de las caractersticas de otro objeto, dicha propiedad se transforma en una especie de propiedadobjeto. Es decir, que el tipo de datos de esta propiedad, pasa a ser de tipo objeto. Esto significa, que dicha propiedad, estar formada por subpropiedades.
resulta la forma ms ptima y segura de lograr una comunicacin fehaciente, en el ncleo interno de un Software. La teora sintctico-gramatical de objetos, propone definir los objetos -en una primera instancia-, pura y exclusivamente en lenguaje natural, aplicando para ello, dos estructuras gramaticales nicas, que deben ser respetadas de forma estricta, a fin de asegurar conexiones lgicas irrefutables. A continuacin, veremos en qu consiste y cmo implementar dicha tcnica.
Diseando un sistema informtico en lenguaje natural Disear un sistema informtico orientado a objetos no es lo mismo que utilizar elementos de la orientacin a objetos: puedo pensar un sistema orientado a procedimientos y escribir el cdigo como si estuviese orientado a objetos. Lo anterior, no es programar orientado a objetos, sino, programar utilizando elementos de la POO. El primer paso para disear un sistema orientado a objetos -segn la teora sintctico-gramatical de
objetos-, es describir el objeto en lenguaje natural. Para describir los objetos en lenguaje natural, los pasos a seguir son: 1. Comenzar por el cualidades presente objeto qu mayor
2. Describir SOLO una cualidad por vez, utilizando una de las siguientes estructuras gramaticales: Estructura gramatical adjetiva: La mesa es de material metlico. Estructura gramatical sustantiva: La mesa tiene cuatro patas.
Identificar Objetos: Es el primer sustantivo ms los obtenidos de las estructuras gramaticales sustantivas: ltimo sustantivo de una estructura gramatical sustantiva, en singular. La Mesa es de color blanco. La mesa tiene cuatro patas. (el objeto ser en singular: Pata)
Identificar propiedades: PROPIEDAD SIMPLE: En una estructura gramatical adjetiva, es el sustantivo que forma una locucin adjetiva (pertenece al objeto que le antecede). La mesa es de color blanco. (color es propiedad de mesa) La mesa tiene cuatro patas. La pata es de color blanco. (color es propiedad de pata) PROPIEDAD COMPUESTA: El ltimo sustantivo de una estructura gramatical sustantiva (es propiedad del objeto que le antecede). La mesa es de color blanco. La mesa tiene cuatro patas. (es propiedad compuesta de mesa) La pata es de color blanco. Si la definicin de los objetos, se realiza empleando
un sistema visual de niveles (por ejemplo, las vietas con niveles), ser sumamente sencillo, reconocer los objetos, sus propiedades, relacin y dependencias de los mismos. Definamos una habitacin con cuatro paredes cubiertas de lajas, una puerta y una ventana: La habitacin tiene cuatro paredes
(defino todas las caractersticas de las paredes, refirindome solo a una) La pared es de posicin lateral La pared tiene muchas lajas La laja es de textura rugosa La laja es de color beige La laja es de longitud 250 mm La laja es de anchura 150 mm La pared tiene una puerta La puerta es de material madera La puerta es de color cedro
La pared tiene una ventana La ventana tiene un marco El marco es de material aluminio El marco es de color blanco El marco tiene un vidrio El vidrio es de espesor 10 mm El vidrio es de textura lisa El vidrio es de pigmentacin blancuzca La habitacin tiene un cielo raso2 El cielo raso es de material yeso El cielo raso es de color blanco
2
Cuando sola definir las propiedades de una habitacin, me refera al cielo raso como techo. El 15 de septiembre de 2012, mientras daba un taller de orientacin a objetos para NeaExtends (en la provincia de Formosa, Argentina), uno de los asistentes, muy sabiamente me hizo notar que el techo, es la parte del exterior de la habitacin, mientras que lo que se puede visualizar desde el interior, se denomina cielo raso.
El piso es de tipo flotante El piso es de material madera El piso es de color cedro Una vez realizada la descripcin de los objetos en lenguaje natural, se procede a la identificacin de objetos y propiedades: La habitacin tiene cuatro paredes La pared es de posicin lateral La pared tiene muchas lajas La laja es de textura rugosa La laja es de color beige La laja es de longitud 250 mm La laja es de anchura 150 mm La pared tiene una puerta La puerta es de material madera La puerta es de color cedro
La pared tiene una ventana La ventana tiene un marco El marco es de material aluminio El marco es de color blanco El marco tiene un vidrio El vidrio es de espesor 10 mm El vidrio es de textura lisa El vidrio es de pigmentacin blancuzca La habitacin tiene un cielo raso El cielo raso es de material yeso El cielo raso es de color blanco La habitacin tiene un piso El piso es de tipo flotante El piso es de material madera El piso es de color cedro
Notar que hemos resaltado los objetos solo una vez, mientras que las propiedades, han sido todas subrayadas y colocadas en cursiva.
3 4
http://www.python.org http://www.php.net
en el mtodo constructor5 de la clase. Dado que Python y PHP son dos lenguajes de tipado dinmico6, en el mtodo constructor se asignar a cada propiedad, un valor equivalente a cero, representativo del tipo de datos. Se considerarn valores equivalentes a cero:
Equivalente a cero Equivalente a cero Equivalente a cero Equivalente a cero Equivalente a cero (en propiedades co de tipo de tipo de tipo de tipo de tipo puestas entero: 0 real: 0.0 string: '' booleano: False coleccin: por !s de un objeto) "#": arra$() "$t%on: &'
Cuando una propiedad se componga de un solo objeto, se asignar como valor de la misma, una instancia de dicho objeto:
En PHP: ne( )bjeto() En Python: )bjeto()
El mtodo constructor es aquel que se ejecuta de forma automtica para inicializar un objeto cuando ste es creado. El nombre del mtodo constructor se encuentra reservado, siendo __init__() para Python y __construct() para PHP . Tipado dinmico: dcese de aquellos lenguajes de programacin generalmente interpretados, en los cuales una misma variable puede tomar valores de distinto tipo a lo largo de la ejecucin del programa. Dichos programas, no requieren que a una variable se le defina de forma anticipada su tipo de datos y por lo tanto, no existen restricciones al respecto.
Un ejemplo concreto:
Python: class *n)bjeto(object): de+ ,,init,,(sel+): sel+.entero - 0 sel+.real - 0.0 sel+.cadena - '' sel+.booleano - False sel+.objetos - &' sel+.objeto - )bjeto() PHP: class *n)bjeto { +unction ,,construct() { .t%is/0entero - 01 .t%is/0real - 0.01 .t%is/0cadena - ''1 .t%is/0booleano - False1 .t%is/0objetos - arra$()1 .t%is/0objeto - ne( )bjeto()1 } }
En los objetos, nos podremos encontrar tres tipos de propiedades: 1. Propiedades simples (de tipo nico) 2. Propiedades compuestas (compuestas por un solo objeto)
Para ver la estructura interna de un objeto en Python, se recomienda descargar el mdulo python-printr de www.python-printr.org e instalarlo en /usr/lib/Python2.x/
PHP: print,r(.objeto)1
Veamos un ejemplo completo con vidrio, marco y ventana, para as, poder modificar el valor de sus propiedades:
Python: class Vidrio(object): de+ ,,init,,(sel+): sel+.espesor - 0 sel+.te2tura - '' sel+.pig entacion - '' class 3arco(object): de+ ,,init,,(sel+): sel+. aterial - '' sel+.color - '' sel+.vidrio - Vidrio() class Ventana(object): de+ ,,init,,(sel+): sel+. arco - 3arco() ventana = Ventana() +ro printr i port printr printr(ventana)
class Ventana { +unction ,,construct() { .t%is/0 arco - ne( 3arco()1 } } $ventana = new Ventana(); print_r($ventana);
El objeto fue creado (inicializado). Sin embargo, ningn valor ha sido asociado a sus propiedades. Si las propiedades fuesen simples y quisiramos modificarlas, lo haramos de la siguiente forma:
Pero cuando las propiedades son compuestas, debe seguirse toda la ruta de propiedades, hasta llegar a la deseada:
Python: ventana. arco.vidrio.espesor - 50 PHP: .ventana/0 arco/0vidrio/0espesor - 501
En objetos donde la dependencia es de varios niveles, modificar las propiedades de esta forma, no solo se hace difcil, sino que adems, es bastante confuso. Claro que tambin podramos crear un nuevo objeto, modificarle sus propiedades simples y reasignarlo al objeto compuesto:
Python: vidrio - Vidrio() vidrio.espesor - 50 arco - 3arco() arco.vidrio - vidrio ventana - Ventana() ventana. arco - arco
Pero hacindolo de esa forma, tambin podramos confundirnos y modificar -sin quererlo- la estructura interna del objeto:
Python: vidrio - Vidrio() vidrio.espesor - 50 ventana - Ventana() ventana. arco - vidrio PHP: .vidrio - ne( Vidrio()1 .vidrio/0espesor - 501 .ventana - ne( Ventana()1 .ventana/0 arco - .vidrio1
Es entonces, cuando se hace necesario en grandes relaciones de objetos, contar con una solucin a este problema. Y la misma, es provista por el patrn de diseo compuesto que veremos en el siguiente captulo.
concepto simple y sencillo que permita comprender el punto de vista desde el cual, este libro abarca a la arquitectura de software pero, sin nimo de que ello represente una definicin ms. A grandes rasgos, puede decirse que la Arquitectura de Software es la forma en la que se organizan los componentes de un sistema, interactan y se relacionan entre s y con el contexto, aplicando normas y principios de diseo y calidad, que fortalezcan y fomenten la usabilidad a la vez que dejan preparado el sistema, para su propia evolucin.
Atributos de calidad
La Calidad del Software puede definirse como los atributos implcitamente requeridos en un sistema que deben ser satisfechos. Cuando estos atributos son satisfechos, puede decirse (aunque en forma objetable), que la calidad del software es satisfactoria. Estos atributos, se gestan desde la arquitectura de software que se emplea, ya sea cumpliendo con aquellos requeridos durante la ejecucin del software, como con aquellos que forman parte del proceso de desarrollo de ste.
Atributos de calidad que pueden observarse durante la ejecucin del software 1. Disponibilidad de uso 2. Confidencialidad, puesto que se debe evitar el acceso no autorizado al sistema 3. Cumplimiento de la Funcionalidad requerida 4. Desempeo del sistema con respecto a factores tales como la capacidad de respuesta 5. Confiabilidad dada por la constancia operativa y permanente del sistema 6. Seguridad externa evitando la prdida de informacin debido a errores del sistema 7. Seguridad interna siendo capaz de impedir ataques, usos no autorizados, etc. Atributos de calidad inherentes al proceso de desarrollo del software 1. Capacidad de Configuracin que el sistema otorga al usuario a fin de realizar ciertos cambios 2. Integrabilidad de los mdulos independientes del sistema 3. Integridad de la informacin asociada
4. Capacidad de Interoperar con otros sistemas (interoperabilidad) 5. Capacidad de permitir ser modificable a futuro (modificabilidad) 6. Ser fcilmente Mantenible (mantenibilidad) 7. Capacidad de Portabilidad, es decir que pueda ser ejecutado en diversos ambientes tanto de software como de hardware 8. Tener una estructura que facilite la Reusabilidad de la misma en futuros sistemas 9. Mantener un diseo arquitectnico Escalable que permita su ampliacin (escalabilidad) 10. Facilidad de ser Sometido a Pruebas que aseguren que el sistema falla cuando es lo que se espera (testeabilidad)
Niveles de abstraccin
Podemos decir que la AS8 se divide en tres niveles de abstraccin bien diferenciados: Estilo Arquitectnico, Patrn Arquitectnico y Patrn de Diseo. Existe una diferencia radical entre estos tres elementos, que debe marcarse a fin de evitar las grandes confusiones que inevitablemente,
8 Arquitectura de Software
concluyen en el mal entendimiento y en los resultados poco satisfactorios. stos, son los que en definitiva, aportarn calidad al sistema resultante. En lo sucesivo, trataremos de establecer la diferencia entre estos tres conceptos, viendo como los mismos, se relacionan entre s, formando parte de un todo: la arquitectura de software. Estilo Arquitectnico, Patrn Arquitectnico y Patrn de Diseo, representan -de lo general a lo particular- los tres niveles de abstraccin en los que se divide la Arquitectura de Software.
Estilo Arquitectnico
El estilo arquitectnico define un nivel general de la estructura del sistema y cmo ste, va a comportarse. Mary Shaw y David Garlan, en su libro Software Architecture (Prentice Hall, 1996), definen los estilos arquitectnicos como la forma de determinar el los componentes y conectores de un sistema, que pueden ser utilizados a instancias del estilo elegido, conjuntamente con un grupo de restricciones sobre como stos pueden ser combinados:
[...] an architectural style determines the vocabulary of components and connectors that
can be used in instances of that style, together with a set of constraints on how they can be combined [...]
Mary Shaw y David Garlan -en el mismo libro-, hacen una distincin de estilos arquitectnicos comunes, citando como tales a: 1. Pipes and filters (filtros y tuberas) 2. Data Abstraction and Object-Oriented Organization (Abstraccin de datos y organizacin orientada a objetos) 3. Event-based (estilo basado en eventos) 4. Layered Systems (Sistemas en capas) 5. Repositories (Repositorios) 6. Table Driven Interpreters Viendo la clasificacin anterior, es muy frecuente que se encuentren relaciones entre los estilos arquitectnicos y los paradigmas de programacin. Sin embargo, debe evitarse relacionarlos en forma directa.
Patrn Arquitectnico
Un patrn arquitectnico, definir entonces, una
plantilla para construir el Software, siendo una particularidad del estilo arquitectnico elegido. En esta definicin, es donde se incluye a MVC, patrn que a la vez, puede ser enmarcado dentro del estilo arquitectnico orientado a objetos (estilo arquitectnico basado en el paradigma de programacin orientada a objetos).
Patrn de Diseo
Dentro de niveles de abstraccin de la arquitectura de Software, los patrones de diseo representan el nivel de abstraccin ms detallado. A nivel general, nos encontramos con el Estilo Arquitectnico. En lo particular, hallamos al Patrn Arquitectnico y, finalmente, el Patrn de Diseo es el detalle. Matt Zandstra en su libro PHP Objects, Patterns and Practice (Apress, 2010) define los patrones de diseo como:
[] is a problem analyzed with good practice for its solution explained [...]
(Traduccin: un problema analizado con buenas prcticas para su solucin explicada) Un patrn de diseo, entonces, es un anlisis
mucho ms detallado, preciso y minucioso de una parte ms pequea del sistema, que puede incluso, trabajar en interaccin con otros patrones de diseo. Por ejemplo, un Singleton puede coexistir con un Factory y stos, a la vez, con Composite. En este sentido, un Patrn Arquitectnico como MVC, podra utilizar diversos patrones de diseo en perfecta coexistencia, para la creacin de sus componentes.
compone a dicha propiedad), previniendo que por error, le sea asignado un objeto o valor, diferente al tipo del objeto esperado. Para lograrlo, dicho patrn esperar que el objeto compositor, le sea pasado como parmetro. Composite en PHP En PHP 5.x, es posible indicar a un mtodo, el tipo de objeto esperado, anteponiendo el nombre del mismo:
class 3arco { +unction ,,construct(Vidrio $vidrio=NULL) { .t%is/0 aterial - ''1 .t%is/0color - ''1 .t%is/0vidrio - .vidrio1 } }
De esta forma, si intentramos construir el objeto Marco(), pasando como parmetro un objeto que
integran y dicho sistema, no necesariamente estar orientado a objetos. Para la teora sintctico-gramatical de objetos, el idioma espaol cumple un papel fundamental. La Real Academia Espaola, define el trmino compositor como un adjetivo cuyo significado es que compone. Y en este sentido ser utilizado en este libro, a fin de no confundirlo con los componentes de un sistema informtico.
Sin embargo, si un objeto Vidrio() o NULL le es pasado como parmetro, el patrn habr servido a su fin:
$vidrio = new Vidrio(); .vidrio/0espesor - 501 .vidrio/0te2tura - 'lisa'1 .vidrio/0pig entacion - 'blancu8ca'1 $!ar%o = new 'ar%o($vidrio); print,r(. arco)1 3arco )bject ( & aterial' -0 &color' -0 &vidrio' -0 Vidrio )bject ( &espesor' -0 50 &te2tura' -0 lisa &pig entacion' -0 blancu8ca ) )
Composite en Python A diferencia de PHP , en Python no podemos indicar a un mtodo, el tipo de objeto que estamos
esperando. Para componer mediante !composite" en Python, la funcin isinstance(objeto, clase)10 ser necesaria:
class 3arco(object): de+ ,,init,,(sel+7 vidrio-9one): sel+. aterial - '' sel+.color - ''
i& i#in#tan%e(vidrio( Vidrio) or vidrio i# None:
Si un objeto de tipo diferente a Vidrio le es pasado como parmetro, un error ser lanzado:
arco - 3arco('no so$ un vidrio') )ypeError: *type +#tr+, no e# de tipo Vidrio
salva al tiempo que, implementado de la forma anterior, nos ensucia el cdigo adems de obligarnos a caer en redundancia. Para solucionar este problema, podemos generar nuestra propia funcin compose() y as, mantener limpios nuestros constructores y evitar la redundancia en un solo paso:
de& %o!po#e(o$-( %.#): i+ isinstance(obj7 cls) or obj is 9one: return obj else: raise ;$peError(':s no es de tipo :s' : (t$pe(obj)7 cls)) class 3arco(object): de+ ,,init,,(sel+7 vidrio-9one): sel+. aterial - '' sel+.color - '' #e.&/vidrio = %o!po#e(vidrio( Vidrio)
su nmero de documento (DNI, Pasaporte, etc.), mientras que el DNI de nuestros objetos, ser su ID. Por lo tanto, a toda definicin de clase, siempre se le agregar en el mtodo constructor -y como primera propiedad- la propiedad objeto_id, donde objeto ser el nombre de la clase:
Python: class Vidrio(object): de+ ,,init,,(sel+): #e.&/vidrio_id = 0 sel+.espesor - 0 sel+.te2tura - '' sel+.pig entacion - '' PHP: class Vidrio{ +unction ,,construct() { $thi#1,vidrio_id = 0; .t%is/0espesor - 01 .t%is/0te2tura - ''1 .t%is/0pig entacion - ''1 } }
Objetos compositores Todo objeto que sirve para componer a otro, se denomina objeto compositor.
Entre los objetos compositores, podemos encontrar dos tipos claramente diferenciados: los compositores reutilizables y los compositores exclusivos -o de pertenencia-, en los que nos centraremos en este captulo. Objetos compositores exclusivos Se dice que un compositor es exclusivo cuando ste puede componer nicamente a un -y solo unobjeto. Cuando la propiedad de un objeto se compone de N objetos del mismo tipo pero diferente identidad (es decir, se compone de objetos similares pero no idnticos), dichos compositores sern compositores exclusivos. Para que un compositor sea considerado de pertenencia, deben necesitarse al menos dos compositores para componer la misma propiedad. Por ejemplo, puedo decir que un vidrio compone a un marco. Pero solo es 1 vidrio. Por lo tanto, no es compositor de pertenencia. Tambin puedo decir que 75 lajas componen a la misma pared. Sin embargo, puedo crear una nica laja y replicar la misma laja N veces para componer a esa pared y a otras. Es decir, puedo reutilizar una misma laja
para componer ms de una pared. Entonces, hablo de un compositor reutilizable. Pero cuando digo que 4 paredes componen a la misma habitacin, cada una de ellas se diferencia por sus cualidades y no puedo reutilizar la misma pared para componer ms de una habitacin. De hecho podras trasladar la pared del living al dormitorio? Es aqu cuando hablamos de objetos compositores de pertenencia: !El Objeto A pertenece al Objeto B".
El caso de Pared !abitaci"n# es exactamente el mismo $ue se da %por e&emplo% en un sistema de administraci"n de empleados# donde' !#l empleado tiene varios datos de contacto" !#l dato de contacto es de tipo tel$fono m%vil" (inalmente# podemos decir $ue' !#l dato de contacto pertenece al empleado".
Pertenencia )uando un tipo de ob&eto es considerado un compositor exclusivo# dicha caracter*stica se de(ine con una nueva
estructura gramatical' El +ob&eto ,- pertenece +a.al.a la- +ob&eto B!&a pared pertenece a la habitaci%n" /icha estructura gramatical# deriva en una nueva propiedad del ob&eto compositor' la propiedad ob&eto0compuesto# cu o valor# ser1 la identidad del ob&eto al cu1l compone'
Python: class "ared(object): de+ ,,init,,(sel+7 puerta-9one7 ventana-9one): sel+.pared,id - 0 sel+.lajas - &' sel+.puerta - co pose(puerta 7 "uerta) sel+.ventana - co pose(ventana 7 Ventana) #e.&/ha$ita%ion = 0 PHP: class "ared { +unction ,,construct("uerta .puerta-9*<<7 Ventana .ventana-9*<<) { .t%is/0pared,id - 01 .t%is/0lajas - arra$()1 .t%is/0puerta - .puerta1 .t%is/0ventana - .ventana1 $thi#1,ha$ita%ion = 0; } }
Agregacin Cuando una propiedad se compone por varios objetos del mismo tipo, la misma se define como una coleccin. Ya sea un array en PHP como una lista en Python. Al crear el objeto, se le deben ir agregando tantos compositores como sean necesarios para componer dicha propiedad:
Python: pared,i8quierda - "ared() pared,derec%a - "ared() pared,+rontal - "ared() pared,dorsal - "ared() %abitacion - #abitacion(piso7 cielo,raso) %abitacion.paredes.append(pared,i8quierda) %abitacion.paredes.append(pared,derec%a) %abitacion.paredes.append(pared,+rontal) %abitacion.paredes.append(pared,dorsal) PHP: .pared,i8quierda - ne( "ared()1 .pared,derec%a - ne( "ared()1 .pared,+rontal - ne( "ared()1 .pared,dorsal - ne( "ared()1 .%abitacion - ne( #abitacion(.piso7 .cielo,raso)1 .%abitacion/0paredes&' - .pared,i8quierda1 .%abitacion/0paredes&' - .pared,derec%a1 .%abitacion/0paredes&' - .pared,+rontal1 .%abitacion/0paredes&' - .pared,dorsal1
Al igual que nos pasaba al inicializar un objeto, podramos agregar un objeto del tipo incorrecto:
Python: %abitacion - #abitacion(piso7 cielo,raso) %abitacion.paredes.append('no so$ una pared') PHP: .%abitacion - ne( #abitacion(.piso7 .cielo,raso)1 .%abitacion/0paredes&' - 'no so$ una pared'1
Y nuestro sistema, seguira adelante como si nada malo hubiese sucedido, poniendo en riesgo toda la integridad de la aplicacin. Para resolver este problema, sabemos que existe el patrn compuesto pero cmo implementarlo? Para ello, se utilizan los llamados mtodos de agregacin. Los mtodos de agregacin, no son ms que funciones que utilizando el patrn compuesto, se encargan de agregar los compositores que sean necesarios para componer la propiedad colectora. Dichos mtodos, se encuentran presentes en todo objeto que posea propiedades colectoras. Vale aclarar que los mtodos de agregacin, no deben definir un valor nulo por defecto como sucede en los mtodos constructores cuando se utiliza el patrn compuesto.
Con los mtodos de agregacin, el agregado de compositores resultar mucho ms seguro y sustentable:
Python: pared,i8quierda - "ared() pared,derec%a - "ared() pared,+rontal - "ared() pared,dorsal - "ared()
Captulo VI: Objetos relacionales simples -o multiplicadoresImagina que tienes que agregar 75 lajas a una pared. Y que en realidad, solo tienes una laja y nada ms, deseas replicarla 75 veces para componer la misma pared.
Una pared, se compone de 75 lajas idnticas (las lajas son exactamente iguales entre s). Es decir, que con tan solo crear 1 objeto laja podremos replicarlo N veces -sin necesidad de modificarlo-, para componer esa u otras paredes. Hablamos de 75 lajas con la misma identidad. Podemos decir entonces, que el objeto laja, es un objeto compositor reutilizable.
Claro est que podras colocar un bucle en el mtodo de agregacin add_laja() del objeto Pared. Pero al no ser laja un compositor exclusivo cmo sabrs la identidad de la laja que compone a una determinada pared? Y sin conocer la identidad de
la laja que se necesita para componer una pared cmo haras para recuperarla tras haberla creado? Para resolver este problema, es entonces, que surge la necesidad de contar con un objeto relacional multiplicador: para poder establecer la relacin existente entre 1 objeto compuesto y N objetos compositores reutilizables (objetos idnticos -misma identidad-).
Haciendo un paralelismo con el ejemplo de empleados y datos de contactos que vimos en el captulo anterior, podemos decir que el caso de Laja y Pared ser el mismo que acontezca -por ejemploen un sistema de gestin contable donde La nota de pedido tiene varios productos. Un producto podra ser Paquete de Algodn SuavecitoSuavecito x 200 gr y la misma nota de pedido, tener 40 paquetes del mismo producto. Objeto relacional simple (o multiplicador) Un objeto relacional es aquel cuya nica finalidad es la de establecer la relacin existente entre dos objetos, multiplicando N veces al compositor. Un objeto relacional simple, se conforma de cuatro
propiedades: INT objeto_id (presente en todos los objetos) ObjetoCompositor objeto_compositor ObjetoCompuesto objeto_compuesto INT relacion
Para establecer la relacin compositor/compuesto, incorporar un mtodo relacional set_relacion() que de forma iterativa, agregar los compositores necesarios, recurriendo al mtodo de agregacin del objeto compuesto:
Python: class <aja"ared(object): de+ ,,init,,(sel+7 co puesto7 co positor-9one): sel+.lajapared,id - 0 sel+.pared - co pose(co puesto7 "ared) sel+.laja - co pose(co positor7 <aja) sel+.relacion - 5 de+ set,relacion(sel+): t pvar - 0 (%ile t pvar 4 sel+.relacion: sel+.pared.add,laja(sel+.laja) t pvar >- 5 PHP: class <aja"ared { +unction ,,construct("ared .co puesto7
Para establecer la relacin entre N lajas y pared, solo bastar con: 1. Crear el objeto compositor 2. Crear el objeto compuesto 3. Crear el objeto relacional 4. Invocar al mtodo set_relacion() para establecer la relacin entre compositor * N y compuesto.
Python: laja - <aja() laja.color - 'beige' pared - "ared(puerta7 ventana) pared.posicion - '+rontal'
En la orientacin a objetos, la base de datos debe cumplir una funcin meramente complementaria, cuyo objetivo, solo ser servir de soporte para almacenar datos de forma sustentable que nos permitan recuperar -con cualquier propsitoobjetos creados. El objetivo de mapear objetos relacionalmente es "recorrer los objetos analizando su relacin, a fin de poder disear una estructura de almacenamiento
de datos (base de datos) sustentable al servicio de dichos objetos". Para qu mapear los objetos? Cuando uno crea objetos, los mismos son "voltiles". Es decir, se crea un objeto, se ejecuta el archivo y tras la finalizacin del script, el objeto se destruye y es eliminado de la memoria. Entonces: cmo recuperar luego ese objeto? Almacenar sus datos en una base de datos es la solucin ms prctica y viable. Por ese motivo, es que la necesitamos. El mapeo relacional debe comenzarse por los objetos que menor cantidad de dependencias posean. Comenzando entonces, por aquellos objetos sin dependencias, seguiremos en el orden de menor a mayor cantidad de dependencias. Para escribir las consultas SQL destinadas a crear las tablas de la base de datos, se debern tener en cuenta las siguientes pautas:
Ms adelante, veremos que los nicos objetos que no tendrn una tabla homnima, sern los Singleton colectores y los subtipos simples. El nombre de la tabla, ser el nombre de la clase, en minsculas.
6lass 3i6lase
Producir:
6=EA;E ;AB<E iclase
Todas las tablas deben crearse con el motor InnoDB Esto es, debido a que nuestra base de datos, deber contemplar las relaciones derivadas del diseo de los objetos. Por tanto, la base de datos, ser una base de datos relacional. MySQL utiliza por defecto el motor MyISAM, quien no posee soporte para bases de datos relaciones. En cambio, el motor InnoDB, nos provee de un excelente soporte para la manipulacin de claves forneas (foreign keys o FK).
6=EA;E ;AB<E iclase ( ) E9CD9E-DnnoEB1
La propiedad objeto_id ser clave primaria de la tabla Una clave primaria, ser de tipo entero, autoincremental y no podr permitir valores nulos.
6=EA;E ;AB<E iclase ( iclase,id D9;(55) 9); 9*<< A*;),D96=E3E9; "=D3A=F GEF ) E9CD9E-DnnoEB1
Todas las propiedades simples, siempre sern campos de la tabla Es decir, cualquier propiedad cuyo valor no sea una coleccin, ni otro objeto, ser campo de la tabla, respetando el tipo de datos definido en el constructor. Los campos de la tabla debern tener s o s, el mismo nombre que las propiedades 11, sin ningn tipo de agregado o cambio.
11 Siempre digo que enseando tambin se aprende y que en vez de competir hay que saber aprender de otros. Si miras los estilos de escritura del cdigo SQL, notars que las comas (,) las coloco a la izquierda de los campos y no al final. Esto lo aprend de Magoo, un alumno del curso de Orientacin a Objetos en Python. Su tcnica me result sorprenderte ya que al colocar las comas a la izquierda del campo, es pr cticamente imposible olvidarse una.
A fin de lograr una estructura de datos optimizada, se deber tener especial cuidado en la cantidad de dgitos o caracteres a indicar en los campos de tipo INT, DECIMAL, CHAR y VARCHAR.
Las propiedades de pertenencia, sern claves forneas con efecto en cascada Las propiedades de pertenencia, sern siempre de tipo INT(11). No podrn ser nulas y cuando la clave primaria a la que hagan referencia sea eliminada, producirn un efecto en cascada.
6=EA;E ;AB<E iclase ( iclase,id D9;(55) 9); 9*<< A*;),D96=E3E9; "=D3A=F GEF 7 propiedad,entero D9;(H) 7 propiedad,real EE6D3A<(I7 J) 7 propiedad,string VA=6#A=(H0) 7 propiedad,bool B))<
Las propiedades compuestas por un solo objeto sern campos de la tabla Debern ser de tipo entero admitiendo valores nulos. Sern establecidas como claves forneas produciendo un valor nulo cuando la clave primaria sea eliminada, excepto cuando se trate de objetos relacionales, donde el efecto ser en cascada.
6=EA;E ;AB<E iclase ( iclase,id D9;(55) 9); 9*<< A*;),D96=E3E9; "=D3A=F GEF 7 propiedad,entero D9;(H) 7 propiedad,real EE6D3A<(I7 J) 7 propiedad,string VA=6#A=(H0) 7 propiedad,bool B))< 7 propiedad,de,pertenencia D9;(55) 9); 9*<< 7 F)=EDC9 GEF (propiedad,de,pertenencia) =EFE=E96EK tabla (ca po,id) )9 EE<E;E 6AK6AEE 7 propiedad,co puesta D9;(55) =EFE=E96EK tabla,co positor (ca po,id) )9 EE<E;E KE; 9*<< ) E9CD9E-DnnoEB1
como
claves
Esta indexacin, deber estar presente en cualquier campo indicado como clave fornea, de cualquier tabla.
Ten en cuenta que seguir todas las reglas de estilo antes mencionadas, ser la forma ms acertada de mantener un diseo simple.
Creacin de la base de datos Todas las consultas anteriores (obtenidas del mapeo relacional), debern ser escritas en un archivo SQL (database.sql). Al principio de este archivo, escribiremos tambin, la consulta SQL para crear y usar la base de datos:
6=EA;E EA;ABAKE nuevadb1 *KE nuevadb1
Es muy frecuente cometer errores de escritura que pueden afectar la sintaxis del lenguaje SQL, provocando que al ejecutar el archivo, la construccin de nuestra base de datos quede inconclusa. Para prevenir este problema, como primera lnea de nuestro script SQL, nos ocuparemos de eliminar previamente la base de datos. Esto nos permitir ejecutar el archivo tantas veces como sea necesario, con solo corregir el error de sintaxis informado por MySQL.
E=)" EA;ABAKE DF ELDK;K nuevadb1 6=EA;E EA;ABAKE nuevadb1
Finalmente, para correr el archivo y crear la base de datos, ejecutaremos el siguiente comando:
$sql /u root /p 4 database.sql
Si todo ha ido bien, ningn mensaje ser mostrado en pantalla. Para comprobar la base de datos, ingresar a MySQL:
$sql /u root /p
Mostrar todas las bases de datos para verificar que la nuestra haya sido creada:
s%o( databases1
Si nuestra base de datos se encuentra creada, la seleccionamos para ver sus tablas:
use nuevadb1 s%o( tables1
Herencia o propiedades distintivas? Por ejemplo, si hablamos de azulejos y lajas, en principio parecera que estamos hablando de dos objetos diferentes. Sin embargo ambos objetos tienen las mismas propiedades: color, textura, espesor, anchura y longitud. Ambos objetos, a la vez, cumplen la misma funcin: servir de revestimiento a las paredes. Pero color, textura, espesor, longitud y anchura no son a caso las propiedades de un tipo de revestimiento? Este es el caso de un solo objeto
(Revestimiento) con una propiedad cuyo valor, marcar la diferencia: tipo, la cul podr tener diferentes valores (azulejo, laja y tambin cermico, baldosa, etc.) que sern los que en definitiva, marquen la diferencia. Hablamos de un solo objeto con propiedades simples.
Herencia o polimorfismo? Sin embargo, puedo tener dos objetos con las mismas propiedades y no tener la posibilidad de unificarlos, ya que los mismos, pertenecen a grupos de objetos diferentes: un vidrio tambin puede definirse con color, textura, espesor, anchura y longitud pero sin embargo, no pertenece al grupo de los revestimientos. Este es el caso de dos objetos diferentes, sin relacin entre s.
Herencia real y subtipos En el afn de unificar objetos, podemos cometer errores que muchas veces pasan desapercibidos. Pensemos en el objeto pared: si una habitacin tiene 4 paredes, una de las paredes tiene una ventana y otra de las paredes tiene una puerta
realmente estamos en presencia solo de un objeto pared? Lo cierto e irrefutable es que las cuatro son paredes. De eso no hay ninguna duda. Pero la presencia de propiedades compuestas (ventana en un caso, puerta en el otro) nos est marcando claramente que estamos en presencia de subtipos del objeto. Pared, tendr como propiedades todas aquellas que hemos definido con anterioridad excepto puerta y ventana que pasarn a ser propiedades de los subtipos de pared: ParedConPuerta y ParedConVentana respectivamente. Los subtipos heredarn todas las propiedades del tipo principal, incluso la propiedad objeto_id. Por la base de datos, no habr que preocuparse en hacer un nuevo mapeo, ya que cuando existe herencia, las propiedades de los subtipos comparten la tabla con la clase madre.
Inicializando subtipos En los mtodos constructores, los subtipos deben inicializarse no solo con sus nuevas propiedades, sino adems, debern inicializar (en su propio constructor), a la clase madre:
Python: class 6lase#ija(6lase3adre): de+ ,,init,,(sel+): # per(9.a#eHi-a( #e.&)/__init__() PHP: class 6lase#ija e2tends 6lase3adre { +unction ,,construct() { parent::,,construct()1 } }
Herencia: saber donde parar Podramos ponernos an ms meticulosos y decir que Puerta y Ventana son dos tipos de abertura diferentes y obtener entonces, el objeto ParedConAbertura en vez de ParedConVentana y ParedConPuerta. Sin embargo, aunque las aberturas compartan las mismas propiedades (como marco, altura, etc.), podramos caer en una herencia infinita de abertura y el diseo de los objetos, estara dejando de lado la simplicidad en nombre de la meticulosidad obsesiva.
Modelado y agrupacin Se puede decir que un modelo es la forma de agrupar clases y categorizarlas. Un modelo constituye un archivo (lo que para Python se denomina mdulo12). Cada modelo estar integrado por clases con relacin directa: Cada clase estar en su propio modelo (el
cual, llevar el nombre de la clase principal en minsculas) Subtipos estarn en el mismo modelo que el objeto madre Relacionales simples, estarn en el mismo modelo que el objeto al que componen
A la vez, todos los modelos, debern agruparse en un directorio al que podremos llamar models. En el caso de Python, este directorio deber poder ser manipulado como un paquete. Por este motivo, un archivo __init__.py deber incluirse al mismo.
Notar que por cuestiones de seguridad, en PHP trabajaremos con el conector mysqli y no con mysql. Sin embargo, en Python solo bastar con una funcin. La capa de abstraccin a bases de datos, pasar a formar parte del ncleo de la aplicacin, puesto
que podr ser reutilizada por cualquier componente de nuestro sistema. Para albergar archivos de ncleo, incluiremos un directorio llamado core.
Como puede observarse, la funcin run_query() recibe como parmetro una sentencia SQL. La funcin comprueba qu tipo de clusula se est invocando: Cuando la sentencia sea de tipo SELECT, retornar una tupla con N tuplas dentro, equivalentes a la cantidad de registros obtenidos de la ejecucin de dicha consulta Cuando la sentencia sea de tipo escritura (INSERT, DELETE y UPDATE), har un commit. Y cuando se tratase de una sentencia de tipo INSERT, retornar la ID del ltimo registro
insertado.
Sin dudas, mysqli es una gran ventaja frente al antiguo conector. Tiene una gran cantidad de clases, mtodos, constantes y propiedades muy bien documentados13. Sin embargo, entender la documentacin puede ser una tediosa tarea, en la cual, hallar un principio y un fin, se podr convertir en la peor pesadilla de tu vida. Antes de comenzar: debers instalar el paquete php5-mysql para poder trabajar con el conector mysqli:
sudo apt/get install p%p@/ $sql
Ahora s. Manos a la obra! Y a crear una capa de abstraccin con mysqli orientado a objetos.
Recetario
Lo primero que debemos tener en cuenta, es que nuestra capa de abstraccin deber proveer de mtodos pblicos, que puedan ser llamados de forma esttica, para que crear un objeto conector, no sea necesario.
13 http://php.net/manual/es/book.mysqli.php
Para poder lograr una capa de abstraccin genrica, la clave es utilizar ReflectionClass14 para crear una instancia de mysqli_stmt y mediante ReflectionClass->getMethod, invocar al mtodo bind_param. De lo contrario, preparar una consulta SQL y enlazarle los valores a ser filtrados, ser imposible.
Ten en cuenta que para seguir los ejemplos de este libro, es necesario contar con la versin 5.3.6 o superior, de PHP .
Propiedades Nuestra capa de abstraccin, tendr una nica propiedad pblica, destinada a almacenar los datos obtenidos tras una consulta de seleccin. El resto de las propiedades, sern de mbito protegido, accesibles solo desde nuestra clase y clases que hereden de sta.
class EB)ject { protected static .conn1 M )bjeto conector $sqli protected static .st t1 M preparacin de la consulta KP< M )bjeto =e+le2ivo de $sqli,st t protected static .re+lection1 protected static .sql1 M Kentencia KP< a ser preparada M Arra$ conteniendo los tipo de datos M !s los datos a ser enla8ados
14 http://php.net/manual/es/class.reflectionclass.php
La consulta SQL, deber ser seteada en los modelos (clases) donde se requiera, incluyendo marcadores de parmetros (embebidos con el signo ?), en la posicin donde un dato deba ser enlazado. Un ejemplo de ella, podra ser el siguiente:
.sql - RD9KE=; D9;) vidrio (espesor7 te2tura7 pig entacion) VA<*EK (S7 S7 S)R1
Mientras que el array $data, deber contener, como primer elemento, una string con el tipo de datos y los elementos siguientes, sern los datos a ser enlazados (todos pasados como string):
.data - arra$(RissR7 R{.t%is/0espesor}R7 R{.t%is/0te2tura}R7 R{.t%is/0pig entacion}R)1
El primer elemento, siempre representar el tipo de datos correspondiente al marcador de parmetro que se desea enlazar. Siendo los tipos de datos posibles: s (string), i (entero), d (doble) y b (blob).
Requerir 4 constantes predefinidas (se recomienda definirlas en un archivo settings): DB_HOST, DB_USER, DB_PASS y DB_NAME. Preparar una sentencia SQL (con marcadores de parmetros):
protected static +unction preparar() { sel+::.st t - sel+::.conn/0prepare( sel+::.sql)1 sel+::.re+lection - ne( =e+lection6lass( ' $sqli,st t')1 }
La clase ReflectionClass de PHP , cumple un papel fundamental: solo a travs de ella podemos crear un objeto mysqli_stmt reflexivo, siendo sta, la nica alternativa que tenemos para preparar sentencias SQL con marcadores de parmetros, de forma dinmica. La propiedad esttica $sql (self::$sql) ser creada
por el nico mtodo pblico que tendr la clase. Enlazar los datos con la sentencia SQL preparada:
protected static +unction set,para s() { . et%od - sel+::.re+lection/0get3et%od( 'bind,para ')1 . et%od/0invoTeArgs(sel+::.st t7 sel+::.data)1 }
La propiedad esttica $data que se pasa como segundo parmetro a invokeArgs, tambin ser seteada por el nico mtodo pblico. En este mtodo (set_params), la variable temporal $method, llama reflexivamente (a travs del mtodo getMethod de reflectionClass), al mtodo bind_param de la clase mysqli. En la siguiente instruccin, a travs del mtodo invokeArgs de ReflectionClass, le pasa por referencia a bind param, los datos a ser enlazados con la sentencia preparada (almacenados en el array $data). Podr a decirse que invokeArgs, se comporta de forma similar a call_user_func_array(). Enlazar resultados de una consulta de seleccin:
protected static +unction get,data(.+ields) { . et%od - sel+::.re+lection/0get3et%od(
Este mtodo es uno de los ms complejos y rebuscados, que incluso cuenta con algunas pseudo-magias un tanto raras como el uso de las funciones serialize y unserialize en la la misma instruccin. Pero analicmoslo detenidamente. El parmetro $fields ser recibido a travs del nico mtodo pblico que crearemos en nuestra capa de abstraccin (este mtodo, a la vez, recibir este dato, tambin como parmetro, pero opcional). Este parmetro, ser un array asociativo, donde las claves, sern asociadas al nombre de los campos, y el valor de esas claves, al dato contenido en el campo. Si tuviese la siguiente consulta SQL:
KE<E6; vidrio,id7 espesor7 te2tura7 pig entacion F=)3 vidrio U#E=E vidrio,id - S
mysqli->bind_result() enlazar el campo vidro.espesor a la clave espesor, vidro.textura a la clave textura y vidrio.pigmentacion a la clave pigmentacion. Las instrucciones:
. et%od - sel+::.re+lection/0get3et%od( 'bind,result')1 . et%od/0invoTeArgs(sel+::.st t7 .+ields)1
se comportan de forma similar, a sus homnimas en el mtodo set_params. Llama reflexivamente al mtodo bind_result de la clase mysqli y le pasa por referencia, al array $fields. En el bucle while, estamos asociando iterativamente los datos obtenidos a nuestra propiedad pblica $results. Pero cmo lo hacemos? para qu serializar y deserializar los datos?:
(%ile(sel+::.st t/0+etc%()) { sel+::.results&' - unseriali8e( seriali8e(.+ields))1
En cada iteracin, stmt->fetch nos est retornando nuestro array $fields, asociado al registro de la tabla, sobre el cul se est iterando. Es decir, que en cada iteracin, stmt->fetch nos retornar algo como esto:
.+ields - arra$(Rvidrio,idR -0 57 RespesorR -0 507 Rte2turaR -0 RlisaR7 Rpig entacionR -0 Rblancu8caR)1
Pero nuestro array $fields, ha sido pasado por referencia. Ergo, en cada iteracin, su contenido ser modificado. Si a mi propiedad esttica $results, le agrego como elemento, un array que est siendo modificado por referencia en el momento que lo estoy asignando a mi propiedad esttica, mi propiedad esttica, ser tambin, modificada en cada iteracin. Para prevenir eso, freezo mi array $fields y lo almaceno en $results serializado. Pero como luego necesitar recuperarlo, ahorro un paso y lo deserializo en la misma iteracin. Al serializarlo, estoy mgicamente emulando una inmutabilidad de los datos asociados.
Notar que cuando la consulta efectuada se realice por coincidencia con una clave primaria (id del objeto), no ser necesario acceder a la propiedad esttica $results, ya que los resultados se encontrarn reflejados en el array $fields, quien al ser pasado por referencia, es modificado tras la llamada a esta capa de abstraccin.
La estructura de control de flujo condicional, que utiliza el mtodo ejecutar(), es la encargada de discernir si se trata de una consulta de lectura a la base de datos para as, llamar al mtodo get_data, o si se trata de una consulta de escritura (INSERT, UPDATE o DELETE). En ese caso, verifica si es una escritura de tipo INSERT para retornar la id del nuevo registro creado. Cdigo completo de la capa de abstraccin
class EB)bject { protected static .conn1 protected static .st t1 protected static .re+lection1 protected static .sql1 protected static .data1 public static .results1 protected static +unction conectar() { sel+::.conn - ne( $sqli(EB,#)K;7 EB,*KE=7 EB,"AKK7 EB,9A3E)1 } protected static +unction preparar() { sel+::.st t - sel+::.conn/0prepare(sel+::.sql)1 sel+::.re+lection - ne( =e+lection6lass(' $sqli,st t')1 } protected static +unction set,para s() { . et%od - sel+::.re+lection/0get3et%od('bind,para ')1 . et%od/0invoTeArgs(sel+::.st t7 sel+::.data)1 } protected static +unction get,data(.+ields) { . et%od - sel+::.re+lection/0get3et%od('bind,result')1
Cmo utilizar la capa de abstraccin creada? En todos los casos, siempre ser necesario invocar estticamente al mtodo ejecutar(), pasndole al menos dos parmetros: la sentencia SQL a preparar y un array con los datos a enlazar a la sentencia SQL preparada:
.sql - RD9KE=; D9;) vidrio (espesor7 te2tura7 pig entacion) VA<*EK (S7 S7 S)R1 .data - arra$(RissR7 R{.t%is/0espesor}R7
Cuando se tratare de una consulta de seleccin, se deber adicionar un tercer parmetro, el cul ser un array asociativo, cuyas claves, sern asociadas a los campos de la tabla:
.sql - RKE<E6; vidrio,id7 espesor7 te2tura7 pig entacion F=)3 vidrio U#E=E vidrio,id - SR1 .data - arra$(RiR7 R{.t%is/0vidrio,id}R)1 .+ields - arra$(Rvidrio,idR -0 RR7 RespesorR -0 RR7 Rte2turaR -0 RR7 Rpig entacionR -0 RR)1 EB)bject::ejecutar(.sql7 .data7 .+ields)1
Finalmente, la responsabilidad del mtodo save(), ser establecer el valor de la propiedad objeto_id con el dato retornado por la capa de abstraccin, cuando la consulta, haya sido de tipo INSERT. Se debe tener en cuenta que todos los m todos save() -sin excepcin alguna-, para crear las consultas de insercin y actualizacin, tendrn en cuenta las mismas pautas que han sido mencionadas para el mapeo: todos los mtodos save() guardarn solo y nicamente los datos de aquellas propiedades que han sido establecidas como campo de su propia tabla. Si observamos los siguientes ejemplos, veremos que no existe diferencia alguna, entre los mtodos save() de objetos simples, compuestos y relacionales:
Python:
3 UN :;<E): =6'PLE class Vidrio(object): de+ ,,init,,(sel+): sel+.vidrio,id - 0 sel+.espesor - 0 sel+.te2tura - '' sel+.pig entacion - '' de& #ave(#e.&): i+ sel+.vidrio,id -- 0: sql - RRRD9KE=; D9;) vidrio (espesor7 te2tura7 pig entacion)
PHP:
3 UN :;<E): =6'PLE class Vidrio{ +unction ,,construct() { .t%is/0vidrio,id - 01 .t%is/0espesor - 01 .t%is/0te2tura - ''1 .t%is/0pig entacion - ''1 } & n%tion #ave() 2
3 UN :;<E): 9:'PUE=): class Ventana { +unction ,,construct(3arco . arco-9*<<) { .t%is/0ventana,id - 01 .t%is/0 arco - . arco1 } & n%tion #ave() 2 i+(.t%is/0ventana,id -- 0) { .sql - RD9KE=; D9;) ventana ( arco) VA<*EK (S)R1 .data - arra$(RiR7 R{.t%is/0 arco/0 arco,id}R)1 .t%is/0ventana,id - EB)bject::ejecutar( .sql7 .data)1 } else {
} } }
3 UN :;<E): >ELA96:NAL class <aja"ared { +unction ,,construct("ared .co puesto7 <aja .co positor-9*<<) { .t%is/0lajapared,id - 01 .t%is/0pared - .co puesto1 .t%is/0laja - .co positor1 .t%is/0relacion - 51 } +unction set,relacion() { .t pvar - 01 (%ile(.t pvar 4 .t%is/0relacion) { .t%is/0pared/0add,laja(.t%is/0laja)1 .t pvar>>1 } } & n%tion #ave() 2 i+(.t%is/0lajapared,id -- 0) { .sql - RD9KE=; D9;) lajapared (pared7 laja7 relacion) VA<*EK (S7 S7 S)R1 .data - arra$(RiiiR7 R{.t%is/0pared/0pared,id}R7 R{.t%is/0laja/0laja,id}R7 R{.t%is/0relacion}R)1 .t%is/0lajapared,id - EB)bject::ejecutar( .sql7 .data)1 } else { .sql - R*"EA;E lajapared KE; pared - S7
Como se puede apreciar, no hay diferencias entre los mtodos save() de los distintos tipos de objetos: todos los mtodos save() siguen la misma lgica algortmica. El orden de llamada para los mtodos save() siempre estar basado en el orden de dependencias.
El orden de llamada a los mtodos save() es un factor clave en la creacin de objetos, ya que de estos mtodos depende de forma directa, la identidad de cada uno de nuestros objetos
dependencias Un objeto simple, basta con crearlo y llamar a su mtodo save() correspondiente:
Python: piso - "iso() piso.tipo - '+lotante' piso. aterial - ' adera' piso.color - 'cedro' piso.save() PHP: .piso - ne( "iso()1 .piso/0tipo - '+lotante'1 .piso/0 aterial - ' adera'1 .piso/0color - 'cedro'1 .piso/0save()1
Llamar al compuesto
mtodo
save()
de
un
objeto
Un objeto compuesto, deber primero crear a su compositor, llamar al save() de ste, y luego crear el compuesto y llamar al save() del compuesto:
Python: vidrio - Vidrio() vidrio.espesor - 50 vidrio.te2tura - 'lisa' vidrio.pig entacion - 'blancu8ca' vidrio.save() arco - 3arco(vidrio) arco. aterial - 'alu inio'
Orden de llamada a los mtodos save() cuando interviene un compositor de pertenencia Cuando un objeto compuesto, dependa de un compositor de pertenencia, primero se deber crear el compuesto y llamar a su save(). Luego, se crearn uno a uno los compositores de pertenencia llamando al save() del compositor en cada creacin y una vez guardados todos los compositores, ser n agregados al compuesto:
Python: %abitacion - #abitacion(piso7 cielo,raso) %abitacion.save() pared,i8q - "ared() pared,i8q.%abitacion - %abitacion.%abitacion,id pared,i8q.save()
Orden de llamada de los mtodos save() cuando interviene un compositor reutilizable con un objeto relacional Cuando un objeto se componga de N compositores reutilizables, primero se deber crear y guardar el compositor; luego se deber crear y guardar el objeto compuesto(); a continuacin, se crear el objeto relacional, se guardar la relacin y finalmente, se se llamar al mtodo set_relacion() del objeto relacional:
Python: laja - <aja() laja.color - 'beige' laja.save() pared - "ared() pared.%abitacion - %abitacion.%abitacion,id pared.save()
Captulo XIII: Mtodos get() estndar, para objetos simples y objetos compuestos
El mtodo get() es el mtodo ms complejo de los tres mtodos comunes, save(), get() y destroy().
El mtodo get() en objetos simples En los objetos sin dependencias (es decir, objetos simples), el mtodo get() solo realizar una consulta a la base de datos para obtener los valores que le ayuden a setear sus propiedades:
Python: class Vidrio(object): de+ ,,init,,(sel+): sel+.vidrio,id - 0 sel+.espesor - 0 sel+.te2tura - '' sel+.pig entacion - ''
El mtodo get() en objetos compuestos En los objetos con propiedades compuestas por un nico objeto, el mtodo get() estar dividido en dos partes: la primera parte actuar como el get() de un objeto simple, mientras que la segunda, recurrir al get() de su compositor, para setear las propiedades compuestas por un solo objeto:
Python: class 3arco(object): de+ ,,init,,(sel+7 vidrio-9one): sel+. arco,id - 0 sel+. aterial - '' sel+.color - '' sel+.vidrio - co pose(vidrio7 Vidrio) de+ get(sel+): sql - RRRKE<E6; F=)3
U#E=E
+ields - run,quer$(sql)&0' sel+. arco,id - +ields&0' sel+. aterial - +ields&5' sel+.color - +ields&J' vidrio = Vidrio() vidrio/vidrio_id = &ie.d#?@A vidrio/get() #e.&/vidrio = vidrio PHP: class 3arco {
+unction ,,construct(Vidrio .vidrio-9*<<) { .t%is/0 arco,id - 01 .t%is/0 aterial - ''1 .t%is/0color - ''1 .t%is/0vidrio - .vidrio1 } +unction get() { .sql - RKE<E6; arco,id7 aterial7 color7 vidrio F=)3 arco U#E=E arco,id - SR1 .data - arra$(RiR7 R{.t%is/0 arco,id}R)1 .+ields - arra$(R arco,idR -0 RR7 R aterialR -0 RR7 RcolorR -0 RR7 RvidrioR -0 RR)1 EB)bject::ejecutar(.sql7 .data7 .+ields)1 .t%is/0 arco,id - .+ields&' arco,id''1 .t%is/0 aterial - .+ields&' aterial''1 .t%is/0color - .+ields&'color''1
Ms adelante, veremos como con la ayuda de una fbrica de objetos, todo el cdigo resaltado (es decir, la creacin del compositor), pasar a ser responsabilidad de un nuevo objeto Factory.
Es vlido aclarar que los subtipos y sus clases madres, poseern -cada uno de ellos-, un mtodo get() estndar como cualquier otro objeto.
Los mtodos get auxiliares, seleccionan solo la identidad de los compositores, utilizando como condicin, el valor de la propiedad de pertenencia. Cuando el compositor en cuestin, posea subtipos, adems de la identidad del objeto, deber retornar True o False en correspondencia a cada subtipo. Un ejemplo de consulta SQL para el objeto madre Pared, podra ser el siguiente:
KE<E6; pared,id7 DF(ventana DK 9*<<7 False7 ;rue)7 DF(puerta DK 9*<<7 False7 ;rue) pared %abitacion - 9
F=)3 U#E=E
El nombre de dichos mtodos estar conformado por la palabra get_ seguida del nombre de la propiedad del objeto compuesto, a la cual dicho compositor compone. Por ejemplo, el mtodo auxiliar de la clase Pared se llamar get_paredes(). Un ejemplo de mtodo get auxiliar, podramos encontrarlo en la clase madre Pared:
Python: de+ get,paredes(sel+): sql - RRRKE<E6; pared,id7 DF(ventana DK 9*<<7 False7 ;rue)7 DF(puerta DK 9*<<7 False7 ;rue) F=)3 pared
return run,quer$(sql) PHP: +unction get,paredes() { .sql - RKE<E6; pared,id7 DF(ventana DK 9*<<7 False7 ;rue)7 DF(puerta DK 9*<<7 False7 ;rue) F=)3 pared U#E=E %abitacion - SR1 .data - arra$(RiR7 R{.t%is/0%abitacion}R)1 .+ields - arra$(Rpared,idR -0 RR)1 return EB)bject::ejecutar( .sql7 .data7 .+ields)1 }
Como se puede observar, los mtodos get auxiliares solo retornan datos y no objetos. En el caso de Python, retornar una tupla con N tuplas dentro, conteniendo la identidad de cada compositor pertenenciente al compuesto que luego lo invoque. Y en el caso de PHP , retornar un array, compuesto de N arrays asociativos. Estos mtodos get auxiliares, como se coment en el prrafo anterior, sern invocados desde el mtodo get() del objeto compuesto, a quien le tocar la parte ms compleja en la historia de los mtodos get() no estndar. Veamos el caso de Habitacion:
Python: de+ get(sel+):
+ields - run,quer$(sql) sel+.%abitacion,id - +ields&0' piso - "iso() piso.piso,id - +ields&5' piso.get() sel+.piso - piso cr - 6ielo=aso() cr.cielo,raso,id - +ields&J' cr.get() sel+.cielo,raso - cr 3 Ha#ta aB C e. !Dtodo get() e#t5ndar 3 6n%orpora!o# na eEten%iFn pared - "ared() pared.%abitacion - sel+.%abitacion,id 3 ..a!ada a. !Dtodo a Ei.iar paredes - pared.get,paredes() 3 6tera!o# para o$tener .o# o$-eto# +or tupla in paredes: i+ tupla&5' is not False: pared - "ared6onVentana() pared.pared,id - tupla&0' pared.get() sel+.add,paredconventana(pared) eli+ tupla&J' is not False: pared - "ared6on"uerta() pared.pared,id - tupla&0' pared.get() sel+.add,paredconpuerta(pared) else: pared - "ared() pared.pared,id - tupla&0'
1. Modificar su propiedad relacin 2. Recuperar al compositor (invocando al mtodo get() de ste) para modificar a su propiedad compositor Finalmente, llamar a su propio mtodo set_relacion() para que se encargue de componer al objeto que lo ha invocado. Un ejemplo de consulta SQL de seleccin en un objeto relacional multiplicador, sera el siguiente:
KE<E6; relacional,id7 co positor7 relacion F=)3 relacional U#E=E co puesto - 9
De modo genrico, el mtodo get() de un relacional multiplicador, deber guardar siempre la siguiente forma y estructura:
Python: de+ get(sel+): sql - RRRKE<E6; relacional,id7 co positor7 relacion F=)3 relacional U#E=E co puesto - :iRRR : Q sel+.co puesto.co puesto,id +ields - run,quer$(sql)&0' sel+.relacion - +ields&5' co positor - 6o positor() co positor.co positor,id - +ields&0' co positor.get()
Finalmente, el objeto compuesto se encargar de llamar al get() del relacional, como ltima instancia de su mtodo get() estndar:
Python: de+ get(sel+): ... pasos est!ndar re.a%iona. = >e.a%iona.(#e.&) re.a%iona./get()
Notar que al crear el objeto relacional, el objeto compuesto se pasa a s mismo como parmetro:
"$t%on: =elacional(#e.&) "#": ne( =elacional($thi#)
Captulo XVI: Factora de objetos con Factory Pattern. Objetos compuestos con mtodos get() mucho ms simples
Factory es -al igual que composite- un patrn de diseo. Su sencillez y simpleza, consisten en un mtodo encargado de crear otros objetos. Para qu nos puede ser til un objeto Factory? Para que los mtodos get() que deben llamar al mtodo homnimo de los objetos que lo componen, pueda ser ms limpio, menos redundante y por lo tanto, ms eficiente. Imaginemos un objeto compuesto por otros 3 objetos. El mtodo get() de ste, se ver como el siguiente:
Python: class )bjetoE(object): de+ ,,init,,(sel+7 objetoa-9one7 objetob-9one7
EB)bject::ejecutar(.sql7 .data7 .+ields)1 .t%is/0objetod,id - .+ields&'objetod,id''1 .objetoa - ne( )bjetoA()1 .objetoa/0objetoa,id - .+ields&'objetoa''1 .objetoa/0get()1 .t%is/0objetoa - .objetoa1 .objetob - ne( )bjetoB()1 .objetob/0objetob,id - .+ields&'objetob''1 .objetob/0get()1 .t%is/0objetob - .objetob1 .objetoc - ne( )bjeto6()1 .objetoc/0objetoc,id - .+ields&'objetoc''1 .objetoc/0get()1 .t%is/0objetoc - .objetoc1 } }
Hay una realidad y es que el mtodo get() del ObjetoD solo debera tener la responsabilidad de setear sus propiedades con los datos obtenidos. Sin embargo, como puede verse, se encuentra forzado a tener que crear una instancia de cada una de los objetos que lo componen, modificar su id, llamar al
Un objeto a nivel del core, encargado de crear y retornar otros objetos, ser la solucin a este problema:
Python: class Factor$6lass(object): de+ aTe(cls7 clase7 id,value7 idna e-''): obj - clase() p - idna e i+ idna e else R:s,idR : Q obj.,,class,,.,,na e,,.lo(er() setattr(obj7 p7 id,value) obj.get() return obj
PHP: class Factor$6lass { public static +unction aTe(.cls7 .id,value7 .idna e-'') {
De esta forma, el seteo de las propiedades compuestas de un objeto, requerir slo de una
.data - arra$(RiR7 R{.t%is/0objetod,id}R)1 .+ields - arra$(Robjetod,idR RobjetoaR -0 RobjetobR -0 RobjetocR -0 -0 RR7 RR7 RR7 RR)1
} }
EB)bject::ejecutar(.sql7 .data7 .+ields)1 .t%is/0objetod,id - .+ields&'objetod,id''1 $thi#1,o$-etoa = 4a%tory9.a##::!aGe( +:$-etoA+( $&ie.d#?+o$-etoa+A); $thi#1,o$-eto$ = 4a%tory9.a##::!aGe( +:$-eto;+( $&ie.d#?+o$-eto$+A); $thi#1,o$-eto% = 4a%tory9.a##::!aGe( +:$-eto9+( $&ie.d#?+o$-eto%+A);
Sin embargo, solo puede existir una -y solo unacoleccin de objetos A. Esta coleccin ser la suma de todos los objetos A existentes, y por tanto, no ser necesaria una ID de ObjetoACollection. Pero debemos asegurarnos de que esto se cumpla. Y para ello, disearemos al nuevo ObjetoCollection como un Singleton.
Singleton es un patrn de diseo. Un Singleton es un objeto de instancia nica (no puede ser instanciado ms de una vez) y para lograr esto, l -y solo l-, puede generar una instancia de s mismo.
Como solo podr tener una nica instancia, la misma se almacenar en una propiedad privada esttica:
class )bject6ollection { private static .objectcollection1 M al acenar! una instancia de sW is o private +unction ,,construct() { .t%is/0objects - arra$()1 } }
El nico mtodo pblico, ser su propio get() esttico quien antes de actuar, ser el encargado de crear una nica instancia de s mismo:
class )bject6ollection { private static .objectcollection1 private +unction ,,construct() { .t%is/0objects - arra$()1 } private +unction add,object()bject .object) { .t%is/0objects&' - .object1 } public static +unction get() { i+(e pt$(sel+::.objectcollection)) {
sel+::.objectcollection - ne( )bject6ollection()1
} } }
} } return sel+::.objectcollection1 }
El mtodo __new__ es un mtodo esttico invocado por Python al crear una nueva instancia de clase. Al sobrescribirlo, se debe invocar al mtodo __new__ de la superclase, utilizando super(clase_actual, cls).__new__(cls). Cada vez que el objeto colector sea llamado, el mismo objeto ser retornado (no se crearn mltiples instancias). Es decir que la sobre-escritura del mtodo __new__, ser la encargada de retornar siempre, la misma instancia.
El mtodo __init__ ser suprimido, a fin de forzar la creacin del objeto solo y nicamente dentro de la propia clase. En reemplazo del mtodo __init__ un mtodo set() privado, ser el encargado de definir las propiedades del colector:
class )bject6ollection(object): ,,objectcollection - 9one
de+ ,,ne(,,(cls): i+ cls.,,objectcollection is 9one: cls.,,objectcollection - super( )bject6ollection7 cls).,,ne(,,(cls) return cls.,,objectcollection de+ ,,set(sel+): sel+.,,objectcollection.objetos - &'
El nico mtodo pblico, ser su propio get() quien antes de actuar, ser el encargado de llamar a __set():
class )bject6ollection(object):
,,objectcollection - 9one de+ ,,ne(,,(cls): i+ cls.,,objectcollection is 9one: cls.,,objectcollection - super( )bject6ollection7 cls).,,ne(,,(cls) return cls.,,objectcollection de+ ,,set(sel+): sel+.,,objectcollection.objetos - &' de+ ,,add,objeto(sel+7 objeto): sel+.,,objectcollection.objetos.append( objeto) de+ get(sel+): sel+.,,objectcollection.,,set()
reutilizables de identidad diferenciada y N2 objetos compuestos. Recientemente, Christian -uno de mis alumnos-, me trajo un caso de compositores reutilizables que requieren de un conector lgico, ampliamente mucho ms esclarecedor que el que vena utilizando como ejemplo en mis clases. Por ese motivo, me tomo la atribucin de citarlo en este libro como ejemplo. Imaginemos un sistema de gestin de eventos festivos, donde tenemos un amplio listado de invitados. Cada invitado puede asistir a diferentes eventos, lo que significa que los distintos eventos, pueden compartir los mismos invitados. Al mismo tiempo, cada evento tiene un gran nmero de invitados. Si los invitados pueden asistir a diferentes eventos, descartamos estar en presencia de compositores de pertenencia. Y al estar Evento compuesto por varios invitados, pero cada uno de ellos, de identidad nica, descartamos estar en presencia de un compositor reutilizable cuya relacin, requiera ser establecida por un objeto relacional multiplicador. Tenemos en consecuencia una relacin de N compositores a N compuestos. Cmo haremos
para establecer la relacin entre ellos? Es aqu que surge la necesidad de contar con un conector lgico relacional. Propiedades del conector lgico El objeto conector lgico, contar entonces, con al menos tres propiedades: 1. Su propiedad objeto_id 2. Objeto compuesto 3. Una coleccin de compositores cuyo valor, se obtendr de la coleccin provista por el objeto compuesto
Python: class DnvitadoEvento(object): de+ ,,init,,(sel+7 evento): sel+.invitadoevento,id - 0 sel+.evento - co pose(evento7 Evento) sel+.invitados - evento.invitados PHP: class DnvitadoEvento { +unction ,,construct(Evento .evento) { .t%is/0invitadoevento,id - 01 .t%is/0evento - .evento1 .t%is/0invitados - .evento/0invitados1 }
Mapeo relacional Cuando un conector lgico debe ser mapeado, se tendr en consideracin todo lo visto en el Captulo VII. Pero cmo se mapean las colecciones? La propiedad colectora de este objeto, a diferencia de las vistas hasta ahora, no posee como valor asociado un array ni una lista vaca. Por el contrario, desde su inicializacin, adoptar como valor una coleccin de objetos. El conector lgico deber iterar sobre la propiedad colectora y por tal motivo, dichas propiedades son mapeadas como si se tratara del objeto compositor en un relacional simple. Obteniendo por tanto (si continuamos con el mismo ejemplo) un campo invitado que ser clave fornea con efecto en cascada. Por consiguiente, la consulta SQL generada, lucir como la siguiente:
6=EA;E ;AB<E invitadoevento ( invitadoevento,id D9;(55) 9); 9*<< A*;),D96=E3E9; "=D3A=F,GEF 7 evento D9;(55) 7 D9EEL(evento)
reemplazada por una nueva. Por tal motivo, siempre antes de ejecutar su propio algoritmo, llamarn al mtodo de destruccin. Ten en cuenta que la relacin final resultante, siempre ser entre 1 compositor y 1 compuesto. Dicho mtodo deber generar de forma dinmica, tanto la consulta SQL de insercin como los valores a ser insertados, ya que deber guardar cada par compuesto-compositor como un nico registro y no queremos conectarnos y desconectarnos a la base de datos, por cada par compuesto-compositor a insertar. Para lograrlo, deber iterar sobre la propiedad colectora:
Python: de+ save(sel+): sel+.destro$() sql - RRRD9KE=; D9;) invitadoevento (evento7 invitado)RRR data - &' t pvar - 0 +or invitado in sel+.invitados: sql >- R7 R i+ t pvar 0 0 else R VA<*EK R sql >- R(:i7 :i)R data.append(sel+.evento.evento,id) data.append(invitado.invitado,id) t pvar >- 5 run,quer$(sql : tuple(data))
PHP: +unction save() { .t%is/0destro$()1 .sql - RD9KE=; D9;) invitadoevento (evento7 invitado)R1 .data - arra$(RR)1 .t pvar - 01 +oreac%(.t%is/0invitados as .invitado) { .sql .- (.t pvar 0 0) S R7 R : R VA<*EK R1 .sql .- R(S7 S)R1 .data&0'.- RiiR1 .data&' - R{.t%is/0evento/0evento,id}R1 .data&' - R{.invitado/0invitado,id}R1 .t pvar>>1 } EB)bject::ejecutar(.sql7 .data)1 }
El mtodo destroy() El mtodo destroy() se encargar de destruir de forma masiva, todas las relaciones existentes con el compuesto:
Python: de+ destro$(): sql - RRREE<E;E F=)3 invitadoevento U#E=E evento - :iR : Q sel+.evento.evento,id run,quer$(sql)
El mtodo get() El mtodo get() del conector lgico, realizar la consulta de forma similar a un mtodo get auxiliar. Sin embargo, su comportamiento, ser distinto. Con los resultados obtenidos de la consulta, deber crear los compositores -al igual que el mtodo get() de un objeto relacional simple- de forma iterativa y agregarlos al compuesto:
Python: de+ get,relacion(sel+): sql - RRRKE<E6; invitado F=)3 invitadoevento U#E=E evento - :iRRR : Q sel+.evento.evento,id results - run,quer$(sql) +or +ield in results: invitado - Dnvitado() invitado.invitado,id - +ield&0' invitado.get() sel+.evento.add,invitado(invitado)