| Login | Tour | Inicio | Chat | Descargas | Wallpapers | Páginas recientes | FAQ | | |||||||||||||||
Custom Search
![]() Emacs como IDE para CakePHP aarkerio La Negación del Viaje Lunar tonathiu Porque los mononeurones si tenemos madre! blacksoul BrunoFerías thot The Art vendaval Aclimatación extraterrestre ¿para qué? ahuramazdah ¿A que le tienes miedo? teosho Sobre nazis, terror y medios tonathiu Amenazas a la cuarta dimensión ¿de veras? ahuramazdah Tarjeta Broadcom BCM94311MCG rev 02 teosho Pidiendo OpenSolaris 2008.5 vendaval Sospechosismo aarkerio Slackware 12.1 Final vendaval Jaime Maussan da por auténtico video trucado del chupacabras hecho en Blender 3D asarch Linux hot girl aarkerio Calderón puede ser sujeto a juicio político, sostiene Carrancá tonathiu La desnutrición en México aarkerio Sistema Infalible ordbal Histórico aarkerio Nietzsche en la FCPyS aarkerio ![]() GNU/Linux ![]() Hacktivismo ![]() Debian ![]() NetBSD ![]() WWW ![]() Guia Linux ![]() Server Side ![]() Ofimatica ![]() Despabilando... ![]() Mundo Maya ![]() Literatura ![]() Agora ![]() Psicologia ![]() Economia ![]() Ambientalismo ![]() Desarrollo Biologia ![]() |
Desarrollo \ Patrones de diseño en Python Este artículo ha sido consultado en 846 ocasiones. Patrones de diseño en PythonVespe
Savikko
Traducido
por
Iván Márquez Larios SinopsisLa elección del lenguaje con el que se implementará afecta el uso de los patrones de diseño. Naturalmente algunos lenguajes aplican mejor que otros para distintas tareas. Cada lenguaje tiene su propio conjunto de fuerzas y debilidades. En este ensayo implementamos algunos de los patrones de diseño más comunes en Python, cuyo modelo de objetos es bastante distinto al de los lenguajes orientados a objetos convencionales. Por lo tanto, conseguimos algo de visión interna de los patrones en el contexto de Python. 1. IntroducciónEn la ingeniería de software el término patrón describe una solución probada a un problema común en un contexto específico. Los patrones pueden ser divididos en 3 distintas categorías dependiendo del nivel de abstracción e independencia del lenguaje de implementación: patrones arquitectónicos, patrones de diseño e idiomas [BMR+96]. En este trabajo nos concentramos en las últimas dos categorías: los patrones de diseño como son descritos en el libro de los conocidos como GANG OF FOUR (Banda de cuatro) [GHJV95] y los idiomas del lenguaje Python. Los patrones no son sólo modelos microarquitectónicos, también son útiles como un vocabulario de diseño para los ingenieros de software. La arquitectura general del sistema y las decisiones de diseño relacionadas pueden ser explicadas dando un conjunto de patrones utilizado. Aunque nuevos patrones surgen, el GOF permanece como una referencia definitiva de patrones de diseño. Por esta razón es importante introducir estos patrones, las nociones y la teoría detrás de ellos y su aplicabilidad a la comunidad Python. El GOF está divido en tres partes y cada una describe los patrones relacionados con el tema de esa parte. Los temas describen el propósito de los patrones. Los patrones de creación se relacionan con problemas de instanciación de objetos. Los patrones estructurales se concentran en la composición de los objetos y sus relaciones con la estructura de los objetos en tiempo de ejecución. Mientras que los patrones estructurales describen la distribución del sistema de objetos, los patrones de comportamiento se enfocan en la dinámica interna e interacción de los objetos en el sistema. Aunque los patrones de diseño aspiran a ser independientes del lenguaje requieren - al menos implícitamente - algo de soporte desde el lenguaje de implementación y especialmente desde su modelo de objetos. En el GOF los lenguajes elejidos son C++ y Smalltalk. Por ello la disponibilidad de especificadores de acceso y funciones miembro estáticas (métodos de clase) son asumidos. El blanco es mirar algunos de los patrones del GOF y tratar de implementarlos en un lenguaje (Python) cuyo modelo de objetos sea radicalmente distinto del de C++. Al hacer esto podemos llegar a algunas conclusiones acerca de la generalidad de los patrones del GOF y sus comodidades - si las hay - son necesarias cuando los aplicamos al ambiente de programación de Python. Y mientras operamos en el nivel del lenguaje de programación observamos algunos idiomas de Python y cómo pueden ayudar a implementar los patrones del GOF. Comenzamos con una breve descripción de Python como un lenguaje de objetos en la sección 2 y luego avanzamos hacia los patrones seleccionados. Elegimos un patrón de cada categoría del GOF: Singleton (creacional, sección 3), Cadena de responsabilidad (comporamiento, sección 4) y Proxy (estructural, sección 5) En la sección 6 sumarizamos las lecciones aprendidas y analizamos a detalle la generalidad de nuestras soluciones de implementación. 2 PythonSimplificando, Python es un lenguaje interpretado con tipos de datos débiles y dinámicos. Estos atributos combinados con una gran variedad de extensiones hacen que Python sea la elección natural para distintos propósitos, por ejemplo scripts CGI. Python también es mencionado como un fuerte candidato para un lenguaje de manejo [Dub96 ] por su naturaleza expresiva e interpretada. Desde la perspectiva de la programación orientada a objetos, Python tiene todas las características necesarias y más: clases, herencia múltiple, sobrecarga de operadores. Un aspecto peculiar del modelo de objetos de Python es su negligencia hacia el ocultamiento de los datos. Por el momento digamos que la política de Python puede ser descrita como ''encapsulación por cortesía '' siendo esto que la instancia de una clase asume que ninguno de sus clientes tratará de traspasar la interfaz de la clase y manipular los atributos de la instancia directamente. Sin embargo, la situación no es totalmente severa; la versión 1.4 del lenguaje impelmenta privacidad utilizando ocultamiento de nombres. Esta solución se considera experimental antes de concebir un mecanismo adecuado [vR96] .La otra
característica sobresaliente de los objetos de Python es que
no son meramente instancias de sus clases; sus estructuras pueden
cambiar en tiempo de ejecución. Este nivel de
flexibilidad combinado con la habilidad de la instancia de atrapar el
acceso a los atributos finca las bases para varios idiomas de
python. Por otro lado también requiere de algun
control del programador, porque demasiado código
"dinámico" puede ser bastante difícil de entender
y mantener. Esto aplica también para los programas
de Python en general; mientras que el lenguaje hace fácil
realizar tareas relativamente complejas, no nos alivia a los
programadores de las demandas de los principios de diseño. 3 SingletonEl patrón singleton provee un mecanismo para limitar el número de instancias de una clase a uno. Por lo tanto el mismo objeto es siempre compartido por distintas partes del código. Un Singleton puede ser visto como una solución más elegante para una variable global porque los datos son abstraídos por detrás de la interfaz de la clase singleton. Primero vemos cómo puede ser implementado un singleton en C++ y luego proveemos la solución con Python con las mismas características.
Nuestra definición
mínima de un
singleton
(Fig. 1)
tiene solo
un miembro público: el método
manejador de la clase Handler.
La
interfaz definida no es muy
útil comotal, porque el cliente no puede hacer nada con la
instancia, pero ahoranos concentramos solo en las técnicas
que aseguran una solainstancia del singleton a la vez.
Ya que Python no tiene
constructores privados debemos encontrar una
alternativa para prevenir instanciaciones. Nuestra
aproximación en la figura 3
es para lanzar una
excepción si el objeto singleton ya se encuentra instanciado
(el atributo privado de la clase __single
es
distinto de None).
¡El objeto
excepción es la
instancia singleton! La desventaja de esta
solución
es que requiere que los clientes estén preparados para la
excepción. También podría ser
argumentado que utilizar excepciones para otros propósitos
distintos del manejo de errores no es un muy buen estilo.
Estas consideraciones pueden ser eliminadas hasta cierto punto
proveyendo un manejador
similar al de la figura 2.
Esta
función oculta los detalles de la instanciación
poco ortodoxa y devuelve una referencia al objeto singleton (Fig. 4).
Debido al sistema de tipos de
Python el código en
la figura 4
funciona para toda la jerarquía singleton.
Consideremos la siguiente situación: la clase Singleton
tiene
sublcases Child
y Junior
como se muestra en la figura 5.
Debido a que existe una relación es-un
entre la clase base y
la subclase solamente puede haber una instancia de toda la
jerarquía. Una instancia de Singleton
o Junior
puede ser creada con la función Handle.
El
constructor de la clase toma un parámetro
-explícito- para que la instanciación deba ser
hecha con una llamada directa al constructor o a una función
especializada de manejo. El siguiente código
demuestra la jerarquía Singleton: >>> child = Child( 'Monty' )Algunas veces es conveniente decidir en tiempo de ejecución cuál clase singleton será instanciada. El GOF propone un acercamiento basado en registro, donde el cliente consulta a un objeto especial registro, el cual contiene un alista de pares nombre-Singleton. Solicitando un singleton por su nombre, elcliente recibe una referencia a la instancia correspondiente deSingleton. Actualizar el registro puede serproblemático: ¿Quién registra unSingleton? si es la instancia misma de Singleton (en suconstructor) !entonces todos los posibles Singleton deben serinstanciados para poder ser accesibles por los clientes del registro! Afortunadamente la
simplificación es posible a
través de los conceptos de domino de nombres de
Python. Los ámbitos local y global - o en su
defecto su representación de diccionario - pueden ser
accedidos por funciones locales
y globales.
Por ejemplo
podríamosinstanciar Junior:
>>> name = 'Junior'Por supuesto, ahora el registro (en el ámbito del diccionario) contiene mucho más que solo información relacionada al singleton, por lo que siempre existe un riesgo de que un cliente trate alguna función como una clase Singleton. Esta desafortunada coincidencia puede ser evitada hasta cierto puntoutilizando alguna convención de nomenclatura para lossingleton. Un objeto de registro específico es unabuena idea aún en el ambiente Python. Los clientesno deberían acceder a los diccionarios de ámbitodirectamente sion a través del registro. Ahora elregistro puede detectar y denegar cualquier búsqueda desingleton que sean ilegales de acuerdo con la convención denomenclatura. Nuevamente, esta aproximacióndepende en la cortesía de los clientes. Tal vez la solución
más segura y
directa es la de registro en el nivel del módulo.
Cada módulo que contenga clases Singleton
deberían
también contener sentencias de inicialización que
registren los nombres de las clases con el módulo de
registro. Debido a que los módulos son
inicializados sólo la primera vez que son importados, un
cliente obtiene acceso al registro importando el módulo del
registro. En cierto modo un módulo puede
ser visto como un Sigleton rudimentario. Una ventaja de este
estilo de registro explícito es la opción de
implementar tantos registros sofisticados como sean
necesarios. En otras palabras podremos almacenar
más información acerca de los singleton que solo
los nombres de las clases, por ejemplo los nombres de los
módulos, diferentes restricciones y
así.
El registro puede también
ofrecer diferentes servicios para las búsquedas de
singleton, estadísticas y depuración, por ejemplo.
4 Cadena de responsabilidadLa motivación detrás de un patrón de cadena de responsabilidad es crear un sistema que pueda servir a diversas solicitudes de manera jerárquica. En otras palabras, si un objeto que es parte de un sistema no sabe cómo responder a una solicitud en específico, la pasa a lo largo del árbol de objetos. Como el nombre lo implica, cada objeto a lo largo de la ruta de la solicitud puede tomar la responsabilidad y atender la solicitud.Un patrón de cadena
de responsabilidad es a menudo
utilizado en el contexto de interfaces gráficas de usuario
donde un objeto puede contener varios otros objetos.
Como el ambiente de ventanas genera eventos los objetos o los manejan o
los pasan a su objeto padre(contenedor), como en la figura 6.
La implementación
del patrón en C++ es relativamente directa: en nuestro
ejemplo de GUI cada objeto podría ser una subclase de la
clase Widget
definida en la figura 7. Mientras
que esto es también una solución alcanzable en
Python, no utiliza el modelo de objetos de Python
a su potencial máximo. Una
aproximación más dinámica y flexible
es
utilizar las técnicas introducidas en el patrón
de
despacho de comandos de Guido van Rossum [vR97]:
búsqueda y adición dinámica de
atributos.
Con Python no
necesitamos restringirnos al conjunto predefinido de
métodos como lo hicimos con la jerarquía Widget:
el único camino para manejar este evento era
llamando a Handle.
La idea
detrás del
patrón de despacho de comando es checar en tiempo de
ejecución si el objeto tiene un método propio o
no. Nuestra clase Widget
en Python(Fig. 8)
provee a sus
subclases
con este mecanismo de despacho. El uso de clases
evento separadas (Event en la figura 8)
enfatiza
el hecho de que varias clases de información pueden ser
transmitidas a través dela cadena.
Solamente el atributo name
es asumido. Dado que nuevos atributos pueden ser
añadidos dinámicamente y nuevos
métodos
pueden ser agregados a traves de sublcases, la interface de la
clase base Event
puede ser mantenida al
mínimo.
Cuando un objeto evento
es pasado al método Handle,
una de cuatro cosas pueden pasar:
Algunas clases Python
para nuestro GUI de ejemplo son implementadas en la Figura 9.
El siguiente código construye la cadena y demuestra
su uso: >>> sd = SendDialog( mw )Un aspecto curioso de nuestra solución es que un manejador de eventos no necesariamente requiere ser un método; puede también ser un objeto función. Esto permite al programador añadir nuevos manejadores de eventos a objetos existentes en lugar de crear nuevas clases a través de la herencia. Dadas las funciones de ámbito de Python, una función evento no puede acceder a los atributos del objeto contenedor. Sin embargo, ya que la función evento por sí misma es un atributo puede ser borrada. En otras palabras, las funciones evento proveen medios para crear temporalmente manejadores de eventos a una jerarquía de cadena de responsabilidad existente. Un ejemplo simple: ... print 'Name: ' + e.name 5 ProxyDesde la perspectiva del diseño orientado a objetos la habilidad para atrapar accesos a atributos provee algunas nuevas soluciones a viejos problemas. Un buen ejemplo es el patrón Proxy, el cual es utilizado cuando un objeto tiene que ser escudado de sus clientes. Puede haber varias razones para ello: conteo de referencias, distintos niveles de permisos de acceso,evaluación floja del estado de un objeto y otras. La estructura del objeto en tiempo de ejecución para el patrón es mostrada en la figura 10.
El cliente no necesita saber que no está accediendo al objeto real(Subject) directamente. En otras palabras, el proxy substituye al objeto real. En C++ esto podría significar que ambos, el proxy y la clase sujeto tienen una clase común de base. En Python el mismo efecto puede ser logrado enmascarando la instancia del proxy como el objeto proveyendo la misma interface de métodos. Nuestra clase proxy en la figura 11 está basada en la clase cuasiuniversal Wrapper [vR96]. Como tal, la clase Proxy es sólo una envolvente trivial para cualquier objeto. Sin embargo, su función principal es la de servir a su clase base para implementaciones más específicas. Dado que el método __gettattr__ es llamado sólo como el último recurso el proxy puede manejar un método sujeto diferentemente "sobrecargándolo" en la claseproxy. Consideremos la siguiente situación: accedemos una instancia de la clase RGB (Fig. 12) primero directamente, luego utilizando una instancia de Proxy genérica como una envolvente y finalmente a través de una instancia de NoBlueProxy (Fig. 13): >>> rgb = RGB( 100, 192, 240 )
Mientras que python provee
algunos mecanismos que son usualmente implementados con
el patrón Proxy (por ejemplo el conteo de referencias
simples)el patrón es todavía altamente aplicable
a la comunidad Python. Un excelente ejemplo es el paquete
deDaniel Larsson RemoteCall [Lar97],
que provee un mecanismo simple para aplicaciones
distribuidas.
Uno de los conceptos clave en el sistema es el rol de agente,
el cual es una representación del lado del cliente de los
objetos del lado del servidor - en otras palabras, proxies.
La
historia del paquete también demuestra un aspecto digno de
mencionar de los patrones en general: el autor reconoció que
había aplicado un patrón después
después de su
implementación. 6 ConclusionesLos patrones del GOF y los de Python pueden beneficiarse mutuamente. Mientras quea Python le faltan algunas características que el GOF asume, no es imposible construir implementaciones de los patrones que funcionen como sus contrapartes del GOF. Nuestra implementación del Singleton sustituyó los constructores privados con un mecanismo de excepción y un método de clase con una función regular pero el patrón subyacente es claramente el Singleton. Es importante notar la diferencia entre un patrón y suimplementación. En Singleton nuestro enfoque principal era mantener las características del patrón descritas en el GOF. Esto guía a una solución que probablemente es muy obscura para ser reconocida como un patrón Python. Una solución más intuitiva - y más del estilo Python tal vez - sería abandonar los problemas de encapsulación y proveer simplemente una función fábrica para la instancia Singleton [Lun97].El uso de Python como un
lenguaje de implementaciones puede
también reforzarel patrón. La
naturaleza flexible y dinámica del lenguaje
provee una buena base para una variedad de distintas y
elegantes soluciones. Nuestra cadena de responsabilidad hace
el patrón más dinámico
al implementarlo con el patrón despacho de
comandos,
el cual toma ventaja de las capacidades de Python en tiempo de
ejecución. Estas capacidades
incluyen búsquedas y adiciones de atributos en tiempo
de ejecución. En otras palabras, las instancias
de una misma clase no necesariamente requieren tener
estructura idéntica y el acceso a los atributos puede ser
monitoreado y atrapado. Estos mecanismos proveen una
forma bastante elegante de implementar varias clases
genéricas como en nuestra implementación del
Proxy. Elegimos tres patrones para
enfatizar los problemas
discutidos, pero tenemos la confianza de que otros patrones del GOF
pueden ser implementados en Python, y con resultados
similares. Mientras que los patrones pudieran terminar con
características flexibles y dinámicas
después del proceso, no necesariamente
erosionaría
la usabilidad y reconocibilidad de los patrones. La
familiaridad y el orden provisto por el uso de patrones puede
ofrecer mayores beneficios para diversos sistemas de objetos y
frameworks Python. Referencias
|
![]() Preparandome para el viaje a Puerto Vallarta... que triste... 1 hour, 22 minutes ago Du hast? 5 hours, 25 minutes ago Ich habe einen Kater, aber nicht so schlecht... 13 hours ago Y yo un Abrazo. 1 day, 12 hours ago Dandole su habrazote a mi santa madre que me soporta 1 day, 14 hours ago esperando a que este el pozole 1 day, 16 hours ago Que estuvimos haciendo >> 10410 lecturas Sexualidad infantil y juvenil 9166 lecturas Anticoncepción de Emergencia 7840 lecturas Rompiendo cualquier clave WEP en unos pocos minutos 6917 lecturas Sinapsis y exocitosis 6227 lecturas Mi primer CakePHP, mmmmm cakeee 5260 lecturas Evolución filética en las hepáticas 4697 lecturas BASH y Primeros Comandos 4012 lecturas CakePHP II Active Record 3742 lecturas Cómo convertirse en hacker 3619 lecturas
|
|||||||||||||
| |||||||||||||||
| Casarse está bien. No casarse está mejor. San Agustín. | |||||||||||||||
| Este trabajo está licenciado bajo la MonoNeurona Commons License. 2002-2008 © :: Colectivo MonoNeurona.org :: | |||||||||||||||