Loading…

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

Like this presentation? Why not share!

Patrones de diseño (en Ruby) — RubyConf Uruguay 2010

on

  • 1,375 views

 

Statistics

Views

Total Views
1,375
Views on SlideShare
1,375
Embed Views
0

Actions

Likes
1
Downloads
13
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as OpenOffice

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • Presentación De qué voy a hablar
  • Presentación De qué voy a hablar
  • Seguir slide, es sencilla
  • Solución conocida a problema dado Lenguaje común, ejemplo observer “Mal” ejemplo: goto, o alguna otra cosa Buen diseño, siempre y cuando estemos hablando del contexto adecuado
  • Va a ser una metáfora visual
  • Secuencia de jugadas con un resultado parejo para ambos jugadores En este caso, blanco esquina, negro afuera
  • Izquierda: negro trabaja bien Derecha: la pared de negro se enfrenta a blanco que lo neutraliza
  • Lo más importante: el contexto.
  • Es decir, elegir la herramienta adecuada para el problema actual es imprescindible
  • Uno de los patrones más odiados. Tiene algunos casos de uso El ejemplo: porque el soporte está en stdlib — se encarga de temas de concurrencia y múltiples threads
  • Permite que un objeto notifique a otros sobre cambios en su estado También soporte en stdlib Requerir 'observer' En la clase observable, requerir Observable El método add_observer (en el initializer de los observers) agrega los observers al observable El método notify_observers en el observable llama al update de los observers, con los mismos argumentos. Pero sólo si antes llamamos a changed para avisarle
  • Permite a un objeto cambiar su comportamiento de acuerdo a su estado interno (sin cambiar la interfaz) Hay muchas librerías que ayudan con State Elegí esta porque me parece clara Hasta le robé el ejemplo de código del readme Cada estado hereda de StatePattern::State El objeto incluye StatePattern Y define el estado inicial transition_to cambia el objeto estado Los métodos color y next son implícitamente delegados al objeto estado
  • Hablando de delegar, hay varios patrones que usan delegación, no sólo State. Adapter, por ejemplo. Nos permite adaptar la interfaz de varias clases incompatibles a una misma interfaz que podemos usar. Para eso, es útil Forwardable En el caso de AdapterA, extiende Forwardable, y luego usa def_delegator. En el caso de AdapterB, no se puede, porque el orden de los parámetros es diferente
  • Iterator nos permite recorrer una lista de objetos, como por ejemplo un array, para trabajar con ellos Implementación casi directa del GoF Para alguien que venga de Java, va a ser algo bastante conocido
  • Pero en ese caso estás haciendo Java, no Ruby
  • En Ruby hay formas más expresivas de lograr lo mismo Tenemos each para iterar sobre elementos
  • Cuando iteramos con diferentes objetivos, es más expresivo iterar con métodos que expliquen qué es lo que queremos lograr Todos estos métodos están definidos en Enumerable Si tuviéramos otra estructura sobre la que iterar, con sólo implementar each e incluír el módulo Enumerable Ayer Aaron Patterson mostró un par de implementaciones para un árbol
  • Permite cambiar la forma en la que un objeto se comporta Ejemplo medio clásico, con distintos objetos para cada Strategy Otra opción, tal vez más ruby, sería incluír módulos para cada Strategy diferente
  • Me gusta más esta manera, parece más ruby
  • Hay muchos usos de patrones que usamos todos los días, muchos que tenemos tan integrados que casi no nos damos cuenta Estos son sólo algunos ejemplos, hay muchos más si uno quiere buscar

