[pyar] Patrones de diseño: Strategy

Luis Andraschnik luis.andraschnik en gmail.com
Mie Feb 21 10:48:43 -03 2018


Hola Cristhian

Si estrictamente hablando tenés razón, lo que quería decir es que la
implementación del patrón de diseño es lenguanje-dependiente. Más que nada
lo dije para aclarar que los ejemplos que había leído eran específicamente
de Python y no pensaran que los saqué de Java, que suele ser la fuente más
habitual de información sobre PD.

La solución con diccionario sin usar clases era la que se me ocurrió. Los
ejemplos con getattr son cosas nuevas para mí, y que recién empiezo a
digerir.
si bien las clases las utilizo a diario, hasta ahora no escribí ni una. Me
cuesta mucho romper la barrera mental de la programación procedural y ver
muchos self, __init__,  __magicmethods__, __getattr__ juntos me hacen que
se me nuble la vista y pierdo el hilo del programa. La POO es un tema que
vengo evitando y siempre me pregunto si vale la pena (te acordás la charla
de Jack Diederich "Stop wrinting classes"?)

Saludos!
Luis


El 21 de febrero de 2018, 10:01, Cristhian Boujon <cristhianboujon en gmail.com
> escribió:

> Hola Luis,
>
> Los patrones de diseño, a priori, no son lenguaje-dependientes, tal es
> así, que todos los patrones de diseño pueden explicarse solo con diagramas
> y apuntan a solucionar un tipo de problemática común. Dicho ésto, el mismo
> patrón de diseño puede ser implementado en distintos lenguajes de
> programación, Java, C#, Python, Ruby, PHP, etc. Seguro en cada lenguaje va
> a cambiar la implementación y eso está bien que suceda porque hay que
> aprovechar las características específicas de cada uno.
>
> Recuerdo en un momento que me surgó la misma duda que vos.
> Pasar la clase o función explícitamente en el código es una opción válida,
> como sugiere Ivan. Otra opción válida es la de diccionarios, no tiene nada
> de malo implementarlos en éste caso, no me queda claro por qué querés
> evitarlo.
> Supongamos que la decisión de qué leer (la selección de la estrategia)
> viene desde el exterior, por ejemplo, del usuario, o sea que se define en
> runtime, tu código podría ser algo así:
>
> strategies = {'png': leer_png, 'jpg': leer_jpg, 'pdf': leer_pdf}
>
> lector = strategies[format] # format es una variable que viene definida
> por el usuario, por ejemplo, desde la consola.
> lector(archivo_cualquiera)
>
> *OOP*
> La clase puede no ser necesaria, pero puede, también, ser necesaria si
> necesitas almacenar un estado interno, así que una versión OOP podría ser:
>
> class Lector:
> def __init__(self, strategy_format):
> self.strategy_format = strategy_format
>
> def leer(nombre_archivo):
> self.strategy_format(nombre_archivo)
>
> De ésta manera, la clase es totalmente independiente del contexto
> específico en el que se la use, no depende de diccionarios o strings, es
> decir, la clase espera que se le pase una función strategy_format, sin
> importar si se la pasa de manera explícita o si se decide en runtime.
> ¿Como decidirlo en runtime?
> 1- Con un diccionario como en primer ejemplo.
> strategies = {'png': leer_png, 'jpg': leer_jpg, 'pdf': leer_pdf}
> strategy = strategies[format] # format es una variable que viene definida
> por el usuario, por ejemplo, desde la consola.
>
> lector = Lector(strategy)
> lector.leer(archivo_cualquiera)
>
> 2- Con un string usando getattr
> def leer_jpg(archivo): # codigo def leer_png(archivo): # codigo
>
> strategy = getattr(self, nombre_function) # Puede ser self o un string con
> el path separado por "." en donde se encuentran las funciones
> lector = Lector(strategy)
> lector.leer(archivo_cualquiera)
>
> Respondiendo tu última pregunta... no, no se puede hacer funcion =
> self.'leer_{}'.format(extension) en python, creo que eso funciona en PHP.
>
> Espero que te haya sido útil.
> Saludos!
>
>
> ---
> *If you want to know more about me, you can check:*
> * <http://github.com/Overflow012>  <https://medium.com/@cristhianboujon>*
> *[image: https://www.linkedin.com/in/cristhian-boujon/]
> <https://www.linkedin.com/in/cristhian-boujon/> *
>
>
> 2018-02-21 8:19 GMT-03:00 Luis Andraschnik <luis.andraschnik en gmail.com>:
>
>> Hola Ivan
>>
>> Esoes muy parecido a lo que hice sólo con funciones, ya que lo que quiero
>> evitar es a priori saber que función tengo que utilizar sin recurrir a
>> if..else, y que el programa "calcule" que función va a usar según el
>> contexto.
>>
>> Saludos!
>> Luis
>>
>> El 20 de febrero de 2018, 19:56, ivan almandoz <alialmandoz en gmail.com>
>> escribió:
>>
>>> hola luis, te paso un snipet que te dejaría hacer lo que necesitas.
>>> espero te sirva:
>>>
>>> class StrategyEjemplo:
>>>     def __init__(self, func=None):
>>>         if func:
>>>             self.execute = func
>>>
>>>     def execute(self):
>>>         print("ningun formato elegido")
>>>
>>>
>>> def leer_png(archivo):
>>>     print('leyendo formato {0}'.format(archivo))
>>>
>>>
>>> def leer_jpg(archivo):
>>>     print('leyendo formato {0}'.format(archivo))
>>>
>>>
>>> def leer_pdf(archivo):
>>>     print('leyendo formato {0}'.format(archivo))
>>>
>>>
>>> if __name__ == "__main__":
>>>     strat0 = StrategyEjemplo()
>>>     strat1 = StrategyEjemplo(lambda: leer_jpg('jpg'))
>>>     strat2 = StrategyEjemplo(lambda: leer_pdf('pdf'))
>>>     strat3 = StrategyEjemplo(lambda: leer_png('png'))
>>>
>>>     strat0.execute()
>>>     strat1.execute()
>>>     strat2.execute()
>>>     strat3.execute()
>>>
>>>
>>>
>>> El 20 de febrero de 2018, 16:44, Luis Andraschnik <
>>> luis.andraschnik en gmail.com> escribió:
>>>
>>>> Hola grupo!!
>>>>
>>>> Leí sobre el patrón de diseño Strategy, más allá de que puede ser
>>>> implementado por funciones sin necesidad de recurrir a clases y que los
>>>> patrones de diseño son lenguaje-dependientes, veo que en muchos textos
>>>> indica que evita el uso de un largo if ..else if ...,
>>>>
>>>> No obstante no veo que se evite if ...else if ...  , salvo que se
>>>> invoquen explícitamente las funciones. Por ejemplo :
>>>>
>>>> def leer_png(archivo):
>>>>
>>>>     print(''leí {} png".format(archivo))
>>>>
>>>> def leer_jpg():
>>>>
>>>>     print('leí {} jpg".format(archivo))
>>>>
>>>> def leer_pdf():
>>>>
>>>>     print('leí {} pdf".format(archivo))
>>>>
>>>>
>>>> def imprimir(file, leer):
>>>>
>>>>     leer(file)
>>>>
>>>>
>>>> Ejemplo de llamado explícito
>>>>
>>>> imprimir("archivo.pdf", leer_pdf)
>>>>
>>>> bárbaro pero muy poco util porque yo no sé de antemano que voy a leer,
>>>> entonces redefino imprimir()
>>>>
>>>>
>>>> def imprimir(archivo_cualquiera):
>>>>
>>>>     if archivo_cualquiera.endswith(".jpg"):
>>>>
>>>>         leer = leer_jpg
>>>>
>>>>     else if archivo_cualquiera.endswith(".png"):
>>>>
>>>>             leer=leer_png
>>>>
>>>>     else if archivo_cualquiera.endswith(".pdf"):
>>>>
>>>>             leer=leer_pdf
>>>>
>>>>     leer(archivo_cualquiera)
>>>>
>>>>
>>>> y entonces dónde es que se evita el if ..else. Y si quiero leer 80
>>>> formatos distintos???
>>>>
>>>>
>>>> Sé que puede implementarse un diccionario de funciones, similar a una
>>>> sentencia switch, pero no creo que se refieran a eso.
>>>>
>>>> Los ejemplos que leí siempre hacen un llamado explícito, pero en
>>>> realida dlo que interesa es como seleccionar la función que se pasa como
>>>> parámetro ...
>>>>
>>>> Me quedé pensando en esto y no le encuentro la solución o estoy
>>>> interpretando algo mal.
>>>>
>>>> Saluti
>>>>
>>>> Luis
>>>>
>>>> _______________________________________________
>>>> Lista de Correo de PyAr - Python Argentina - pyar en python.org.ar
>>>> Sitio web: http://www.python.org.ar/
>>>>
>>>> Para administrar la lista (o desuscribirse) entrar a
>>>> http://listas.python.org.ar/listinfo/pyar
>>>>
>>>> La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre de
>>>> Argentina - http://www.usla.org.ar
>>>>
>>>
>>>
>>> _______________________________________________
>>> Lista de Correo de PyAr - Python Argentina - pyar en python.org.ar
>>> Sitio web: http://www.python.org.ar/
>>>
>>> Para administrar la lista (o desuscribirse) entrar a
>>> http://listas.python.org.ar/listinfo/pyar
>>>
>>> La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre de
>>> Argentina - http://www.usla.org.ar
>>>
>>
>>
>> _______________________________________________
>> Lista de Correo de PyAr - Python Argentina - pyar en python.org.ar
>> Sitio web: http://www.python.org.ar/
>>
>> Para administrar la lista (o desuscribirse) entrar a
>> http://listas.python.org.ar/listinfo/pyar
>>
>> La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre de
>> Argentina - http://www.usla.org.ar
>>
>
>
> _______________________________________________
> Lista de Correo de PyAr - Python Argentina - pyar en python.org.ar
> Sitio web: http://www.python.org.ar/
>
> Para administrar la lista (o desuscribirse) entrar a
> http://listas.python.org.ar/listinfo/pyar
>
> La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre de
> Argentina - http://www.usla.org.ar
>
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.python.org.ar/pipermail/pyar/attachments/20180221/798852f4/attachment-0001.html>


Más información sobre la lista de distribución pyar