Patrones de diseño (en Ruby) — RubyConf Uruguay 2010 Patrones de diseño (en Ruby) — RubyConf Uruguay 2010 Presentation Transcript

  • Photo by lucynieto http://www.flickr.com/photos/lucynieto/2299831355/ Patrones de diseño (en ruby)
    • Ignacio (Nacho) Facello
    • @nachof
    • [email_address]
  •  
  • Photo by lucynieto http://www.flickr.com/photos/lucynieto/2299831355/ Patrones de diseño (en ruby)
    • Ignacio (Nacho) Facello
    • @nachof
    • [email_address]
  • Qué son patrones de diseño?
    • Un patrón de diseño es una solución general reutilizable a un problema de común ocurrencia en el diseño de software (Wikipedia)
    • Concepto originalmente usado en arquitectura (Christopher Alexander)
    • Popularizado en el libro Design Patterns: Elements of Reusable Object-Oriented Software, popularmente conocido como GoF (Gang of Four), de Erich Gamma, Richard Helm, Ralph Johnson, y John Vlissides.
  • Para qué sirven?
    • Conocer una solución para un problema dado es útil cuando uno se enfrenta a ese problema.
    • Nos dan un lenguaje común.
    • Suelen resultar en un buen diseño
  • Todo lo que sé de patrones lo aprendí jugando go
  • Joseki
  • El mismo joseki...
  • … en diferentes contextos.
  • Cuando no sirven...
    • Que algo sea un patrón no quiere decir que sea adecuado.
    • El contexto lo es todo.
  • Lo importante: elegir la herramienta adecuada Photo by jannem http://www.flickr.com/photos/jannem/3312116875/
  • Algunos ejemplos de patrones en Ruby
  • Singleton require 'singleton' # From stdlib class SingletonExample include Singleton end one = SingletonExample.instance two = SingletonExample.instance puts one == two #=> true
  • Observer require 'observer' # From stdlib class Car include Observable def initialize @fuel = 100 @speed = 0 end def run while @fuel > 0 do @speed += 1 @fuel -= 1 changed notify_observers ( @speed , @fuel ) end end end class SpeedWarner def initialize (car, speed_limit) @limit = speed_limit car. add_observer ( self ) end def update (speed, fuel) puts "Too fast!" if speed > @limit end end car = Car.new SpeedWarner. new (car, 70 ) FuelWarner. new (car, 10 ) car.run
  • State require 'state_pattern' # Gem by @dcadenas # http://github.com/dcadenas/state_pattern class Stop < StatePattern: :State def next sleep 3 transition_to (Go) end def color &quot;Red&quot; end end class Go < StatePattern: :State def next sleep 2 transition_to (Caution) end def color &quot;Green&quot; end end class Caution < StatePattern: :State def next sleep 1 transition_to (Stop) end def color &quot;Amber&quot; end end class TrafficSemaphore include StatePattern set_initial_state Stop end semaphore = TrafficSemaphore.new loop do puts semaphore.color semaphore. next end
  • Adapter require 'forwardable' class LegacyClassA def some_method (a, b) puts &quot;#{a}, #{b} (old A)&quot; end end class LegacyClassB def do_something (b, a) puts &quot;#{a}, #{b} (old B)&quot; end end class AdapterA extend Forwardable def initialize (adaptee) @adaptee = adaptee end def_delegator : @adaptee , :some_method , :action end class AdapterB def initialize (adaptee) @adaptee = adaptee end def action (a, b) @adaptee . do_something (b, a) end end adapted_a = AdapterA. new (LegacyClassA.new) adapted_b = AdapterB. new (LegacyClassB.new) [adapted_a, adapted_b].each { |adapted| adapted. action ( &quot;Hello&quot; , &quot;World&quot; ) }
  • Iterator class ArrayIterator def initialize (array) @array = array @index = 0 end def first @index = 0 end def next @index += 1 end def current @array [ @index ] end def over? @index >= @array .size end end list = [ 1 , 2 , 3 , 4 ] iterator = ArrayIterator. new (list) while (!iterator.over?) do puts iterator.current iterator. next end
  • Iterator class ArrayIterator def initialize (array) @array = array @index = 0 end def first @index = 0 end def next @index += 1 end def current @array [ @index ] end def over? @index >= @array .size end end list = [ 1 , 2 , 3 , 4 ] iterator = ArrayIterator. new (list) while (!iterator.over?) do puts iterator.current iterator. next end
  • Mucho más sencillo... list = [ 1 , 2 , 3 , 4 ] list.each do |item| puts item end
  • Otras formas de iterar list = [ 1 , 2 , 3 , 4 ] list.each do |item| puts item end list.map { |item| item * 2 } #=> [3,4,5,6] list.any? { |item| item == 2 } #=> true list.select { |item| item > 2 } #=> [3,4] list.detect { |item| item > 2 } #=> 3
  • Strategy require 'forwardable' class Caveman extend Forwardable attr_accessor :strategy def initialize (strategy = DefaultStrategy.new) @strategy = strategy end def_delegator : @strategy , :survive def normal_day wake_up survive go_to_sleep end def wake_up puts &quot;Waking up&quot; end def go_to_sleep puts &quot;Sleep now&quot; end end class DefaultStrategy def survive puts &quot;Hide from tigers&quot; end end class AggressiveStrategy def survive puts &quot;Grab spear, hunt tigers&quot; end end class ConfusedStrategy def survive puts &quot;Grab tiger, hunt spears&quot; end end og = Caveman.new og.normal_day og.strategy = AggressiveStrategy.new og.normal_day
  • Strategy (con lambdas) class Caveman attr_accessor :strategy def initialize (strategy = lambda { puts &quot;Hide from tiger&quot; }) @strategy = strategy end def normal_day wake_up survive go_to_sleep end def survive @strategy .call end def wake_up puts &quot;Waking up&quot; end def go_to_sleep puts &quot;Sleep now&quot; end end og = Caveman.new og.normal_day og.strategy = lambda { puts &quot;Grab spear, hunt tiger&quot; } og.normal_day
  • Algunos usos
    • Rails: Model-View-Controller
    • ActiveRecord::Observer: Observer
    • Array#sort: Strategy
  • Algunos comentarios finales
    • Stdlib y gemas son útiles
    • Memorizarse los patrones y usarlos a cada oportunidad no ayuda.
    • Entender sus consecuencias, y su porqué, sí sirve.
    • “There may be a dozen different ways to implement a [given pattern] - it doesn't have to be done exactly like the GoF book or some web page.” Paul Wheaton (http://www.javaranch.com/patterns/)
  •  
  • Gracias :-)